Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

net/http : Keepalive is not supported correctly on server for HTTP 1.0 when response body size is bigger than 2048 bytes #32540

Closed
dmitry3001 opened this issue Jun 10, 2019 · 5 comments

Comments

Projects
None yet
3 participants
@dmitry3001
Copy link

commented Jun 10, 2019

What version of Go are you using (go version)?

$ go version
go1.12.5 linux/amd64

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env

GOARCH="amd64"
GOBIN=""
GOCACHE="/root/.cache/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/go"
GOPROXY=""
GORACE=""
GOROOT="/usr/local/go"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build757355127=/tmp/go-build -gno-record-gcc-switches"

What did you do?

  1. I have started HTTP server using following code. Http server generates response of size passed in "Generated-Response-Size" header.
package main

import (
	"io"
	"io/ioutil"
	"math/rand"
	"net/http"
	"strconv"
)

func hello(w http.ResponseWriter, r *http.Request) {
	ioutil.ReadAll(r.Body)
	defer r.Body.Close()

	len, err := strconv.Atoi(r.Header.Get("Generated-Response-Size"))
	if err != nil{
		panic(err)
	}

	io.WriteString(w, generateString(len))
}

func generateString(size int) string {
	bytes := make([]byte, size)
	for i := 0; i < size; i++ {
		bytes[i] = byte(65 + rand.Intn(25))
	}
	return string(bytes)
}

func main() {
	http.HandleFunc("/", hello)
	http.ListenAndServe(":9000", nil)
}

I have executed curl with following options

curl --http1.0 -v -X POST -H 'Connection: keep-alive' -H 'Generated-Response-Size: 2049'    http://localhost:9000

What did you expect to see?

* Rebuilt URL to: http://localhost:9000/
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 9000 (#0)
> POST / HTTP/1.0
> Host: localhost:9000
> User-Agent: curl/7.47.0
> Accept: */*
> Connection: keep-alive
> Generated-Response-Size: 2049
>
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Date: Mon, 10 Jun 2019 23:34:33 GMT
< Content-Length: 2049
< Content-Type: text/plain; charset=utf-8
* HTTP/1.0 connection set to keep alive!
**< Connection: keep-alive
<
* Connection #0 to host localhost left intact

What did you see instead?

* Rebuilt URL to: http://localhost:9000/
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 9000 (#0)
> POST / HTTP/1.0
> Host: localhost:9000
> User-Agent: curl/7.47.0
> Accept: */*
> Connection: keep-alive
> Generated-Response-Size: 2049
>
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Date: Mon, 10 Jun 2019 23:34:37 GMT
< Content-Type: text/plain; charset=utf-8
<
* Closing connection 0

The expectation is to see Connection #0 to host localhost left intact instead of Closing connection 0 . In the same time, when I pass any number less than 2049 "Generated-Response-Size" I can see the expected output and keepalive supported by the server correctly.

@fraenkel

This comment has been minimized.

Copy link
Contributor

commented Jun 11, 2019

The Server is making a best effort to generate a Content-Length which is required for Keep-Alive. The default buffer size is 2048 before chunking takes over which is not supported for http 1.0. The result is a response which has no Content-Length and will close the connection.
If you want to guarantee keep-alive with http 1.0, it would be best if you set a Content-Length rather than allow the Server to do its best.

@dmitry3001

This comment has been minimized.

Copy link
Author

commented Jun 11, 2019

This actually means that HTTP server is not fully 1.0 spec compliant. Does this look more like known issue or bug ?

@fraenkel

This comment has been minimized.

Copy link
Contributor

commented Jun 11, 2019

I would be curious how this relates to spec compliance. Please see https://en.wikipedia.org/wiki/HTTP_persistent_connection for an explanation for 1.0 support which is not part of any official spec.

If you were doing http 1.1 which is much more common, then chunking would have occurred and the connection would have been kept alive.

@dmitry3001

This comment has been minimized.

Copy link
Author

commented Jun 11, 2019

Agree, persistent connections are not parts of any official specs... That should probably be just a known issue for HTTP 1.0, I'm about to close the thread

@FiloSottile

This comment has been minimized.

Copy link
Member

commented Jun 13, 2019

Sounds like expected behavior due to HTTP/1.0 not supporting chunking.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.