Minor issue but I was debugging something else with Fiddler and it kept telling me this about responses from HN:<p><i>Fiddler has detected a protocol violation in session #122.<p>The Server did not return properly formatted HTTP Headers. HTTP headers
should be terminated with CRLFCRLF. These were terminated with LFLF.</i><p>Presumably this is an issue in the Arc code outputting the headers. Also, is this where I should report this or is there a support email or something I can address?
The problem appears to be in srv.arc where there's the following:<p><pre><code> (def gen-type-header (ctype)
(+ "HTTP/1.0 200 OK
Content-Type: "
ctype
"
Connection: close"))
</code></pre>
hexl-mode on the file shows that those line endings are 0x0A:<p><pre><code> 00001630: 2874 6162 6c65 2929 0a0a 2864 6566 2067 (table))..(def g
00001640: 656e 2d74 7970 652d 6865 6164 6572 2028 en-type-header (
00001650: 6374 7970 6529 0a20 2028 2b20 2248 5454 ctype). (+ "HTT
00001660: 502f 312e 3020 3230 3020 4f4b 0a43 6f6e P/1.0 200 OK.Con
00001670: 7465 6e74 2d54 7970 653a 2022 0a20 2020 tent-Type: ".
00001680: 2020 6374 7970 650a 2020 2020 2022 0a43 ctype. ".C
00001690: 6f6e 6e65 6374 696f 6e3a 2063 6c6f 7365 onnection: close
000016a0: 2229 290a 0a28 6d61 7020 2866 6e20 2828 "))..(map (fn ((
</code></pre>
Eventually the headers get printed to the socket via prn:<p><pre><code> (let filetype (static-filetype op)
(aif (and filetype (file-exists (string staticdir* op)))
(do (prn (type-header* filetype))
</code></pre>
prn is defined in arc.arc<p><pre><code> (def pr args
(map1 disp args)
(car args))
(def prn args
(do1 (apply pr args)
(pr #\newline))) ; writec doesn't implicitly flush
</code></pre>
which is using disp which is defined in ac.scm<p><pre><code> (define (printwith f args)u (let ((port (if (> (length args) 1)
(cadr args)
(current-output-port))))
(when (pair? args)
(f (ac-denil (car args)) port))
(unless (ar-bflag 'explicit-flush)
(flush-output port)))
'nil)
(defarc write (arc-write . args) (printwith write args))
(xdef disp (lambda args (printwith display args)))
</code></pre>
That's using the MzScheme display method which appears to just do writing of bytes and doesn't do any CRLF translation (<a href="http://docs.racket-lang.org/reference/Writing.html?q=display#(def._((quote._~23~25kernel)._display))" rel="nofollow">http://docs.racket-lang.org/reference/Writing.html?q=display...</a>)<p>Quick verification of that:<p><pre><code> $ cat test.scm
(display "Hello, World!")
(display #\return)
(display #\newline)
$ mzscheme -r test.scm | hexdump -C
00000000 48 65 6c 6c 6f 2c 20 57 6f 72 6c 64 21 0d 0a |Hello, World!..|
</code></pre>
So, there are a couple of possible solutions: explicitly specify CRLF as line endings when needed (i.e. insert #\return), or have a special version of pr for network communication that does LF -> CRLF translation).<p>Within the respond function there are other instances of using prn to send to the socket that need to be fixed:<p><pre><code> (def respond (str op args cooks clen ctype in ip)
(w/stdout str
(iflet f (srvops* op)
(let req (inst 'request 'args args 'cooks cooks 'ctype ctype
'clen clen 'in in 'ip ip)
(if (redirector* op)
(do (prn rdheader*)
(prn "Location: " (f str req))
(prn))
(do (prn header*)
(awhen (max-age* op)
(prn "Cache-Control: max-age=" it))
(f str req))))
(let filetype (static-filetype op)
(aif (and filetype (file-exists (string staticdir* op)))
(do (prn (type-header* filetype))
(awhen static-max-age*
(prn "Cache-Control: max-age=" it))
(prn)
(w/infile i it
(whilet b (readb i)
(writeb b str))))
(respond-err str unknown-msg*))))))
</code></pre>
I'm guessing that altering gen-type-header and creating a special prcrlf function is the way to go.<p><pre><code> (def prcrlf args
(do1 (apply pr args)
(pr #\return)
(pr #\newline)))
(def gen-type-header (ctype)
(+ "HTTP/1.0 200 OK#\return
Content-Type: "
ctype
"#\return
Connection: close"))
</code></pre>
Although, personally, I don't like the assumption that the editor is inserting 0x0A for line-endings and would rather be totally certain with something like:<p><pre><code> (def gen-type-header (ctype)
(+ "HTTP/1.0 200 OK"
#\return #\newline
"Content-Type: "
ctype
#\return #\newline
"Connection: close"))
</code></pre>
Since you'll need to do this sort of thing a lot a little helper would probably make sense (and I'd add the CRLF on the last line explicitly):<p><pre><code> (def crlf (a)
(+ a #\return #\newline))
(def gen-type-header (ctype)
(+ (crlf "HTTP/1.0 200 OK")
(crlf (+ "Content-Type: " ctype))
(crlf "Connection: close")))
</code></pre>
And change every instance of prn in respond to prcrlf. Except for (prn (type-header* filetype)) which becomes (pr (type-header* filetype)).<p>Note: I have not tested this change. Probably some other small gotchas.