原著の公式サイトを見つけました。ソースコードが掲載されていて、ご質問のコードとも一致するようです。これで試してみます。書籍は未入手です。
ブラウザを使ってアクセスすると、サーバのレスポンスを直接見ることができません。telnetコマンドを使って手作業でリクエストを送信、レスポンスを受け取ることにします (最近のオペレーティングシステムではtelnetが入っていないことがあるので、なければインストールして下さい)。別の端末を開いて、次のように実行・入力します。
bash
1$ telnet localhost 8080
2Trying 127.0.0.1...
3Connected to localhost.
4Escape character is '^]'.
5GET /greeting HTTP/1.1
6Host: localhost:8080
7
8<form>What is your name?<input name='name' /></form>Connection closed by foreign host.
9$
10```サーバが正しいレスポンスを返していません。接続はできているのに「ERR_INVALID_HTTP_RESPONSE」というエラーになるのはこのためでしょう。
11
12- 上で説明していることの意味がわからなければ、まず**HTTPというプロトコルについて調べて下さい** (HTTPについては文中でも多少説明があるだろうと思いますが、必要に応じて他の参考書もご覧下さい)。
13
14さて、以下いささか冗長とは思いますが、解決するために私がやったことを書きます。
15
16# 単体テスト
17
18いきなりプログラムを実行するのではなく、まず関数ごとにテストをしてみましょう。
19
20アクセスするURLを``http://localhost:8080/greeting``と想定します。クライアントが送るリクエストは、つぎのようなものになります (実際のブラウザが送るものはもっと複雑ですが、単純化しています)。
GET /greeting HTTP/1.1
Host: localhost:8080
(空行)
プログラムをロードし、(サーバは起動せずに) ``parse-url``、``get-header``の動作をテストします。
```lisp
[1]> (load "webserver.lisp")
;; Loading file webserver.lisp ...
;; Loaded file webserver.lisp
T
[2]> (parse-url "GET /greeting HTTP/1.1")
("greeting")
[3]> (get-header *standard-input*)
Host: localhost:8080
((HOST . "localhost:8080"))
[4]>
```うまく動いているようです。
次に、リクエストハンドラをテストします。サンプルの``hello-request-handler``でやってみます。
```lisp
[4]> (hello-request-handler "greeting" '((HOST . "localhost:8080")) nil)
<form>What is your name?<input name='name' /></form>
"<form>What is your name?<input name='name' /></form>"
[5]>
```最初にステータス行やレスポンスヘッダがありません。ソースコードの該当箇所を確認します。
```lisp
(defun hello-request-handler (path header params)
(if (equal path "greeting")
(let ((name (assoc 'name params)))
(if (not name)
(princ "<form>What is your name?<input name='name' /></form>")
(format t "Nice to meet you, ~a!" (cdr name))))
(princ "Sorry... I don't know that page.")))
```ステータス行もレスポンスヘッダも出力していません。これでは正しいレスポンスになりません。コードを修正します。
```lisp
(defun hello-request-handler (path header params)
(if (equal path "greeting")
(let ((name (assoc 'name params)))
(format t "HTTP/1.0 200 OK~C~C" #\return #\linefeed)
(format t "Content-Type: text/html~C~C" #\return #\linefeed)
(format t "~C~C" #\return #\linefeed)
(if (not name)
(princ "<form>What is your name?<input name='name' /></form>")
(format t "Nice to meet you, ~a!" (cdr name))))
(progn
(format t "HTTP/1.0 404 NG~C~C" #\return #\linefeed)
(format t "Content-Type: text/html~C~C" #\return #\linefeed)
(format t "~C~C" #\return #\linefeed)
(princ "Sorry... I don't know that page.")))
)
```かなり手抜きですが、まあいいでしょう。もう一度やってみます。
```lisp
[4]> (hello-request-handler "greeting" '((HOST . "localhost:8080")) nil)
HTTP/1.0 200 OK
Content-Type: text/html
<form>What is your name?<input name='name' /></form>
"<form>What is your name?<input name='name' /></form>"
[5]>
```うまくいったようです (あと、``/greeting``以外にアクセスした場合と、クエリパラメータがある場合は、ご自分でやってみて下さい)。
# 結合テスト
単体テストに通ったので、サーバを起動して全体の動作をテストしましょう。
```lisp
[2]> (serve #'hello-request-handler)
別の端末を開いて、次のように実行します。
bash
1$ telnet localhost 8080
2Trying 127.0.0.1...
3Connected to localhost.
4Escape character is '^]'.
5GET /greeting HTTP/1.1
6Host: localhost:8080
7
8HTTP/1.0 200 OK
9Content-Type: text/html
10
11<form>What is your name?<input name='name' /></form>Connection closed by foreign host.
12$
13```正常なレスポンスを返しています (``/greeting``以外にアクセスした場合と、クエリパラメータがある場合は、ご自分でやってみて下さい)。
14
15最後に、ブラウザで正常にアクセスできることを確認します。
16
17---
18私は書籍を読んでいないので推測ですが、著者にとってこのサンプルの目的は「こうすれば実現できる」と示すことであり、処理の細部は省いたのでしょう。読者のやりたいことに合わせて**自分でリクエストハンドラを書いて下さい**、ということかと思います。