diff --git a/integration-tests/nghttpx_http1_test.go b/integration-tests/nghttpx_http1_test.go index 3114ad9c..48ac9f7c 100644 --- a/integration-tests/nghttpx_http1_test.go +++ b/integration-tests/nghttpx_http1_test.go @@ -209,3 +209,74 @@ func TestH1H2CrumbleCookie(t *testing.T) { t.Errorf("status: %v; want %v", got, want) } } + +// TestH1H2GenerateVia tests that server generates Via header field to and +// from backend server. +func TestH1H2GenerateVia(t *testing.T) { + st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) { + if got, want := r.Header.Get("Via"), "1.1 nghttpx"; got != want { + t.Errorf("Via: %v; want %v", got, want) + } + }) + defer st.Close() + + res, err := st.http1(requestParam{ + name: "TestH1H2GenerateVia", + }) + if err != nil { + t.Fatalf("Error st.http1() = %v", err) + } + if got, want := res.header.Get("Via"), "2.0 nghttpx"; got != want { + t.Errorf("Via: %v; want %v", got, want) + } +} + +// TestH1H2AppendVia tests that server adds value to existing Via +// header field to and from backend server. +func TestH1H2AppendVia(t *testing.T) { + st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) { + if got, want := r.Header.Get("Via"), "foo, 1.1 nghttpx"; got != want { + t.Errorf("Via: %v; want %v", got, want) + } + w.Header().Add("Via", "bar") + }) + defer st.Close() + + res, err := st.http1(requestParam{ + name: "TestH1H2AppendVia", + header: []hpack.HeaderField{ + pair("via", "foo"), + }, + }) + if err != nil { + t.Fatalf("Error st.http1() = %v", err) + } + if got, want := res.header.Get("Via"), "bar, 2.0 nghttpx"; got != want { + t.Errorf("Via: %v; want %v", got, want) + } +} + +// TestH1H2NoVia tests that server does not add value to existing Via +// header field to and from backend server. +func TestH1H2NoVia(t *testing.T) { + st := newServerTester([]string{"--http2-bridge", "--no-via"}, t, func(w http.ResponseWriter, r *http.Request) { + if got, want := r.Header.Get("Via"), "foo"; got != want { + t.Errorf("Via: %v; want %v", got, want) + } + w.Header().Add("Via", "bar") + }) + defer st.Close() + + res, err := st.http1(requestParam{ + name: "TestH1H2NoVia", + header: []hpack.HeaderField{ + pair("via", "foo"), + }, + }) + if err != nil { + t.Fatalf("Error st.http1() = %v", err) + } + if got, want := res.header.Get("Via"), "bar"; got != want { + t.Errorf("Via: %v; want %v", got, want) + } +} diff --git a/integration-tests/nghttpx_http2_test.go b/integration-tests/nghttpx_http2_test.go index 3f5ab860..6efe9859 100644 --- a/integration-tests/nghttpx_http2_test.go +++ b/integration-tests/nghttpx_http2_test.go @@ -121,6 +121,77 @@ func TestH2H1StripAddXff(t *testing.T) { } } +// TestH2H1GenerateVia tests that server generates Via header field to and +// from backend server. +func TestH2H1GenerateVia(t *testing.T) { + st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) { + if got, want := r.Header.Get("Via"), "2.0 nghttpx"; got != want { + t.Errorf("Via: %v; want %v", got, want) + } + }) + defer st.Close() + + res, err := st.http2(requestParam{ + name: "TestH2H1GenerateVia", + }) + if err != nil { + t.Fatalf("Error st.http2() = %v", err) + } + if got, want := res.header.Get("Via"), "1.1 nghttpx"; got != want { + t.Errorf("Via: %v; want %v", got, want) + } +} + +// TestH2H1AppendVia tests that server adds value to existing Via +// header field to and from backend server. +func TestH2H1AppendVia(t *testing.T) { + st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) { + if got, want := r.Header.Get("Via"), "foo, 2.0 nghttpx"; got != want { + t.Errorf("Via: %v; want %v", got, want) + } + w.Header().Add("Via", "bar") + }) + defer st.Close() + + res, err := st.http2(requestParam{ + name: "TestH2H1AppendVia", + header: []hpack.HeaderField{ + pair("via", "foo"), + }, + }) + if err != nil { + t.Fatalf("Error st.http2() = %v", err) + } + if got, want := res.header.Get("Via"), "bar, 1.1 nghttpx"; got != want { + t.Errorf("Via: %v; want %v", got, want) + } +} + +// TestH2H1NoVia tests that server does not add value to existing Via +// header field to and from backend server. +func TestH2H1NoVia(t *testing.T) { + st := newServerTester([]string{"--no-via"}, t, func(w http.ResponseWriter, r *http.Request) { + if got, want := r.Header.Get("Via"), "foo"; got != want { + t.Errorf("Via: %v; want %v", got, want) + } + w.Header().Add("Via", "bar") + }) + defer st.Close() + + res, err := st.http2(requestParam{ + name: "TestH2H1NoVia", + header: []hpack.HeaderField{ + pair("via", "foo"), + }, + }) + if err != nil { + t.Fatalf("Error st.http2() = %v", err) + } + if got, want := res.header.Get("Via"), "bar"; got != want { + t.Errorf("Via: %v; want %v", got, want) + } +} + // TestH2H1BadRequestCL tests that server rejects request whose // content-length header field value does not match its request body // size. diff --git a/integration-tests/nghttpx_spdy_test.go b/integration-tests/nghttpx_spdy_test.go index 6cf356d9..0b289397 100644 --- a/integration-tests/nghttpx_spdy_test.go +++ b/integration-tests/nghttpx_spdy_test.go @@ -99,6 +99,77 @@ func TestS3H1InvalidRequestCL(t *testing.T) { } } +// TestS3H1GenerateVia tests that server generates Via header field to and +// from backend server. +func TestS3H1GenerateVia(t *testing.T) { + st := newServerTesterTLS([]string{"--npn-list=spdy/3.1"}, t, func(w http.ResponseWriter, r *http.Request) { + if got, want := r.Header.Get("Via"), "1.1 nghttpx"; got != want { + t.Errorf("Via: %v; want %v", got, want) + } + }) + defer st.Close() + + res, err := st.spdy(requestParam{ + name: "TestS3H1GenerateVia", + }) + if err != nil { + t.Fatalf("Error st.spdy() = %v", err) + } + if got, want := res.header.Get("Via"), "1.1 nghttpx"; got != want { + t.Errorf("Via: %v; want %v", got, want) + } +} + +// TestS3H1AppendVia tests that server adds value to existing Via +// header field to and from backend server. +func TestS3H1AppendVia(t *testing.T) { + st := newServerTesterTLS([]string{"--npn-list=spdy/3.1"}, t, func(w http.ResponseWriter, r *http.Request) { + if got, want := r.Header.Get("Via"), "foo, 1.1 nghttpx"; got != want { + t.Errorf("Via: %v; want %v", got, want) + } + w.Header().Add("Via", "bar") + }) + defer st.Close() + + res, err := st.spdy(requestParam{ + name: "TestS3H1AppendVia", + header: []hpack.HeaderField{ + pair("via", "foo"), + }, + }) + if err != nil { + t.Fatalf("Error st.spdy() = %v", err) + } + if got, want := res.header.Get("Via"), "bar, 1.1 nghttpx"; got != want { + t.Errorf("Via: %v; want %v", got, want) + } +} + +// TestS3H1NoVia tests that server does not add value to existing Via +// header field to and from backend server. +func TestS3H1NoVia(t *testing.T) { + st := newServerTesterTLS([]string{"--npn-list=spdy/3.1", "--no-via"}, t, func(w http.ResponseWriter, r *http.Request) { + if got, want := r.Header.Get("Via"), "foo"; got != want { + t.Errorf("Via: %v; want %v", got, want) + } + w.Header().Add("Via", "bar") + }) + defer st.Close() + + res, err := st.spdy(requestParam{ + name: "TestS3H1NoVia", + header: []hpack.HeaderField{ + pair("via", "foo"), + }, + }) + if err != nil { + t.Fatalf("Error st.spdy() = %v", err) + } + if got, want := res.header.Get("Via"), "bar"; got != want { + t.Errorf("Via: %v; want %v", got, want) + } +} + // TestS3H2ConnectFailure tests that server handles the situation that // connection attempt to HTTP/2 backend failed. func TestS3H2ConnectFailure(t *testing.T) { diff --git a/src/shrpx_spdy_upstream.cc b/src/shrpx_spdy_upstream.cc index 41264cfb..5844d587 100644 --- a/src/shrpx_spdy_upstream.cc +++ b/src/shrpx_spdy_upstream.cc @@ -886,8 +886,13 @@ int SpdyUpstream::on_downstream_header_complete(Downstream *downstream) { } } - if (!get_config()->no_via) { - auto via = downstream->get_response_header(http2::HD_VIA); + auto via = downstream->get_response_header(http2::HD_VIA); + if (get_config()->no_via) { + if (via) { + nv[hdidx++] = "via"; + nv[hdidx++] = via->value.c_str(); + } + } else { if (via) { via_value = via->value; via_value += ", ";