summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2013-12-20 09:42:39 -0800
committerAndreas Rumpf <rumpf_a@web.de>2013-12-20 09:42:39 -0800
commit259d205ff6c44e086371f2a7b28a9345257d094e (patch)
tree92d1d8306cc233b46d9f1190192f3077f5f0c876
parent22e88026afc9e662206aea5c6de742ed680cc3dd (diff)
parent7d5fa3f52d23c4f238c1664fc568eb7f3c6a34b6 (diff)
downloadNim-259d205ff6c44e086371f2a7b28a9345257d094e.tar.gz
Merge pull request #759 from zielmicha/stdmsg
Write tracebacks to stderr instead of stdout.
-rw-r--r--.gitignore2
-rw-r--r--examples/cgi/cgi_server.py11
-rw-r--r--examples/cgi/cgi_stacktrace.nim5
-rw-r--r--examples/cgi/example.nim7
-rw-r--r--lib/pure/cgi.nim36
-rw-r--r--lib/system.nim16
-rw-r--r--lib/system/excpt.nim44
-rw-r--r--web/news.txt4
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
 ------------------