diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | examples/cgi/cgi_server.py | 11 | ||||
-rw-r--r-- | examples/cgi/cgi_stacktrace.nim | 5 | ||||
-rw-r--r-- | examples/cgi/example.nim | 7 | ||||
-rw-r--r-- | lib/pure/cgi.nim | 36 | ||||
-rw-r--r-- | lib/system.nim | 16 | ||||
-rw-r--r-- | lib/system/excpt.nim | 44 | ||||
-rw-r--r-- | web/news.txt | 4 |
8 files changed, 84 insertions, 41 deletions
diff --git a/.gitignore b/.gitignore index 2fc6db667..f5719848b 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 000000000..1907515e8 --- /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 000000000..e9f2f567c --- /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 000000000..17629982a --- /dev/null +++ b/examples/cgi/example.nim @@ -0,0 +1,7 @@ +import cgi + +write(stdout, "Content-type: text/html\n\n") +write(stdout, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\">\n") +write(stdout, "<html><head><title>Test</title></head><body>\n") +write(stdout, "Hello!") +writeln(stdout, "</body></html>") diff --git a/lib/pure/cgi.nim b/lib/pure/cgi.nim index c499abdc0..29c686fd7 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 - ## ``<br />`` and are easily readable in a browser. write(stdout, "Content-type: text/html\n\n") - system.stackTraceNewLine = "<br />\n" -proc setStackTraceNewLine*() = - ## Modifies the debug stack traces so that they contain - ## ``<br />`` and are easily readable in a browser. - system.stackTraceNewLine = "<br />\n" +proc resetForStacktrace() = + stdout.write """<!--: spam +Content-Type: text/html + +<body bgcolor=#f0f0f8><font color=#f0f0f8 size=-5> --> +<body bgcolor=#f0f0f8><font color=#f0f0f8 size=-5> --> --> +</font> </font> </font> </script> </object> </blockquote> </pre> +</table> </table> </table> </table> </table> </font> </font> </font> +""" + +proc writeErrorMessage*(data: string) = + ## Tries to reset browser state and writes `data` to stdout in + ## <plaintext> tag. + resetForStacktrace() + # We use <plaintext> here, instead of escaping, so stacktrace can + # be understood by human looking at source. + stdout.write("<plaintext>\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 d7a9b08ab..106eb04a3 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: "<stdio.h>".}: 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 7937d9738..9b6a64fb0 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 ``<br>`` - ## 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 1b492fa97..3d1546fb7 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 ------------------ |