nghttpx: Don't discard data on HTTP/1 backend EOF

Also HTTP/1 frontend testing method was added.
This commit is contained in:
Tatsuhiro Tsujikawa 2015-01-20 22:19:28 +09:00
parent 6e446934d4
commit daec7c16d3
3 changed files with 92 additions and 3 deletions

View File

@ -9,6 +9,43 @@ import (
"testing" "testing"
) )
func TestH1H1PlainGET(t *testing.T) {
st := newServerTester(nil, t, noopHandler)
defer st.Close()
res, err := st.http1(requestParam{
name: "TestH1H1PlainGET",
})
if err != nil {
t.Errorf("Error st.http1() = %v", err)
}
want := 200
if got := res.status; got != want {
t.Errorf("status = %v; want %v", got, want)
}
}
func TestH1H1PlainGETClose(t *testing.T) {
st := newServerTester(nil, t, noopHandler)
defer st.Close()
res, err := st.http1(requestParam{
name: "TestH1H1PlainGET",
header: []hpack.HeaderField{
pair("Connection", "close"),
},
})
if err != nil {
t.Fatalf("Error st.http1() = %v", err)
}
want := 200
if got := res.status; got != want {
t.Errorf("status = %v; want %v", got, want)
}
}
func TestH2H1PlainGET(t *testing.T) { func TestH2H1PlainGET(t *testing.T) {
st := newServerTester(nil, t, noopHandler) st := newServerTester(nil, t, noopHandler)
defer st.Close() defer st.Close()

View File

@ -1,6 +1,7 @@
package nghttp2 package nghttp2
import ( import (
"bufio"
"bytes" "bytes"
"crypto/tls" "crypto/tls"
"errors" "errors"
@ -8,6 +9,8 @@ import (
"github.com/bradfitz/http2" "github.com/bradfitz/http2"
"github.com/bradfitz/http2/hpack" "github.com/bradfitz/http2/hpack"
"github.com/tatsuhiro-t/go-nghttp2" "github.com/tatsuhiro-t/go-nghttp2"
"io"
"io/ioutil"
"net" "net"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
@ -34,6 +37,7 @@ func pair(name, value string) hpack.HeaderField {
type serverTester struct { type serverTester struct {
args []string // command-line arguments args []string // command-line arguments
cmd *exec.Cmd // test frontend server process, which is test subject cmd *exec.Cmd // test frontend server process, which is test subject
url string // test frontend server URL
t *testing.T t *testing.T
ts *httptest.Server // backend server ts *httptest.Server // backend server
conn net.Conn // connection to frontend server conn net.Conn // connection to frontend server
@ -87,6 +91,7 @@ func newServerTester(args []string, t *testing.T, handler http.HandlerFunc) *ser
cmd: exec.Command(serverBin, args...), cmd: exec.Command(serverBin, args...),
t: t, t: t,
ts: ts, ts: ts,
url: fmt.Sprintf("http://127.0.0.1:%v", serverPort),
nextStreamID: 1, nextStreamID: 1,
authority: u.Host, authority: u.Host,
frCh: make(chan http2.Frame), frCh: make(chan http2.Frame),
@ -165,6 +170,47 @@ type requestParam struct {
body []byte // request body body []byte // request body
} }
func (st *serverTester) http1(rp requestParam) (*serverResponse, error) {
method := "GET"
if rp.method != "" {
method = rp.method
}
var body io.Reader
if rp.body != nil {
body = bytes.NewBuffer(rp.body)
}
req, err := http.NewRequest(method, st.url, body)
if err != nil {
return nil, err
}
for _, h := range rp.header {
req.Header.Add(h.Name, h.Value)
}
req.Header.Add("Test-Case", rp.name)
if err := req.Write(st.conn); err != nil {
return nil, err
}
resp, err := http.ReadResponse(bufio.NewReader(st.conn), req)
if err != nil {
return nil, err
}
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
resp.Body.Close()
res := &serverResponse{
status: resp.StatusCode,
header: resp.Header,
body: respBody,
}
return res, nil
}
func (st *serverTester) http2(rp requestParam) (*serverResponse, error) { func (st *serverTester) http2(rp requestParam) (*serverResponse, error) {
res := &serverResponse{} res := &serverResponse{}
st.headerBlkBuf.Reset() st.headerBlkBuf.Reset()

View File

@ -506,6 +506,11 @@ int HttpsUpstream::downstream_eof(DownstreamConnection *dconn) {
if (LOG_ENABLED(INFO)) { if (LOG_ENABLED(INFO)) {
DCLOG(INFO, dconn) << "EOF"; DCLOG(INFO, dconn) << "EOF";
} }
if (downstream->get_response_state() == Downstream::MSG_COMPLETE) {
goto end;
}
if (downstream->get_response_state() == Downstream::HEADER_COMPLETE) { if (downstream->get_response_state() == Downstream::HEADER_COMPLETE) {
// Server may indicate the end of the request by EOF // Server may indicate the end of the request by EOF
if (LOG_ENABLED(INFO)) { if (LOG_ENABLED(INFO)) {
@ -518,10 +523,11 @@ int HttpsUpstream::downstream_eof(DownstreamConnection *dconn) {
goto end; goto end;
} }
if (downstream->get_response_state() != Downstream::MSG_COMPLETE) { if (downstream->get_response_state() == Downstream::INITIAL) {
// error // we did not send any response headers, so we can reply error
// message.
if (LOG_ENABLED(INFO)) { if (LOG_ENABLED(INFO)) {
DCLOG(INFO, dconn) << "Treated as error"; DCLOG(INFO, dconn) << "Return error reply";
} }
if (error_reply(502) != 0) { if (error_reply(502) != 0) {
return -1; return -1;