nghttpx: Add --no-host-rewrite option
This commit is contained in:
parent
82f90f9030
commit
a68c4c1e3c
|
@ -160,6 +160,57 @@ func TestH1H1HostRewrite(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestH1H1HTTP10 tests that server can accept HTTP/1.0 request
|
||||||
|
// without Host header field
|
||||||
|
func TestH1H1HTTP10(t *testing.T) {
|
||||||
|
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Add("request-host", r.Host)
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
if _, err := io.WriteString(st.conn, "GET / HTTP/1.0\r\nTest-Case: TestH1H1HTTP10\r\n\r\n"); err != nil {
|
||||||
|
t.Fatalf("Error io.WriteString() = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error http.ReadResponse() = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := resp.StatusCode, 200; got != want {
|
||||||
|
t.Errorf("status: %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
if got, want := resp.Header.Get("request-host"), st.backendHost; got != want {
|
||||||
|
t.Errorf("request-host: %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestH1H1HTTP10NoHostRewrite tests that server generates host header
|
||||||
|
// field using actual backend server even if --no-http-rewrite is
|
||||||
|
// used.
|
||||||
|
func TestH1H1HTTP10NoHostRewrite(t *testing.T) {
|
||||||
|
st := newServerTester([]string{"--no-host-rewrite"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Add("request-host", r.Host)
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
if _, err := io.WriteString(st.conn, "GET / HTTP/1.0\r\nTest-Case: TestH1H1HTTP10NoHostRewrite\r\n\r\n"); err != nil {
|
||||||
|
t.Fatalf("Error io.WriteString() = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error http.ReadResponse() = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := resp.StatusCode, 200; got != want {
|
||||||
|
t.Errorf("status: %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
if got, want := resp.Header.Get("request-host"), st.backendHost; got != want {
|
||||||
|
t.Errorf("request-host: %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestH1H2ConnectFailure tests that server handles the situation that
|
// TestH1H2ConnectFailure tests that server handles the situation that
|
||||||
// connection attempt to HTTP/2 backend failed.
|
// connection attempt to HTTP/2 backend failed.
|
||||||
func TestH1H2ConnectFailure(t *testing.T) {
|
func TestH1H2ConnectFailure(t *testing.T) {
|
||||||
|
@ -230,6 +281,32 @@ func TestH1H2HTTP10(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestH1H2HTTP10NoHostRewrite tests that server generates host header
|
||||||
|
// field using actual backend server even if --no-http-rewrite is
|
||||||
|
// used.
|
||||||
|
func TestH1H2HTTP10NoHostRewrite(t *testing.T) {
|
||||||
|
st := newServerTester([]string{"--http2-bridge", "--no-host-rewrite"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Add("request-host", r.Host)
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
if _, err := io.WriteString(st.conn, "GET / HTTP/1.0\r\nTest-Case: TestH1H2HTTP10NoHostRewrite\r\n\r\n"); err != nil {
|
||||||
|
t.Fatalf("Error io.WriteString() = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error http.ReadResponse() = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := resp.StatusCode, 200; got != want {
|
||||||
|
t.Errorf("status: %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
if got, want := resp.Header.Get("request-host"), st.backendHost; got != want {
|
||||||
|
t.Errorf("request-host: %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestH1H2CrumbleCookie tests that Cookies are crumbled and assembled
|
// TestH1H2CrumbleCookie tests that Cookies are crumbled and assembled
|
||||||
// when forwarding to HTTP/2 backend link. go-nghttp2 server
|
// when forwarding to HTTP/2 backend link. go-nghttp2 server
|
||||||
// concatenates crumbled Cookies automatically, so this test is not
|
// concatenates crumbled Cookies automatically, so this test is not
|
||||||
|
|
|
@ -213,6 +213,28 @@ func TestH2H1HostRewrite(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestH2H1NoHostRewrite tests that server does not rewrite host
|
||||||
|
// header field
|
||||||
|
func TestH2H1NoHostRewrite(t *testing.T) {
|
||||||
|
st := newServerTester([]string{"--no-host-rewrite"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Add("request-host", r.Host)
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http2(requestParam{
|
||||||
|
name: "TestH2H1NoHostRewrite",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
|
}
|
||||||
|
if got, want := res.status, 200; got != want {
|
||||||
|
t.Errorf("status: %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
if got, want := res.header.Get("request-host"), st.frontendHost; got != want {
|
||||||
|
t.Errorf("request-host: %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestH2H1BadRequestCL tests that server rejects request whose
|
// TestH2H1BadRequestCL tests that server rejects request whose
|
||||||
// content-length header field value does not match its request body
|
// content-length header field value does not match its request body
|
||||||
// size.
|
// size.
|
||||||
|
@ -626,3 +648,25 @@ func TestH2H2HostRewrite(t *testing.T) {
|
||||||
t.Errorf("request-host: %v; want %v", got, want)
|
t.Errorf("request-host: %v; want %v", got, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestH2H2NoHostRewrite tests that server does not rewrite host
|
||||||
|
// header field
|
||||||
|
func TestH2H2NoHostRewrite(t *testing.T) {
|
||||||
|
st := newServerTester([]string{"--http2-bridge", "--no-host-rewrite"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Add("request-host", r.Host)
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http2(requestParam{
|
||||||
|
name: "TestH2H2NoHostRewrite",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
|
}
|
||||||
|
if got, want := res.status, 200; got != want {
|
||||||
|
t.Errorf("status: %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
if got, want := res.header.Get("request-host"), st.frontendHost; got != want {
|
||||||
|
t.Errorf("request-host: %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -42,6 +42,7 @@ type serverTester struct {
|
||||||
url string // test frontend server URL
|
url string // test frontend server URL
|
||||||
t *testing.T
|
t *testing.T
|
||||||
ts *httptest.Server // backend server
|
ts *httptest.Server // backend server
|
||||||
|
frontendHost string // frontend server host
|
||||||
backendHost string // backend server host
|
backendHost string // backend server host
|
||||||
conn net.Conn // connection to frontend server
|
conn net.Conn // connection to frontend server
|
||||||
h2PrefaceSent bool // HTTP/2 preface was sent in conn
|
h2PrefaceSent bool // HTTP/2 preface was sent in conn
|
||||||
|
@ -125,6 +126,7 @@ func newServerTesterInternal(args []string, t *testing.T, handler http.HandlerFu
|
||||||
t: t,
|
t: t,
|
||||||
ts: ts,
|
ts: ts,
|
||||||
url: fmt.Sprintf("%v://%v", scheme, authority),
|
url: fmt.Sprintf("%v://%v", scheme, authority),
|
||||||
|
frontendHost: fmt.Sprintf("127.0.0.1:%v", serverPort),
|
||||||
backendHost: backendURL.Host,
|
backendHost: backendURL.Host,
|
||||||
nextStreamID: 1,
|
nextStreamID: 1,
|
||||||
authority: authority,
|
authority: authority,
|
||||||
|
|
11
src/shrpx.cc
11
src/shrpx.cc
|
@ -766,6 +766,7 @@ void fill_default_config() {
|
||||||
|
|
||||||
mod_config()->tls_proto_mask = 0;
|
mod_config()->tls_proto_mask = 0;
|
||||||
mod_config()->no_location_rewrite = false;
|
mod_config()->no_location_rewrite = false;
|
||||||
|
mod_config()->no_host_rewrite = false;
|
||||||
mod_config()->argc = 0;
|
mod_config()->argc = 0;
|
||||||
mod_config()->argv = nullptr;
|
mod_config()->argv = nullptr;
|
||||||
mod_config()->downstream_connections_per_host = 8;
|
mod_config()->downstream_connections_per_host = 8;
|
||||||
|
@ -1168,6 +1169,11 @@ HTTP:
|
||||||
--client and default mode. For --http2-proxy and
|
--client and default mode. For --http2-proxy and
|
||||||
--client-proxy mode, location header field will not be
|
--client-proxy mode, location header field will not be
|
||||||
altered regardless of this option.
|
altered regardless of this option.
|
||||||
|
--no-host-rewrite
|
||||||
|
Don't rewrite host and :authority header fields on
|
||||||
|
--http2-bridge, --client and default mode. For
|
||||||
|
--http2-proxy and --client-proxy mode, these headers
|
||||||
|
will not be altered regardless of this option.
|
||||||
--altsvc=<PROTOID,PORT[,HOST,[ORIGIN]]>
|
--altsvc=<PROTOID,PORT[,HOST,[ORIGIN]]>
|
||||||
Specify protocol ID, port, host and origin of
|
Specify protocol ID, port, host and origin of
|
||||||
alternative service. <HOST> and <ORIGIN> are optional.
|
alternative service. <HOST> and <ORIGIN> are optional.
|
||||||
|
@ -1332,6 +1338,7 @@ int main(int argc, char **argv) {
|
||||||
{"tls-ctx-per-worker", no_argument, &flag, 70},
|
{"tls-ctx-per-worker", no_argument, &flag, 70},
|
||||||
{"backend-response-buffer", required_argument, &flag, 71},
|
{"backend-response-buffer", required_argument, &flag, 71},
|
||||||
{"backend-request-buffer", required_argument, &flag, 72},
|
{"backend-request-buffer", required_argument, &flag, 72},
|
||||||
|
{"no-host-rewrite", no_argument, &flag, 73},
|
||||||
{nullptr, 0, nullptr, 0}};
|
{nullptr, 0, nullptr, 0}};
|
||||||
|
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
|
@ -1661,6 +1668,10 @@ int main(int argc, char **argv) {
|
||||||
// --backend-request-buffer
|
// --backend-request-buffer
|
||||||
cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_REQUEST_BUFFER, optarg);
|
cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_REQUEST_BUFFER, optarg);
|
||||||
break;
|
break;
|
||||||
|
case 73:
|
||||||
|
// --no-host-rewrite
|
||||||
|
cmdcfgs.emplace_back(SHRPX_OPT_NO_HOST_REWRITE, "yes");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,6 +133,7 @@ const char SHRPX_OPT_ADD_RESPONSE_HEADER[] = "add-response-header";
|
||||||
const char SHRPX_OPT_WORKER_FRONTEND_CONNECTIONS[] =
|
const char SHRPX_OPT_WORKER_FRONTEND_CONNECTIONS[] =
|
||||||
"worker-frontend-connections";
|
"worker-frontend-connections";
|
||||||
const char SHRPX_OPT_NO_LOCATION_REWRITE[] = "no-location-rewrite";
|
const char SHRPX_OPT_NO_LOCATION_REWRITE[] = "no-location-rewrite";
|
||||||
|
const char SHRPX_OPT_NO_HOST_REWRITE[] = "no-host-rewrite";
|
||||||
const char SHRPX_OPT_BACKEND_HTTP1_CONNECTIONS_PER_HOST[] =
|
const char SHRPX_OPT_BACKEND_HTTP1_CONNECTIONS_PER_HOST[] =
|
||||||
"backend-http1-connections-per-host";
|
"backend-http1-connections-per-host";
|
||||||
const char SHRPX_OPT_BACKEND_HTTP1_CONNECTIONS_PER_FRONTEND[] =
|
const char SHRPX_OPT_BACKEND_HTTP1_CONNECTIONS_PER_FRONTEND[] =
|
||||||
|
@ -1079,6 +1080,12 @@ int parse_config(const char *opt, const char *optarg) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (util::strieq(opt, SHRPX_OPT_NO_HOST_REWRITE)) {
|
||||||
|
mod_config()->no_host_rewrite = util::strieq(optarg, "yes");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (util::strieq(opt, SHRPX_OPT_BACKEND_HTTP1_CONNECTIONS_PER_HOST)) {
|
if (util::strieq(opt, SHRPX_OPT_BACKEND_HTTP1_CONNECTIONS_PER_HOST)) {
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
|
|
|
@ -123,6 +123,7 @@ extern const char SHRPX_OPT_ALTSVC[];
|
||||||
extern const char SHRPX_OPT_ADD_RESPONSE_HEADER[];
|
extern const char SHRPX_OPT_ADD_RESPONSE_HEADER[];
|
||||||
extern const char SHRPX_OPT_WORKER_FRONTEND_CONNECTIONS[];
|
extern const char SHRPX_OPT_WORKER_FRONTEND_CONNECTIONS[];
|
||||||
extern const char SHRPX_OPT_NO_LOCATION_REWRITE[];
|
extern const char SHRPX_OPT_NO_LOCATION_REWRITE[];
|
||||||
|
extern const char SHRPX_OPT_NO_HOST_REWRITE[];
|
||||||
extern const char SHRPX_OPT_BACKEND_HTTP1_CONNECTIONS_PER_HOST[];
|
extern const char SHRPX_OPT_BACKEND_HTTP1_CONNECTIONS_PER_HOST[];
|
||||||
extern const char SHRPX_OPT_BACKEND_HTTP1_CONNECTIONS_PER_FRONTEND[];
|
extern const char SHRPX_OPT_BACKEND_HTTP1_CONNECTIONS_PER_FRONTEND[];
|
||||||
extern const char SHRPX_OPT_LISTENER_DISABLE_TIMEOUT[];
|
extern const char SHRPX_OPT_LISTENER_DISABLE_TIMEOUT[];
|
||||||
|
@ -299,6 +300,7 @@ struct Config {
|
||||||
bool http2_no_cookie_crumbling;
|
bool http2_no_cookie_crumbling;
|
||||||
bool upstream_frame_debug;
|
bool upstream_frame_debug;
|
||||||
bool no_location_rewrite;
|
bool no_location_rewrite;
|
||||||
|
bool no_host_rewrite;
|
||||||
bool auto_tls_ticket_key;
|
bool auto_tls_ticket_key;
|
||||||
bool tls_ctx_per_worker;
|
bool tls_ctx_per_worker;
|
||||||
};
|
};
|
||||||
|
|
|
@ -234,7 +234,8 @@ int Http2DownstreamConnection::push_request_headers() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *authority = nullptr, *host = nullptr;
|
const char *authority = nullptr, *host = nullptr;
|
||||||
if (!get_config()->http2_proxy && !get_config()->client_proxy) {
|
if (!get_config()->no_host_rewrite && !get_config()->http2_proxy &&
|
||||||
|
!get_config()->client_proxy) {
|
||||||
// HTTP/2 backend does not support multiple address, so we always
|
// HTTP/2 backend does not support multiple address, so we always
|
||||||
// use index = 0.
|
// use index = 0.
|
||||||
if (!downstream_->get_request_http2_authority().empty()) {
|
if (!downstream_->get_request_http2_authority().empty()) {
|
||||||
|
@ -341,7 +342,8 @@ int Http2DownstreamConnection::push_request_headers() {
|
||||||
nva.push_back(http2::make_nv_ls(":path", path));
|
nva.push_back(http2::make_nv_ls(":path", path));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!get_config()->http2_proxy && !get_config()->client_proxy) {
|
if (!get_config()->no_host_rewrite && !get_config()->http2_proxy &&
|
||||||
|
!get_config()->client_proxy) {
|
||||||
if (authority) {
|
if (authority) {
|
||||||
nva.push_back(http2::make_nv_lc(":authority", authority));
|
nva.push_back(http2::make_nv_lc(":authority", authority));
|
||||||
}
|
}
|
||||||
|
|
|
@ -226,7 +226,8 @@ int HttpDownstreamConnection::attach_downstream(Downstream *downstream) {
|
||||||
|
|
||||||
int HttpDownstreamConnection::push_request_headers() {
|
int HttpDownstreamConnection::push_request_headers() {
|
||||||
const char *authority = nullptr, *host = nullptr;
|
const char *authority = nullptr, *host = nullptr;
|
||||||
if (!get_config()->http2_proxy && !get_config()->client_proxy) {
|
if (!get_config()->no_host_rewrite && !get_config()->http2_proxy &&
|
||||||
|
!get_config()->client_proxy) {
|
||||||
if (!downstream_->get_request_http2_authority().empty()) {
|
if (!downstream_->get_request_http2_authority().empty()) {
|
||||||
authority = get_config()->downstream_addrs[addr_idx_].hostport.get();
|
authority = get_config()->downstream_addrs[addr_idx_].hostport.get();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue