search
LoginSignup
7
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

posted at

Organization

Go言語: net/httpで建てたサーバにnetcatでリクエストすると400 Bad Requestが付いてくる件

Goの標準ライブラリ、net/httpで作ったHTTPサーバに対して、netcatやtelnetでリクエストを送ると、なぜがレスポンスボディの後に「HTTP/1.1 400 Bad Request」が付いてくることに気が付きました。

$ nc localhost 8080
GET / HTTP/1.1
Host: localhost:8080
[ここまで入力したらENTERキーを押す]

HTTP/1.1 200 OK
Date: Sat, 09 May 2015 07:56:54 GMT
Content-Length: 13
Content-Type: text/plain; charset=utf-8

Hello, World
[ここでENTERキーを押す]
HTTP/1.1 400 Bad Request

一番最後の行に注目してください。なぜか最後に「Bad Request」がついてきます。ちなみに、レスポンスヘッダの「Content-Length」は13なので、最後の行はレスポンスボディではないことが分かります。

この現象を再現するには、次のコードでサーバを立てると再現できます。

main.go
package main

import (
    "fmt"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello, World\n")
    })
    http.ListenAndServe(":8080", nil)
}

このサーバは、go runコマンドで起動することができます。

$ go run main.go

この現象について調べていたら、GoのGoogleグループに「HTTP response sent but never closed and ending with "HTTP/1.1 400 Bad Request"」というスレッドを見つけました。このスレッドによれば、net/httpはHTTP 1.1であれば、リクエストヘッダーにConnection: closeが無い限り、Keep Aliveで通信を行うように作られているとのことです。これは、HTTP 1.1の仕様に従っているので、不具合ではありません。

従って、今回のケースでは、2回目のENTER押下をしていますが、それが空っぽのリクエストとしてサーバが認識した結果、Bad Requestのレスポンスが帰ってきたと理解できます。ですので、2回目のENTERの代わりに、リクエストをもう一度書くと、レスポンスを得ることができます。

$ nc localhost 8080
GET / HTTP/1.1
Host: localhost:8080
[ここまで書いてENTER押下]

HTTP/1.1 200 OK
Date: Sat, 09 May 2015 08:06:28 GMT
Content-Length: 13
Content-Type: text/plain; charset=utf-8

Hello, World
GET / HTTP/1.1
Host: localhost:8080
[更にここまで書いてENTER押下]

HTTP/1.1 200 OK
Date: Sat, 09 May 2015 08:06:31 GMT
Content-Length: 13
Content-Type: text/plain; charset=utf-8

Hello, World
[ENTER押下]
HTTP/1.1 400 Bad Request

最後の「HTTP/1.1 400 Bad Request」を受け取らないようにするには、ヘッダにConnection: closeを書きます。

$ nc localhost 8080
GET / HTTP/1.1
Host: localhost:8080
Connection: close
[ここまで書いてENTER押下]

HTTP/1.1 200 OK
Date: Sat, 09 May 2015 08:08:40 GMT
Content-Length: 13
Content-Type: text/plain; charset=utf-8
Connection: close

Hello, World

もちろん、HTTP 1.0でリクエストをすれば、Keep Aliveがデフォルトで無効の状態となり、最後の「HTTP/1.1 400 Bad Request」も受け取らなくなります。

$ nc localhost 8080
GET / HTTP/1.0
[ここまで書いてENTER押下]

HTTP/1.0 200 OK
Date: Sat, 09 May 2015 08:09:14 GMT
Content-Length: 13
Content-Type: text/plain; charset=utf-8

Hello, World

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
7
Help us understand the problem. What are the problem?