(2020年2月3日追記:コードの後半を修正、19章のdod-request-handlerの記述を追加)
現象
Land of Lispの13章は、ローカルでWebサイトを立ち上げることが目標になっているが、リクエストハンドラを本に載っている通り以下のコードを書いてしまうと、2020年現在、macOS Catalina環境下では、Chromeでは「127.0.0.1 から無効な応答が送信されました(ERR_INVALID_HTTP_RESPONSE)」というエラーが返ってきてしまい、FirefoxではHTMLコードがそのまま画面に表示されてしまう。
15章以降では、Webサーバが正しく立ち上がる前提で話が進むので、ここで詰まってしまうとコードを走らせることができなくなってしまう。
(defun hello-request-handler (path header params)
(if (equal path "greeting")
(let ((name (assoc 'name params)))
(if (not name)
(princ "<html><form>What is your name?<input name='name' />
</form></html>")
(format t "<html>Nice to meet you, ~a!</html>" (cdr name))))
(princ "Sorry... I don't know that page.")))
解決法
以下の記事で起きている現象と性質は同様で、解決法も同じであった(lambdacadabraさんに深謝)。
https://lambdacadabra.blogspot.com/2016/11/land-of-lispwebfirefox.html
主要なコードの変更点は、HTMLコードの前にレスポンス行と改行を2つ出力するようにしたという点。
それに応じて、URL相違の際に表示されるテキストの前後にもhtmlタグを追加している。
これで、Chrome, Firefoxいずれでも正しく表示されるようになった。
記事中では「ChromeではHTMLがきちんと解釈されて入力フォームなどが普通に表示される」とあるが、記事投稿時(2016年)の後Chromeの仕様変更があり、エラーを吐くようになったのかもしれない。
(defun hello-request-handler (path header params)
(if (equal path "greeting")
(let ((name (assoc 'name params)))
(if (not name)
(progn ; 追加
(princ "HTTP/1.1 200 OK") ; 追加
(terpri) ; 追加
(terpri) ; 追加
(princ "<html><form>What is your name?<input name='name' />
</form></html>"))
(progn ; 追加
(princ "HTTP/1.1 200 OK") ; 追加
(terpri) ; 追加
(terpri) ; 追加
(format t "<html>Nice to meet you, ~a!</html>" (cdr name)))))
(progn ;; Added
(princ "HTTP/1.1 200 OK") ;; 追加
(terpri) ;; 追加
(terpri) ;; 追加
(princ "<html>Sorry... I don't know that page.</html>")))) ;; 変更
参考:19章に登場する同様のハンドラ(dod-request-handler)の修正方法
19章で書くDice of Doomのハンドラにも同様の変更が必要なので、下記に変更後のコードを記しておく。
(defun dod-request-handler (path header params)
(if (equal path "game.html")
(progn (princ "HTTP/1.1 200 OK") ;; 追加
(terpri) ;; 追加
(terpri) ;; 追加
(princ "<!doctype html>")
(tag center ()
(princ "Welcome to DICE OF DOOM!")
(tag br ())
(let ((chosen (assoc 'chosen params)))
(when (or (not *cur-game-tree*) (not chosen))
(setf chosen nil)
(web-initialize))
(cond ((lazy-null (caddr *cur-game-tree*))
(web-announce-winner (cadr *cur-game-tree*)))
((zerop (car *cur-game-tree*))
(web-handle-human
(when chosen
(read-from-string (cdr chosen)))))
(t (web-handle-computer))))
(tag br ())
(draw-dod-page *cur-game-tree* *from-tile*)))
(progn (princ "HTTP/1.1 200 OK") ;; 追加
(terpri) ;; 追加
(terpri) ;; 追加
(princ "<html>Sorry... I don't know that page.</html>")))) ;; 変更