diff --git a/.gitignore b/.gitignore
index 2fc6db6678..f5719848bf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -63,6 +63,8 @@ examples/cross_calculator/android/tags
/examples/allany
/examples/cairoex
/examples/cgiex
+/examples/cgi/cgi_stacktrace
+/examples/cgi/example
/examples/curlex
/examples/debugging
/examples/docstrings
diff --git a/examples/cgi/cgi_server.py b/examples/cgi/cgi_server.py
new file mode 100644
index 0000000000..1907515e80
--- /dev/null
+++ b/examples/cgi/cgi_server.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+import BaseHTTPServer
+import CGIHTTPServer
+
+server = BaseHTTPServer.HTTPServer
+handler = CGIHTTPServer.CGIHTTPRequestHandler
+server_address = ('localhost', 8008)
+handler.cgi_directories = ['/']
+
+httpd = server(server_address, handler)
+httpd.serve_forever()
diff --git a/examples/cgi/cgi_stacktrace.nim b/examples/cgi/cgi_stacktrace.nim
new file mode 100644
index 0000000000..e9f2f567c2
--- /dev/null
+++ b/examples/cgi/cgi_stacktrace.nim
@@ -0,0 +1,5 @@
+import cgi
+cgi.setStackTraceStdout()
+
+var a: string = nil
+a.add "foobar"
diff --git a/examples/cgi/example.nim b/examples/cgi/example.nim
new file mode 100644
index 0000000000..17629982ab
--- /dev/null
+++ b/examples/cgi/example.nim
@@ -0,0 +1,7 @@
+import cgi
+
+write(stdout, "Content-type: text/html\n\n")
+write(stdout, "\n")
+write(stdout, "
Test\n")
+write(stdout, "Hello!")
+writeln(stdout, "")
diff --git a/lib/pure/cgi.nim b/lib/pure/cgi.nim
index c499abdc09..29c686fd7f 100644
--- a/lib/pure/cgi.nim
+++ b/lib/pure/cgi.nim
@@ -342,16 +342,35 @@ proc writeContentType*() =
##
## .. code-block:: Nimrod
## write(stdout, "Content-type: text/html\n\n")
- ##
- ## It also modifies the debug stack traces so that they contain
- ## ``
`` and are easily readable in a browser.
write(stdout, "Content-type: text/html\n\n")
- system.stackTraceNewLine = "
\n"
-proc setStackTraceNewLine*() =
- ## Modifies the debug stack traces so that they contain
- ## ``
`` and are easily readable in a browser.
- system.stackTraceNewLine = "
\n"
+proc resetForStacktrace() =
+ stdout.write """
+ --> -->
+
+
+"""
+
+proc writeErrorMessage*(data: string) =
+ ## Tries to reset browser state and writes `data` to stdout in
+ ## tag.
+ resetForStacktrace()
+ # We use here, instead of escaping, so stacktrace can
+ # be understood by human looking at source.
+ stdout.write("\n")
+ stdout.write(data)
+
+proc setStackTraceStdout*() =
+ ## Makes Nimrod output stacktraces to stdout, instead of server log.
+ errorMessageWriter = writeErrorMessage
+
+proc setStackTraceNewLine*() {.deprecated.} =
+ ## Makes Nimrod output stacktraces to stdout, instead of server log.
+ ## Depracated alias for setStackTraceStdout.
+ setStackTraceStdout()
proc setCookie*(name, value: string) =
## Sets a cookie.
@@ -374,4 +393,3 @@ when isMainModule:
const test1 = "abc\L+def xyz"
assert UrlEncode(test1) == "abc%0A%2Bdef+xyz"
assert UrlDecode(UrlEncode(test1)) == test1
-
diff --git a/lib/system.nim b/lib/system.nim
index d7a9b08ab1..106eb04a3d 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -1951,15 +1951,13 @@ when not defined(JS): #and not defined(NimrodVM):
## The standard output stream.
stderr* {.importc: "stderr", header: "".}: TFile
## The standard error stream.
- ##
- ## Note: In my opinion, this should not be used -- the concept of a
- ## separate error stream is a design flaw of UNIX. A separate *message
- ## stream* is a good idea, but since it is named ``stderr`` there are few
- ## programs out there that distinguish properly between ``stdout`` and
- ## ``stderr``. So, that's what you get if you don't name your variables
- ## appropriately. It also annoys people if redirection
- ## via ``>output.txt`` does not work because the program writes
- ## to ``stderr``.
+
+ when defined(useStdoutAsStdmsg):
+ template stdmsg*: TFile = stdout
+ else:
+ template stdmsg*: TFile = stderr
+ ## Template which expands to either stdout or stderr depending on
+ ## `useStdoutAsStdmsg` compile-time switch.
proc Open*(f: var TFile, filename: string,
mode: TFileMode = fmRead, bufSize: int = -1): Bool {.tags: [].}
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
index 7937d9738e..9b6a64fb05 100644
--- a/lib/system/excpt.nim
+++ b/lib/system/excpt.nim
@@ -11,14 +11,13 @@
# use the heap (and nor exceptions) do not include the GC or memory allocator.
var
- stackTraceNewLine*: string ## undocumented feature; it is replaced by ``
``
- ## for CGI applications
-
-template stackTraceNL: expr =
- (if IsNil(stackTraceNewLine): "\n" else: stackTraceNewLine)
+ errorMessageWriter*: (proc(msg: string): void {.tags: [FWriteIO].})
+ ## Function that will be called
+ ## instead of stdmsg.write when printing stacktrace.
+ ## Unstable API.
when not defined(windows) or not defined(guiapp):
- proc writeToStdErr(msg: CString) = write(stdout, msg)
+ proc writeToStdErr(msg: CString) = write(stdmsg, msg)
else:
proc MessageBoxA(hWnd: cint, lpText, lpCaption: cstring, uType: int): int32 {.
@@ -27,6 +26,12 @@ else:
proc writeToStdErr(msg: CString) =
discard MessageBoxA(0, msg, nil, 0)
+proc showErrorMessage(data: cstring) =
+ if errorMessageWriter != nil:
+ errorMessageWriter($data)
+ else:
+ writeToStdErr(data)
+
proc chckIndx(i, a, b: int): int {.inline, compilerproc.}
proc chckRange(i, a, b: int): int {.inline, compilerproc.}
proc chckRangeF(x, a, b: float): float {.inline, compilerproc.}
@@ -111,7 +116,7 @@ when defined(nativeStacktrace) and nativeStackTraceSupported:
add(s, tempDlInfo.dli_sname)
else:
add(s, '?')
- add(s, stackTraceNL)
+ add(s, "\n")
else:
if dlresult != 0 and tempDlInfo.dli_sname != nil and
c_strcmp(tempDlInfo.dli_sname, "signalHandler") == 0'i32:
@@ -172,21 +177,18 @@ proc auxWriteStackTrace(f: PFrame, s: var string) =
add(s, ')')
for k in 1..max(1, 25-(s.len-oldLen)): add(s, ' ')
add(s, tempFrames[j].procname)
- add(s, stackTraceNL)
+ add(s, "\n")
when hasSomeStackTrace:
proc rawWriteStackTrace(s: var string) =
when nimrodStackTrace:
if framePtr == nil:
- add(s, "No stack traceback available")
- add(s, stackTraceNL)
+ add(s, "No stack traceback available\n")
else:
- add(s, "Traceback (most recent call last)")
- add(s, stackTraceNL)
+ add(s, "Traceback (most recent call last)\n")
auxWriteStackTrace(framePtr, s)
elif defined(nativeStackTrace) and nativeStackTraceSupported:
- add(s, "Traceback from system (most recent call last)")
- add(s, stackTraceNL)
+ add(s, "Traceback from system (most recent call last)\n")
auxWriteStackTraceWithBacktrace(s)
else:
add(s, "No stack traceback available\n")
@@ -207,7 +209,7 @@ proc raiseExceptionAux(e: ref E_Base) =
pushCurrentException(e)
c_longjmp(excHandler.context, 1)
elif e[] of EOutOfMemory:
- writeToStdErr(e.name)
+ showErrorMessage(e.name)
quitOrDebug()
else:
when hasSomeStackTrace:
@@ -219,7 +221,7 @@ proc raiseExceptionAux(e: ref E_Base) =
add(buf, " [")
add(buf, $e.name)
add(buf, "]\n")
- writeToStdErr(buf)
+ showErrorMessage(buf)
else:
# ugly, but avoids heap allocations :-)
template xadd(buf, s, slen: expr) =
@@ -235,7 +237,7 @@ proc raiseExceptionAux(e: ref E_Base) =
add(buf, " [")
xadd(buf, e.name, c_strlen(e.name))
add(buf, "]\n")
- writeToStdErr(buf)
+ showErrorMessage(buf)
quitOrDebug()
proc raiseException(e: ref E_Base, ename: CString) {.compilerRtl.} =
@@ -255,9 +257,9 @@ proc WriteStackTrace() =
when hasSomeStackTrace:
var s = ""
rawWriteStackTrace(s)
- writeToStdErr(s)
+ showErrorMessage(s)
else:
- writeToStdErr("No stack traceback available\n")
+ showErrorMessage("No stack traceback available\n")
proc getStackTrace(): string =
when hasSomeStackTrace:
@@ -298,13 +300,13 @@ when not defined(noSignalHandler):
var buf = newStringOfCap(2000)
rawWriteStackTrace(buf)
processSignal(sig, buf.add) # nice hu? currying a la nimrod :-)
- writeToStdErr(buf)
+ showErrorMessage(buf)
GC_enable()
else:
var msg: cstring
template asgn(y: expr) = msg = y
processSignal(sig, asgn)
- writeToStdErr(msg)
+ showErrorMessage(msg)
when defined(endb): dbgAborting = True
quit(1) # always quit when SIGABRT
diff --git a/web/news.txt b/web/news.txt
index 1b492fa971..3d1546fb75 100644
--- a/web/news.txt
+++ b/web/news.txt
@@ -29,7 +29,6 @@ Changes affecting backwards compatibility
using the new ``OSLastError`` proc.
- ``os.parentDir`` now returns "" if there is no parent dir.
-
Compiler Additions
------------------
@@ -41,7 +40,8 @@ Compiler Additions
over the generated code.
- The compiler now supports a ``computedGoto`` pragma to support very fast
dispatching for interpreters and the like.
-
+- In CGI scripts stacktraces are shown user only if cgi.setStackTraceStdout
+ is used.
Language Additions
------------------