nghttpx: Support unknown method
This commit is contained in:
parent
852a320586
commit
f38babe30f
|
@ -53,23 +53,20 @@ func TestH1H1PlainGETClose(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestH1H1InvalidMethod tests that server rejects invalid method with
|
// TestH1H1UnknownMethod tests that server can forward unknown method
|
||||||
// 501 status code
|
func TestH1H1UnknownMethod(t *testing.T) {
|
||||||
func TestH1H1InvalidMethod(t *testing.T) {
|
st := newServerTester(nil, t, noopHandler)
|
||||||
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
t.Errorf("server should not forward this request")
|
|
||||||
})
|
|
||||||
defer st.Close()
|
defer st.Close()
|
||||||
|
|
||||||
res, err := st.http1(requestParam{
|
res, err := st.http1(requestParam{
|
||||||
name: "TestH1H1InvalidMethod",
|
name: "TestH1H1UnknownMethod",
|
||||||
method: "get",
|
method: "get",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error st.http1() = %v", err)
|
t.Fatalf("Error st.http1() = %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if got, want := res.status, 501; got != want {
|
if got, want := res.status, 200; got != want {
|
||||||
t.Errorf("status = %v; want %v", got, want)
|
t.Errorf("status = %v; want %v", got, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -589,22 +589,19 @@ func TestH2H1InvalidRequestCL(t *testing.T) {
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// TestH2H1InvalidMethod tests that server rejects invalid method with
|
// TestH2H1UnknownMethod tests that server can forward unknown method.
|
||||||
// 501.
|
func TestH2H1UnknownMethod(t *testing.T) {
|
||||||
func TestH2H1InvalidMethod(t *testing.T) {
|
st := newServerTester(nil, t, noopHandler)
|
||||||
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
t.Errorf("server should not forward this request")
|
|
||||||
})
|
|
||||||
defer st.Close()
|
defer st.Close()
|
||||||
|
|
||||||
res, err := st.http2(requestParam{
|
res, err := st.http2(requestParam{
|
||||||
name: "TestH2H1InvalidMethod",
|
name: "TestH2H1UnknownMethod",
|
||||||
method: "get",
|
method: "get",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error st.http2() = %v", err)
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
}
|
}
|
||||||
if got, want := res.status, 501; got != want {
|
if got, want := res.status, 200; got != want {
|
||||||
t.Errorf("status: %v; want %v", got, want)
|
t.Errorf("status: %v; want %v", got, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -210,22 +210,19 @@ func TestS3H1HeaderFields(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestS3H1InvalidMethod tests that server rejects invalid method with
|
// TestS3H1UnknownMethod tests that server can forward unknown method.
|
||||||
// 501.
|
func TestS3H1UnknownMethod(t *testing.T) {
|
||||||
func TestS3H1InvalidMethod(t *testing.T) {
|
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1"}, t, noopHandler)
|
||||||
st := newServerTesterTLS([]string{"--npn-list=spdy/3.1"}, t, func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
t.Errorf("server should not forward this request")
|
|
||||||
})
|
|
||||||
defer st.Close()
|
defer st.Close()
|
||||||
|
|
||||||
res, err := st.spdy(requestParam{
|
res, err := st.spdy(requestParam{
|
||||||
name: "TestS3H1InvalidMethod",
|
name: "TestS3H1UnknownMethod",
|
||||||
method: "get",
|
method: "get",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error st.spdy() = %v", err)
|
t.Fatalf("Error st.spdy() = %v", err)
|
||||||
}
|
}
|
||||||
if got, want := res.status, 501; got != want {
|
if got, want := res.status, 200; got != want {
|
||||||
t.Errorf("status: %v; want %v", got, want)
|
t.Errorf("status: %v; want %v", got, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -824,7 +824,7 @@ ClientHandler::get_downstream_connection(Downstream *downstream) {
|
||||||
// proxy mode falls in this case.
|
// proxy mode falls in this case.
|
||||||
if (groups.size() == 1) {
|
if (groups.size() == 1) {
|
||||||
group_idx = 0;
|
group_idx = 0;
|
||||||
} else if (req.method == HTTP_CONNECT) {
|
} else if (req.method_token == HTTP_CONNECT) {
|
||||||
// We don't know how to treat CONNECT request in host-path
|
// We don't know how to treat CONNECT request in host-path
|
||||||
// mapping. It most likely appears in proxy scenario. Since we
|
// mapping. It most likely appears in proxy scenario. Since we
|
||||||
// have dealt with proxy case already, just use catch-all group.
|
// have dealt with proxy case already, just use catch-all group.
|
||||||
|
@ -1040,14 +1040,14 @@ void ClientHandler::write_accesslog(Downstream *downstream) {
|
||||||
upstream_accesslog(
|
upstream_accesslog(
|
||||||
get_config()->logging.access.format,
|
get_config()->logging.access.format,
|
||||||
LogSpec{
|
LogSpec{
|
||||||
downstream, StringRef{ipaddr_}, http2::to_method_string(req.method),
|
downstream, StringRef{ipaddr_}, req.method,
|
||||||
|
|
||||||
req.method == HTTP_CONNECT
|
req.method_token == HTTP_CONNECT
|
||||||
? StringRef(req.authority)
|
? StringRef(req.authority)
|
||||||
: get_config()->http2_proxy
|
: get_config()->http2_proxy
|
||||||
? StringRef(construct_absolute_request_uri(balloc, req))
|
? StringRef(construct_absolute_request_uri(balloc, req))
|
||||||
: req.path.empty()
|
: req.path.empty()
|
||||||
? req.method == HTTP_OPTIONS
|
? req.method_token == HTTP_OPTIONS
|
||||||
? StringRef::from_lit("*")
|
? StringRef::from_lit("*")
|
||||||
: StringRef::from_lit("-")
|
: StringRef::from_lit("-")
|
||||||
: StringRef(req.path),
|
: StringRef(req.path),
|
||||||
|
|
|
@ -635,7 +635,7 @@ bool Downstream::validate_response_recv_body_length() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Downstream::check_upgrade_fulfilled() {
|
void Downstream::check_upgrade_fulfilled() {
|
||||||
if (req_.method == HTTP_CONNECT) {
|
if (req_.method_token == HTTP_CONNECT) {
|
||||||
upgraded_ = 200 <= resp_.http_status && resp_.http_status < 300;
|
upgraded_ = 200 <= resp_.http_status && resp_.http_status < 300;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -650,13 +650,13 @@ void Downstream::check_upgrade_fulfilled() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Downstream::inspect_http2_request() {
|
void Downstream::inspect_http2_request() {
|
||||||
if (req_.method == HTTP_CONNECT) {
|
if (req_.method_token == HTTP_CONNECT) {
|
||||||
req_.upgrade_request = true;
|
req_.upgrade_request = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Downstream::inspect_http1_request() {
|
void Downstream::inspect_http1_request() {
|
||||||
if (req_.method == HTTP_CONNECT) {
|
if (req_.method_token == HTTP_CONNECT) {
|
||||||
req_.upgrade_request = true;
|
req_.upgrade_request = true;
|
||||||
} else {
|
} else {
|
||||||
auto upgrade = req_.fs.header(http2::HD_UPGRADE);
|
auto upgrade = req_.fs.header(http2::HD_UPGRADE);
|
||||||
|
@ -741,7 +741,7 @@ bool Downstream::get_expect_final_response() const {
|
||||||
|
|
||||||
bool Downstream::expect_response_body() const {
|
bool Downstream::expect_response_body() const {
|
||||||
return !resp_.headers_only &&
|
return !resp_.headers_only &&
|
||||||
http2::expect_response_body(req_.method, resp_.http_status);
|
http2::expect_response_body(req_.method_token, resp_.http_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Downstream::expect_response_trailer() const {
|
bool Downstream::expect_response_trailer() const {
|
||||||
|
|
|
@ -126,7 +126,7 @@ struct Request {
|
||||||
: fs(balloc, 16),
|
: fs(balloc, 16),
|
||||||
recv_body_length(0),
|
recv_body_length(0),
|
||||||
unconsumed_body_length(0),
|
unconsumed_body_length(0),
|
||||||
method(-1),
|
method_token(-1),
|
||||||
http_major(1),
|
http_major(1),
|
||||||
http_minor(1),
|
http_minor(1),
|
||||||
upgrade_request(false),
|
upgrade_request(false),
|
||||||
|
@ -158,7 +158,8 @@ struct Request {
|
||||||
int64_t recv_body_length;
|
int64_t recv_body_length;
|
||||||
// The number of bytes not consumed by the application yet.
|
// The number of bytes not consumed by the application yet.
|
||||||
size_t unconsumed_body_length;
|
size_t unconsumed_body_length;
|
||||||
int method;
|
StringRef method;
|
||||||
|
int method_token;
|
||||||
// HTTP major and minor version
|
// HTTP major and minor version
|
||||||
int http_major, http_minor;
|
int http_major, http_minor;
|
||||||
// Returns true if the request is HTTP upgrade (HTTP Upgrade or
|
// Returns true if the request is HTTP upgrade (HTTP Upgrade or
|
||||||
|
|
|
@ -103,7 +103,7 @@ int Http2DownstreamConnection::attach_downstream(Downstream *downstream) {
|
||||||
auto &req = downstream_->request();
|
auto &req = downstream_->request();
|
||||||
|
|
||||||
// HTTP/2 disables HTTP Upgrade.
|
// HTTP/2 disables HTTP Upgrade.
|
||||||
if (req.method != HTTP_CONNECT) {
|
if (req.method_token != HTTP_CONNECT) {
|
||||||
req.upgrade_request = false;
|
req.upgrade_request = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,7 +251,7 @@ int Http2DownstreamConnection::push_request_headers() {
|
||||||
|
|
||||||
auto no_host_rewrite = httpconf.no_host_rewrite ||
|
auto no_host_rewrite = httpconf.no_host_rewrite ||
|
||||||
get_config()->http2_proxy ||
|
get_config()->http2_proxy ||
|
||||||
req.method == HTTP_CONNECT;
|
req.method_token == HTTP_CONNECT;
|
||||||
|
|
||||||
// http2session_ has already in CONNECTED state, so we can get
|
// http2session_ has already in CONNECTED state, so we can get
|
||||||
// addr_idx here.
|
// addr_idx here.
|
||||||
|
@ -286,15 +286,14 @@ int Http2DownstreamConnection::push_request_headers() {
|
||||||
nva.reserve(req.fs.headers().size() + 9 + num_cookies +
|
nva.reserve(req.fs.headers().size() + 9 + num_cookies +
|
||||||
httpconf.add_request_headers.size());
|
httpconf.add_request_headers.size());
|
||||||
|
|
||||||
nva.push_back(
|
nva.push_back(http2::make_nv_ls_nocopy(":method", req.method));
|
||||||
http2::make_nv_ls_nocopy(":method", http2::to_method_string(req.method)));
|
|
||||||
|
|
||||||
if (req.method != HTTP_CONNECT) {
|
if (req.method_token != HTTP_CONNECT) {
|
||||||
assert(!req.scheme.empty());
|
assert(!req.scheme.empty());
|
||||||
|
|
||||||
nva.push_back(http2::make_nv_ls_nocopy(":scheme", req.scheme));
|
nva.push_back(http2::make_nv_ls_nocopy(":scheme", req.scheme));
|
||||||
|
|
||||||
if (req.method == HTTP_OPTIONS && req.path.empty()) {
|
if (req.method_token == HTTP_OPTIONS && req.path.empty()) {
|
||||||
nva.push_back(http2::make_nv_ll(":path", "*"));
|
nva.push_back(http2::make_nv_ll(":path", "*"));
|
||||||
} else {
|
} else {
|
||||||
nva.push_back(http2::make_nv_ls_nocopy(":path", req.path));
|
nva.push_back(http2::make_nv_ls_nocopy(":path", req.path));
|
||||||
|
@ -333,7 +332,7 @@ int Http2DownstreamConnection::push_request_headers() {
|
||||||
if (fwdconf.params) {
|
if (fwdconf.params) {
|
||||||
auto params = fwdconf.params;
|
auto params = fwdconf.params;
|
||||||
|
|
||||||
if (get_config()->http2_proxy || req.method == HTTP_CONNECT) {
|
if (get_config()->http2_proxy || req.method_token == HTTP_CONNECT) {
|
||||||
params &= ~FORWARDED_PROTO;
|
params &= ~FORWARDED_PROTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,7 +375,7 @@ int Http2DownstreamConnection::push_request_headers() {
|
||||||
nva.push_back(http2::make_nv_ls_nocopy("x-forwarded-for", xff->value));
|
nva.push_back(http2::make_nv_ls_nocopy("x-forwarded-for", xff->value));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!get_config()->http2_proxy && req.method != HTTP_CONNECT) {
|
if (!get_config()->http2_proxy && req.method_token != HTTP_CONNECT) {
|
||||||
// We use same protocol with :scheme header field
|
// We use same protocol with :scheme header field
|
||||||
nva.push_back(http2::make_nv_ls_nocopy("x-forwarded-proto", req.scheme));
|
nva.push_back(http2::make_nv_ls_nocopy("x-forwarded-proto", req.scheme));
|
||||||
}
|
}
|
||||||
|
@ -428,7 +427,7 @@ int Http2DownstreamConnection::push_request_headers() {
|
||||||
|
|
||||||
// Add body as long as transfer-encoding is given even if
|
// Add body as long as transfer-encoding is given even if
|
||||||
// req.fs.content_length == 0 to forward trailer fields.
|
// req.fs.content_length == 0 to forward trailer fields.
|
||||||
if (req.method == HTTP_CONNECT || transfer_encoding ||
|
if (req.method_token == HTTP_CONNECT || transfer_encoding ||
|
||||||
req.fs.content_length > 0 || req.http2_expect_body) {
|
req.fs.content_length > 0 || req.http2_expect_body) {
|
||||||
// Request-body is expected.
|
// Request-body is expected.
|
||||||
nghttp2_data_provider data_prd{{}, http2_data_read_callback};
|
nghttp2_data_provider data_prd{{}, http2_data_read_callback};
|
||||||
|
|
|
@ -2055,13 +2055,6 @@ int Http2Session::handle_downstream_push_promise_complete(
|
||||||
}
|
}
|
||||||
|
|
||||||
auto method_token = http2::lookup_method_token(method->value);
|
auto method_token = http2::lookup_method_token(method->value);
|
||||||
if (method_token == -1) {
|
|
||||||
if (LOG_ENABLED(INFO)) {
|
|
||||||
SSLOG(INFO, this) << "Unrecognized method: " << method->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO Rewrite authority if we enabled rewrite host. But we
|
// TODO Rewrite authority if we enabled rewrite host. But we
|
||||||
// really don't know how to rewrite host. Should we use the same
|
// really don't know how to rewrite host. Should we use the same
|
||||||
|
@ -2069,7 +2062,8 @@ int Http2Session::handle_downstream_push_promise_complete(
|
||||||
if (authority) {
|
if (authority) {
|
||||||
promised_req.authority = authority->value;
|
promised_req.authority = authority->value;
|
||||||
}
|
}
|
||||||
promised_req.method = method_token;
|
promised_req.method = method->value;
|
||||||
|
promised_req.method_token = method_token;
|
||||||
// libnghttp2 ensures that we don't have CONNECT method in
|
// libnghttp2 ensures that we don't have CONNECT method in
|
||||||
// PUSH_PROMISE, and guarantees that :scheme exists.
|
// PUSH_PROMISE, and guarantees that :scheme exists.
|
||||||
if (scheme) {
|
if (scheme) {
|
||||||
|
|
|
@ -117,7 +117,7 @@ int Http2Upstream::upgrade_upstream(HttpsUpstream *http) {
|
||||||
rv = nghttp2_session_upgrade2(
|
rv = nghttp2_session_upgrade2(
|
||||||
session_, reinterpret_cast<const uint8_t *>(settings_payload.c_str()),
|
session_, reinterpret_cast<const uint8_t *>(settings_payload.c_str()),
|
||||||
settings_payload.size(),
|
settings_payload.size(),
|
||||||
http->get_downstream()->request().method == HTTP_HEAD, nullptr);
|
http->get_downstream()->request().method_token == HTTP_HEAD, nullptr);
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
if (LOG_ENABLED(INFO)) {
|
if (LOG_ENABLED(INFO)) {
|
||||||
ULOG(INFO, this) << "nghttp2_session_upgrade() returned error: "
|
ULOG(INFO, this) << "nghttp2_session_upgrade() returned error: "
|
||||||
|
@ -296,12 +296,6 @@ int Http2Upstream::on_request_headers(Downstream *downstream,
|
||||||
auto scheme = req.fs.header(http2::HD__SCHEME);
|
auto scheme = req.fs.header(http2::HD__SCHEME);
|
||||||
|
|
||||||
auto method_token = http2::lookup_method_token(method->value);
|
auto method_token = http2::lookup_method_token(method->value);
|
||||||
if (method_token == -1) {
|
|
||||||
if (error_reply(downstream, 501) != 0) {
|
|
||||||
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For HTTP/2 proxy, we request :authority.
|
// For HTTP/2 proxy, we request :authority.
|
||||||
if (method_token != HTTP_CONNECT && get_config()->http2_proxy && !authority) {
|
if (method_token != HTTP_CONNECT && get_config()->http2_proxy && !authority) {
|
||||||
|
@ -309,7 +303,8 @@ int Http2Upstream::on_request_headers(Downstream *downstream,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
req.method = method_token;
|
req.method = method->value;
|
||||||
|
req.method_token = method_token;
|
||||||
if (scheme) {
|
if (scheme) {
|
||||||
req.scheme = scheme->value;
|
req.scheme = scheme->value;
|
||||||
}
|
}
|
||||||
|
@ -604,9 +599,11 @@ int on_frame_send_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
||||||
|
|
||||||
auto token = http2::lookup_token(nv.name, nv.namelen);
|
auto token = http2::lookup_token(nv.name, nv.namelen);
|
||||||
switch (token) {
|
switch (token) {
|
||||||
case http2::HD__METHOD:
|
case http2::HD__METHOD: {
|
||||||
req.method = http2::lookup_method_token(value);
|
req.method = value;
|
||||||
|
req.method_token = http2::lookup_method_token(value);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case http2::HD__SCHEME:
|
case http2::HD__SCHEME:
|
||||||
req.scheme = value;
|
req.scheme = value;
|
||||||
break;
|
break;
|
||||||
|
@ -1415,7 +1412,7 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) {
|
||||||
!get_config()->http2_proxy && (downstream->get_stream_id() % 2) &&
|
!get_config()->http2_proxy && (downstream->get_stream_id() % 2) &&
|
||||||
resp.fs.header(http2::HD_LINK) &&
|
resp.fs.header(http2::HD_LINK) &&
|
||||||
(downstream->get_non_final_response() || resp.http_status == 200) &&
|
(downstream->get_non_final_response() || resp.http_status == 200) &&
|
||||||
(req.method == HTTP_GET || req.method == HTTP_POST)) {
|
(req.method_token == HTTP_GET || req.method_token == HTTP_POST)) {
|
||||||
|
|
||||||
if (prepare_push_promise(downstream) != 0) {
|
if (prepare_push_promise(downstream) != 0) {
|
||||||
// Continue to send response even if push was failed.
|
// Continue to send response even if push was failed.
|
||||||
|
|
|
@ -321,7 +321,7 @@ int HttpDownstreamConnection::push_request_headers() {
|
||||||
|
|
||||||
auto &balloc = downstream_->get_block_allocator();
|
auto &balloc = downstream_->get_block_allocator();
|
||||||
|
|
||||||
auto connect_method = req.method == HTTP_CONNECT;
|
auto connect_method = req.method_token == HTTP_CONNECT;
|
||||||
|
|
||||||
auto &httpconf = get_config()->http;
|
auto &httpconf = get_config()->http;
|
||||||
|
|
||||||
|
@ -340,8 +340,7 @@ int HttpDownstreamConnection::push_request_headers() {
|
||||||
auto buf = downstream_->get_request_buf();
|
auto buf = downstream_->get_request_buf();
|
||||||
|
|
||||||
// Assume that method and request path do not contain \r\n.
|
// Assume that method and request path do not contain \r\n.
|
||||||
auto meth = http2::to_method_string(req.method);
|
buf->append(req.method);
|
||||||
buf->append(meth);
|
|
||||||
buf->append(" ");
|
buf->append(" ");
|
||||||
|
|
||||||
if (connect_method) {
|
if (connect_method) {
|
||||||
|
@ -354,7 +353,7 @@ int HttpDownstreamConnection::push_request_headers() {
|
||||||
buf->append("://");
|
buf->append("://");
|
||||||
buf->append(authority);
|
buf->append(authority);
|
||||||
buf->append(req.path);
|
buf->append(req.path);
|
||||||
} else if (req.method == HTTP_OPTIONS && req.path.empty()) {
|
} else if (req.method_token == HTTP_OPTIONS && req.path.empty()) {
|
||||||
// Server-wide OPTIONS
|
// Server-wide OPTIONS
|
||||||
buf->append("*");
|
buf->append("*");
|
||||||
} else {
|
} else {
|
||||||
|
@ -708,7 +707,7 @@ int htp_hdrs_completecb(http_parser *htp) {
|
||||||
|
|
||||||
// TODO It seems that the cases other than HEAD are handled by
|
// TODO It seems that the cases other than HEAD are handled by
|
||||||
// http-parser. Need test.
|
// http-parser. Need test.
|
||||||
return !http2::expect_response_body(req.method, resp.http_status);
|
return !http2::expect_response_body(req.method_token, resp.http_status);
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,33 @@ int htp_msg_begin(http_parser *htp) {
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int htp_methodcb(http_parser *htp, const char *data, size_t len) {
|
||||||
|
auto upstream = static_cast<HttpsUpstream *>(htp->data);
|
||||||
|
auto downstream = upstream->get_downstream();
|
||||||
|
auto &req = downstream->request();
|
||||||
|
|
||||||
|
auto &balloc = downstream->get_block_allocator();
|
||||||
|
|
||||||
|
if (req.fs.buffer_size() + len >
|
||||||
|
get_config()->http.request_header_field_buffer) {
|
||||||
|
if (LOG_ENABLED(INFO)) {
|
||||||
|
ULOG(INFO, upstream) << "Too large request size="
|
||||||
|
<< req.fs.buffer_size() + len;
|
||||||
|
}
|
||||||
|
assert(downstream->get_request_state() == Downstream::INITIAL);
|
||||||
|
downstream->set_request_state(Downstream::HTTP1_REQUEST_HEADER_TOO_LARGE);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
req.fs.add_extra_buffer_size(len);
|
||||||
|
|
||||||
|
req.method = concat_string_ref(balloc, req.method, StringRef{data, len});
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
int htp_uricb(http_parser *htp, const char *data, size_t len) {
|
int htp_uricb(http_parser *htp, const char *data, size_t len) {
|
||||||
auto upstream = static_cast<HttpsUpstream *>(htp->data);
|
auto upstream = static_cast<HttpsUpstream *>(htp->data);
|
||||||
|
@ -88,8 +115,11 @@ int htp_uricb(http_parser *htp, const char *data, size_t len) {
|
||||||
|
|
||||||
auto &balloc = downstream->get_block_allocator();
|
auto &balloc = downstream->get_block_allocator();
|
||||||
|
|
||||||
// We happen to have the same value for method token.
|
// This could be executed more than once, but no harm here.
|
||||||
req.method = htp->method;
|
if (htp->method != HTTP_METHOD_UNKNOWN) {
|
||||||
|
// We happen to have the same value for method token.
|
||||||
|
req.method_token = htp->method;
|
||||||
|
}
|
||||||
|
|
||||||
if (req.fs.buffer_size() + len >
|
if (req.fs.buffer_size() + len >
|
||||||
get_config()->http.request_header_field_buffer) {
|
get_config()->http.request_header_field_buffer) {
|
||||||
|
@ -104,7 +134,7 @@ int htp_uricb(http_parser *htp, const char *data, size_t len) {
|
||||||
|
|
||||||
req.fs.add_extra_buffer_size(len);
|
req.fs.add_extra_buffer_size(len);
|
||||||
|
|
||||||
if (req.method == HTTP_CONNECT) {
|
if (req.method_token == HTTP_CONNECT) {
|
||||||
req.authority =
|
req.authority =
|
||||||
concat_string_ref(balloc, req.authority, StringRef{data, len});
|
concat_string_ref(balloc, req.authority, StringRef{data, len});
|
||||||
} else {
|
} else {
|
||||||
|
@ -243,7 +273,7 @@ void rewrite_request_host_path_from_uri(BlockAllocator &balloc, Request &req,
|
||||||
StringRef path;
|
StringRef path;
|
||||||
if (u.field_set & (1 << UF_PATH)) {
|
if (u.field_set & (1 << UF_PATH)) {
|
||||||
path = util::get_uri_field(uri.c_str(), u, UF_PATH);
|
path = util::get_uri_field(uri.c_str(), u, UF_PATH);
|
||||||
} else if (req.method == HTTP_OPTIONS) {
|
} else if (req.method_token == HTTP_OPTIONS) {
|
||||||
// Server-wide OPTIONS takes following form in proxy request:
|
// Server-wide OPTIONS takes following form in proxy request:
|
||||||
//
|
//
|
||||||
// OPTIONS http://example.org HTTP/1.1
|
// OPTIONS http://example.org HTTP/1.1
|
||||||
|
@ -297,13 +327,11 @@ int htp_hdrs_completecb(http_parser *htp) {
|
||||||
|
|
||||||
req.connection_close = !http_should_keep_alive(htp);
|
req.connection_close = !http_should_keep_alive(htp);
|
||||||
|
|
||||||
auto method = req.method;
|
|
||||||
|
|
||||||
if (LOG_ENABLED(INFO)) {
|
if (LOG_ENABLED(INFO)) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << http2::to_method_string(method) << " "
|
ss << req.method << " "
|
||||||
<< (method == HTTP_CONNECT ? req.authority : req.path) << " "
|
<< (req.method_token == HTTP_CONNECT ? req.authority : req.path)
|
||||||
<< "HTTP/" << req.http_major << "." << req.http_minor << "\n";
|
<< " HTTP/" << req.http_major << "." << req.http_minor << "\n";
|
||||||
|
|
||||||
for (const auto &kv : req.fs.headers()) {
|
for (const auto &kv : req.fs.headers()) {
|
||||||
ss << TTY_HTTP_HD << kv.name << TTY_RST << ": " << kv.value << "\n";
|
ss << TTY_HTTP_HD << kv.name << TTY_RST << ": " << kv.value << "\n";
|
||||||
|
@ -340,7 +368,7 @@ int htp_hdrs_completecb(http_parser *htp) {
|
||||||
|
|
||||||
auto &balloc = downstream->get_block_allocator();
|
auto &balloc = downstream->get_block_allocator();
|
||||||
|
|
||||||
if (method != HTTP_CONNECT) {
|
if (req.method_token != HTTP_CONNECT) {
|
||||||
http_parser_url u{};
|
http_parser_url u{};
|
||||||
rv = http_parser_parse_url(req.path.c_str(), req.path.size(), 0, &u);
|
rv = http_parser_parse_url(req.path.c_str(), req.path.size(), 0, &u);
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
|
@ -356,7 +384,8 @@ int htp_hdrs_completecb(http_parser *htp) {
|
||||||
|
|
||||||
req.no_authority = true;
|
req.no_authority = true;
|
||||||
|
|
||||||
if (method == HTTP_OPTIONS && req.path == StringRef::from_lit("*")) {
|
if (req.method_token == HTTP_OPTIONS &&
|
||||||
|
req.path == StringRef::from_lit("*")) {
|
||||||
req.path = StringRef{};
|
req.path = StringRef{};
|
||||||
} else {
|
} else {
|
||||||
req.path = http2::rewrite_clean_path(balloc, req.path);
|
req.path = http2::rewrite_clean_path(balloc, req.path);
|
||||||
|
@ -482,7 +511,10 @@ http_parser_settings htp_hooks = {
|
||||||
htp_hdr_valcb, // http_data_cb on_header_value;
|
htp_hdr_valcb, // http_data_cb on_header_value;
|
||||||
htp_hdrs_completecb, // http_cb on_headers_complete;
|
htp_hdrs_completecb, // http_cb on_headers_complete;
|
||||||
htp_bodycb, // http_data_cb on_body;
|
htp_bodycb, // http_data_cb on_body;
|
||||||
htp_msg_completecb // http_cb on_message_complete;
|
htp_msg_completecb, // http_cb on_message_complete;
|
||||||
|
nullptr, // http_cb on_chunk_header;
|
||||||
|
nullptr, // http_cb on_chunk_complete;
|
||||||
|
htp_methodcb, // http_data_cb on_method;
|
||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
@ -973,7 +1005,7 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
|
||||||
}
|
}
|
||||||
#endif // HAVE_MRUBY
|
#endif // HAVE_MRUBY
|
||||||
|
|
||||||
auto connect_method = req.method == HTTP_CONNECT;
|
auto connect_method = req.method_token == HTTP_CONNECT;
|
||||||
|
|
||||||
auto buf = downstream->get_response_buf();
|
auto buf = downstream->get_response_buf();
|
||||||
|
|
||||||
|
|
|
@ -68,9 +68,8 @@ mrb_value request_get_method(mrb_state *mrb, mrb_value self) {
|
||||||
auto data = static_cast<MRubyAssocData *>(mrb->ud);
|
auto data = static_cast<MRubyAssocData *>(mrb->ud);
|
||||||
auto downstream = data->downstream;
|
auto downstream = data->downstream;
|
||||||
const auto &req = downstream->request();
|
const auto &req = downstream->request();
|
||||||
auto method = http2::to_method_string(req.method);
|
|
||||||
|
|
||||||
return mrb_str_new(mrb, method.c_str(), method.size());
|
return mrb_str_new(mrb, req.method.c_str(), req.method.size());
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
@ -80,6 +79,8 @@ mrb_value request_set_method(mrb_state *mrb, mrb_value self) {
|
||||||
auto downstream = data->downstream;
|
auto downstream = data->downstream;
|
||||||
auto &req = downstream->request();
|
auto &req = downstream->request();
|
||||||
|
|
||||||
|
auto &balloc = downstream->get_block_allocator();
|
||||||
|
|
||||||
check_phase(mrb, data->phase, PHASE_REQUEST);
|
check_phase(mrb, data->phase, PHASE_REQUEST);
|
||||||
|
|
||||||
const char *method;
|
const char *method;
|
||||||
|
@ -88,13 +89,13 @@ mrb_value request_set_method(mrb_state *mrb, mrb_value self) {
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
mrb_raise(mrb, E_RUNTIME_ERROR, "method must not be empty string");
|
mrb_raise(mrb, E_RUNTIME_ERROR, "method must not be empty string");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto token =
|
auto token =
|
||||||
http2::lookup_method_token(reinterpret_cast<const uint8_t *>(method), n);
|
http2::lookup_method_token(reinterpret_cast<const uint8_t *>(method), n);
|
||||||
if (token == -1) {
|
|
||||||
mrb_raise(mrb, E_RUNTIME_ERROR, "method not supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
req.method = token;
|
req.method =
|
||||||
|
make_string_ref(balloc, StringRef{method, static_cast<size_t>(n)});
|
||||||
|
req.method_token = token;
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
|
@ -220,12 +220,6 @@ void on_ctrl_recv_callback(spdylay_session *session, spdylay_frame_type type,
|
||||||
}
|
}
|
||||||
|
|
||||||
auto method_token = http2::lookup_method_token(method->value);
|
auto method_token = http2::lookup_method_token(method->value);
|
||||||
if (method_token == -1) {
|
|
||||||
if (upstream->error_reply(downstream, 501) != 0) {
|
|
||||||
ULOG(FATAL, upstream) << "error_reply failed";
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto is_connect = method_token == HTTP_CONNECT;
|
auto is_connect = method_token == HTTP_CONNECT;
|
||||||
if (!path || !host || !http2::non_empty_value(host) ||
|
if (!path || !host || !http2::non_empty_value(host) ||
|
||||||
|
@ -264,7 +258,8 @@ void on_ctrl_recv_callback(spdylay_session *session, spdylay_frame_type type,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
req.method = method_token;
|
req.method = method->value;
|
||||||
|
req.method_token = method_token;
|
||||||
if (is_connect) {
|
if (is_connect) {
|
||||||
req.authority = path->value;
|
req.authority = path->value;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -28,6 +28,7 @@ EXTRA_DIST = CMakeLists.txt
|
||||||
if ENABLE_THIRD_PARTY
|
if ENABLE_THIRD_PARTY
|
||||||
|
|
||||||
noinst_LTLIBRARIES = libhttp-parser.la
|
noinst_LTLIBRARIES = libhttp-parser.la
|
||||||
|
libhttp_parser_la_CPPFLAGS = ${AMCPPFLAGS} -DHTTP_PARSER_METHOD_CB=1
|
||||||
libhttp_parser_la_SOURCES = \
|
libhttp_parser_la_SOURCES = \
|
||||||
http-parser/http_parser.c \
|
http-parser/http_parser.c \
|
||||||
http-parser/http_parser.h
|
http-parser/http_parser.h
|
||||||
|
|
|
@ -280,6 +280,7 @@ enum state
|
||||||
{ s_dead = 1 /* important that this is > 0 */
|
{ s_dead = 1 /* important that this is > 0 */
|
||||||
|
|
||||||
, s_start_req_or_res
|
, s_start_req_or_res
|
||||||
|
, s_res_or_resp_mark_H
|
||||||
, s_res_or_resp_H
|
, s_res_or_resp_H
|
||||||
, s_start_res
|
, s_start_res
|
||||||
, s_res_H
|
, s_res_H
|
||||||
|
@ -298,7 +299,11 @@ enum state
|
||||||
|
|
||||||
, s_start_req
|
, s_start_req
|
||||||
|
|
||||||
|
, s_req_method_start
|
||||||
, s_req_method
|
, s_req_method
|
||||||
|
#if HTTP_PARSER_METHOD_CB
|
||||||
|
, s_req_method_unknown
|
||||||
|
#endif
|
||||||
, s_req_spaces_before_url
|
, s_req_spaces_before_url
|
||||||
, s_req_schema
|
, s_req_schema
|
||||||
, s_req_schema_slash
|
, s_req_schema_slash
|
||||||
|
@ -644,6 +649,9 @@ size_t http_parser_execute (http_parser *parser,
|
||||||
const char *url_mark = 0;
|
const char *url_mark = 0;
|
||||||
const char *body_mark = 0;
|
const char *body_mark = 0;
|
||||||
const char *status_mark = 0;
|
const char *status_mark = 0;
|
||||||
|
#if HTTP_PARSER_METHOD_CB
|
||||||
|
const char *method_mark = 0;
|
||||||
|
#endif
|
||||||
enum state p_state = (enum state) parser->state;
|
enum state p_state = (enum state) parser->state;
|
||||||
const unsigned int lenient = parser->lenient_http_headers;
|
const unsigned int lenient = parser->lenient_http_headers;
|
||||||
|
|
||||||
|
@ -692,6 +700,14 @@ size_t http_parser_execute (http_parser *parser,
|
||||||
case s_req_fragment:
|
case s_req_fragment:
|
||||||
url_mark = data;
|
url_mark = data;
|
||||||
break;
|
break;
|
||||||
|
#if HTTP_PARSER_METHOD_CB
|
||||||
|
case s_res_or_resp_H:
|
||||||
|
case s_req_method_start:
|
||||||
|
case s_req_method:
|
||||||
|
case s_req_method_unknown:
|
||||||
|
method_mark = data;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
case s_res_status:
|
case s_res_status:
|
||||||
status_mark = data;
|
status_mark = data;
|
||||||
break;
|
break;
|
||||||
|
@ -726,9 +742,10 @@ reexecute:
|
||||||
parser->content_length = ULLONG_MAX;
|
parser->content_length = ULLONG_MAX;
|
||||||
|
|
||||||
if (ch == 'H') {
|
if (ch == 'H') {
|
||||||
UPDATE_STATE(s_res_or_resp_H);
|
UPDATE_STATE(s_res_or_resp_mark_H);
|
||||||
|
|
||||||
CALLBACK_NOTIFY(message_begin);
|
CALLBACK_NOTIFY_NOADVANCE(message_begin);
|
||||||
|
REEXECUTE();
|
||||||
} else {
|
} else {
|
||||||
parser->type = HTTP_REQUEST;
|
parser->type = HTTP_REQUEST;
|
||||||
UPDATE_STATE(s_start_req);
|
UPDATE_STATE(s_start_req);
|
||||||
|
@ -738,19 +755,46 @@ reexecute:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case s_res_or_resp_mark_H:
|
||||||
|
assert(ch == 'H');
|
||||||
|
UPDATE_STATE(s_res_or_resp_H);
|
||||||
|
#if HTTP_PARSER_METHOD_CB
|
||||||
|
/* TODO This will call on_method even if type == HTTP_BOTH is
|
||||||
|
* used and it later turns out that this is response.
|
||||||
|
* Automatic handling bites us hard.
|
||||||
|
*/
|
||||||
|
MARK(method);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
|
||||||
case s_res_or_resp_H:
|
case s_res_or_resp_H:
|
||||||
if (ch == 'T') {
|
if (ch == 'T') {
|
||||||
parser->type = HTTP_RESPONSE;
|
parser->type = HTTP_RESPONSE;
|
||||||
UPDATE_STATE(s_res_HT);
|
UPDATE_STATE(s_res_HT);
|
||||||
} else {
|
} else {
|
||||||
|
#if HTTP_PARSER_METHOD_CB
|
||||||
|
if (UNLIKELY(!TOKEN(ch))) {
|
||||||
|
SET_ERRNO(HPE_INVALID_CONSTANT);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UNLIKELY(ch != 'E')) {
|
||||||
|
parser->method = HTTP_METHOD_UNKNOWN;
|
||||||
|
} else {
|
||||||
|
parser->method = HTTP_HEAD;
|
||||||
|
parser->index = 2;
|
||||||
|
}
|
||||||
|
#else
|
||||||
if (UNLIKELY(ch != 'E')) {
|
if (UNLIKELY(ch != 'E')) {
|
||||||
SET_ERRNO(HPE_INVALID_CONSTANT);
|
SET_ERRNO(HPE_INVALID_CONSTANT);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
parser->type = HTTP_REQUEST;
|
|
||||||
parser->method = HTTP_HEAD;
|
parser->method = HTTP_HEAD;
|
||||||
parser->index = 2;
|
parser->index = 2;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
parser->type = HTTP_REQUEST;
|
||||||
UPDATE_STATE(s_req_method);
|
UPDATE_STATE(s_req_method);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -952,7 +996,6 @@ reexecute:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case s_start_req:
|
case s_start_req:
|
||||||
{
|
|
||||||
if (ch == CR || ch == LF)
|
if (ch == CR || ch == LF)
|
||||||
break;
|
break;
|
||||||
parser->flags = 0;
|
parser->flags = 0;
|
||||||
|
@ -963,6 +1006,25 @@ reexecute:
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UPDATE_STATE(s_req_method_start);
|
||||||
|
#if HTTP_PARSER_METHOD_CB
|
||||||
|
MARK(method);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CALLBACK_NOTIFY_NOADVANCE(message_begin);
|
||||||
|
REEXECUTE();
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case s_req_method_start:
|
||||||
|
{
|
||||||
|
enum state next_state = s_req_method;
|
||||||
|
|
||||||
|
if (UNLIKELY(!IS_ALPHA(ch))) {
|
||||||
|
SET_ERRNO(HPE_INVALID_METHOD);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
parser->method = (enum http_method) 0;
|
parser->method = (enum http_method) 0;
|
||||||
parser->index = 1;
|
parser->index = 1;
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
|
@ -984,12 +1046,26 @@ reexecute:
|
||||||
case 'T': parser->method = HTTP_TRACE; break;
|
case 'T': parser->method = HTTP_TRACE; break;
|
||||||
case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE, UNBIND, UNLINK */ break;
|
case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE, UNBIND, UNLINK */ break;
|
||||||
default:
|
default:
|
||||||
|
#if HTTP_PARSER_METHOD_CB
|
||||||
|
if (UNLIKELY(!TOKEN(ch))) {
|
||||||
|
SET_ERRNO(HPE_INVALID_METHOD);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
parser->method = (unsigned int) HTTP_METHOD_UNKNOWN;
|
||||||
|
|
||||||
|
next_state = s_req_method_unknown;
|
||||||
|
#else
|
||||||
SET_ERRNO(HPE_INVALID_METHOD);
|
SET_ERRNO(HPE_INVALID_METHOD);
|
||||||
goto error;
|
goto error;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
UPDATE_STATE(s_req_method);
|
|
||||||
|
|
||||||
CALLBACK_NOTIFY(message_begin);
|
UPDATE_STATE(next_state);
|
||||||
|
|
||||||
|
#if HTTP_PARSER_METHOD_CB
|
||||||
|
MARK(method);
|
||||||
|
#endif
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1003,8 +1079,21 @@ reexecute:
|
||||||
}
|
}
|
||||||
|
|
||||||
matcher = method_strings[parser->method];
|
matcher = method_strings[parser->method];
|
||||||
if (ch == ' ' && matcher[parser->index] == '\0') {
|
|
||||||
|
if (ch == ' ') {
|
||||||
|
if (matcher[parser->index] != '\0') {
|
||||||
|
#if HTTP_PARSER_METHOD_CB
|
||||||
|
parser->method = (unsigned int) HTTP_METHOD_UNKNOWN;
|
||||||
|
#else
|
||||||
|
SET_ERRNO(HPE_INVALID_METHOD);
|
||||||
|
goto error;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
UPDATE_STATE(s_req_spaces_before_url);
|
UPDATE_STATE(s_req_spaces_before_url);
|
||||||
|
#if HTTP_PARSER_METHOD_CB
|
||||||
|
CALLBACK_DATA(method);
|
||||||
|
#endif
|
||||||
} else if (ch == matcher[parser->index]) {
|
} else if (ch == matcher[parser->index]) {
|
||||||
; /* nada */
|
; /* nada */
|
||||||
} else if (IS_ALPHA(ch)) {
|
} else if (IS_ALPHA(ch)) {
|
||||||
|
@ -1034,14 +1123,56 @@ reexecute:
|
||||||
#undef XX
|
#undef XX
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
#if HTTP_PARSER_METHOD_CB
|
||||||
|
if (UNLIKELY(!TOKEN(ch))) {
|
||||||
|
SET_ERRNO(HPE_INVALID_METHOD);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
parser->method = (unsigned int) HTTP_METHOD_UNKNOWN;
|
||||||
|
|
||||||
|
UPDATE_STATE(s_req_method_unknown);
|
||||||
|
#else
|
||||||
SET_ERRNO(HPE_INVALID_METHOD);
|
SET_ERRNO(HPE_INVALID_METHOD);
|
||||||
goto error;
|
goto error;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
} else if (ch == '-' &&
|
} else if (ch == '-' &&
|
||||||
parser->index == 1 &&
|
parser->index == 1 &&
|
||||||
parser->method == HTTP_MKCOL) {
|
parser->method == HTTP_MKCOL) {
|
||||||
parser->method = HTTP_MSEARCH;
|
parser->method = HTTP_MSEARCH;
|
||||||
} else {
|
} else {
|
||||||
|
#if HTTP_PARSER_METHOD_CB
|
||||||
|
if (UNLIKELY(!TOKEN(ch))) {
|
||||||
|
SET_ERRNO(HPE_INVALID_METHOD);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
parser->method = (unsigned int) HTTP_METHOD_UNKNOWN;
|
||||||
|
|
||||||
|
UPDATE_STATE(s_req_method_unknown);
|
||||||
|
#else
|
||||||
|
SET_ERRNO(HPE_INVALID_METHOD);
|
||||||
|
goto error;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
++parser->index;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HTTP_PARSER_METHOD_CB
|
||||||
|
case s_req_method_unknown:
|
||||||
|
{
|
||||||
|
if (UNLIKELY(ch == '\0')) {
|
||||||
|
SET_ERRNO(HPE_INVALID_METHOD);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch == ' ') {
|
||||||
|
UPDATE_STATE(s_req_spaces_before_url);
|
||||||
|
CALLBACK_DATA(method);
|
||||||
|
} else if (UNLIKELY(!TOKEN(ch))) {
|
||||||
SET_ERRNO(HPE_INVALID_METHOD);
|
SET_ERRNO(HPE_INVALID_METHOD);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -1049,6 +1180,7 @@ reexecute:
|
||||||
++parser->index;
|
++parser->index;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
case s_req_spaces_before_url:
|
case s_req_spaces_before_url:
|
||||||
{
|
{
|
||||||
|
@ -2078,6 +2210,9 @@ reexecute:
|
||||||
CALLBACK_DATA_NOADVANCE(url);
|
CALLBACK_DATA_NOADVANCE(url);
|
||||||
CALLBACK_DATA_NOADVANCE(body);
|
CALLBACK_DATA_NOADVANCE(body);
|
||||||
CALLBACK_DATA_NOADVANCE(status);
|
CALLBACK_DATA_NOADVANCE(status);
|
||||||
|
#if HTTP_PARSER_METHOD_CB
|
||||||
|
CALLBACK_DATA_NOADVANCE(method);
|
||||||
|
#endif
|
||||||
|
|
||||||
RETURN(len);
|
RETURN(len);
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,17 @@ typedef unsigned __int64 uint64_t;
|
||||||
# define HTTP_PARSER_STRICT 1
|
# define HTTP_PARSER_STRICT 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Compile with -DHTTP_PARSER_METHOD_CB=1 to enable method
|
||||||
|
* callback. If it is enabled, method string is notified with
|
||||||
|
* on_method callback. The unknown method which would be rejeted
|
||||||
|
* previously is also accepted and notified with the on_method
|
||||||
|
* callback. The method field of http_parser struct becomes
|
||||||
|
* HTTP_METHOD_UNKNOWN if method is unknown to http_parser.
|
||||||
|
*/
|
||||||
|
#ifndef HTTP_PARSER_METHOD_CB
|
||||||
|
# define HTTP_PARSER_METHOD_CB 0
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Maximium header size allowed. If the macro is not defined
|
/* Maximium header size allowed. If the macro is not defined
|
||||||
* before including this header then the default is used. To
|
* before including this header then the default is used. To
|
||||||
* change the maximum header size, define the macro in the build
|
* change the maximum header size, define the macro in the build
|
||||||
|
@ -140,6 +151,8 @@ enum http_method
|
||||||
#undef XX
|
#undef XX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Unknown HTTP method */
|
||||||
|
#define HTTP_METHOD_UNKNOWN 255
|
||||||
|
|
||||||
enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH };
|
enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH };
|
||||||
|
|
||||||
|
@ -176,6 +189,7 @@ enum flags
|
||||||
XX(CB_status, "the on_status callback failed") \
|
XX(CB_status, "the on_status callback failed") \
|
||||||
XX(CB_chunk_header, "the on_chunk_header callback failed") \
|
XX(CB_chunk_header, "the on_chunk_header callback failed") \
|
||||||
XX(CB_chunk_complete, "the on_chunk_complete callback failed") \
|
XX(CB_chunk_complete, "the on_chunk_complete callback failed") \
|
||||||
|
XX(CB_method, "the on_method callback failed") \
|
||||||
\
|
\
|
||||||
/* Parsing-related errors */ \
|
/* Parsing-related errors */ \
|
||||||
XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
|
XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
|
||||||
|
@ -218,7 +232,6 @@ enum http_errno {
|
||||||
/* Get an http_errno value from an http_parser */
|
/* Get an http_errno value from an http_parser */
|
||||||
#define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno)
|
#define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno)
|
||||||
|
|
||||||
|
|
||||||
struct http_parser {
|
struct http_parser {
|
||||||
/** PRIVATE **/
|
/** PRIVATE **/
|
||||||
unsigned int type : 2; /* enum http_parser_type */
|
unsigned int type : 2; /* enum http_parser_type */
|
||||||
|
@ -264,6 +277,7 @@ struct http_parser_settings {
|
||||||
*/
|
*/
|
||||||
http_cb on_chunk_header;
|
http_cb on_chunk_header;
|
||||||
http_cb on_chunk_complete;
|
http_cb on_chunk_complete;
|
||||||
|
http_data_cb on_method;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,7 @@ struct message {
|
||||||
enum http_method method;
|
enum http_method method;
|
||||||
int status_code;
|
int status_code;
|
||||||
char response_status[MAX_ELEMENT_SIZE];
|
char response_status[MAX_ELEMENT_SIZE];
|
||||||
|
char request_method[MAX_ELEMENT_SIZE];
|
||||||
char request_path[MAX_ELEMENT_SIZE];
|
char request_path[MAX_ELEMENT_SIZE];
|
||||||
char request_url[MAX_ELEMENT_SIZE];
|
char request_url[MAX_ELEMENT_SIZE];
|
||||||
char fragment[MAX_ELEMENT_SIZE];
|
char fragment[MAX_ELEMENT_SIZE];
|
||||||
|
@ -103,6 +104,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_GET
|
,.method= HTTP_GET
|
||||||
|
,.request_method = "GET"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= "/test"
|
,.request_path= "/test"
|
||||||
|
@ -134,6 +136,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_GET
|
,.method= HTTP_GET
|
||||||
|
,.request_method = "GET"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= "/favicon.ico"
|
,.request_path= "/favicon.ico"
|
||||||
|
@ -163,6 +166,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_GET
|
,.method= HTTP_GET
|
||||||
|
,.request_method = "GET"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= "/dumbfuck"
|
,.request_path= "/dumbfuck"
|
||||||
|
@ -184,6 +188,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_GET
|
,.method= HTTP_GET
|
||||||
|
,.request_method = "GET"
|
||||||
,.query_string= "page=1"
|
,.query_string= "page=1"
|
||||||
,.fragment= "posts-17408"
|
,.fragment= "posts-17408"
|
||||||
,.request_path= "/forums/1/topics/2375"
|
,.request_path= "/forums/1/topics/2375"
|
||||||
|
@ -203,6 +208,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_GET
|
,.method= HTTP_GET
|
||||||
|
,.request_method = "GET"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= "/get_no_headers_no_body/world"
|
,.request_path= "/get_no_headers_no_body/world"
|
||||||
|
@ -222,6 +228,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_GET
|
,.method= HTTP_GET
|
||||||
|
,.request_method = "GET"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= "/get_one_header_no_body"
|
,.request_path= "/get_one_header_no_body"
|
||||||
|
@ -245,6 +252,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 0
|
,.http_minor= 0
|
||||||
,.method= HTTP_GET
|
,.method= HTTP_GET
|
||||||
|
,.request_method = "GET"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= "/get_funky_content_length_body_hello"
|
,.request_path= "/get_funky_content_length_body_hello"
|
||||||
|
@ -270,6 +278,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_POST
|
,.method= HTTP_POST
|
||||||
|
,.request_method = "POST"
|
||||||
,.query_string= "q=search"
|
,.query_string= "q=search"
|
||||||
,.fragment= "hey"
|
,.fragment= "hey"
|
||||||
,.request_path= "/post_identity_body_world"
|
,.request_path= "/post_identity_body_world"
|
||||||
|
@ -297,6 +306,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_POST
|
,.method= HTTP_POST
|
||||||
|
,.request_method = "POST"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= "/post_chunked_all_your_base"
|
,.request_path= "/post_chunked_all_your_base"
|
||||||
|
@ -325,6 +335,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_POST
|
,.method= HTTP_POST
|
||||||
|
,.request_method = "POST"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= "/two_chunks_mult_zero_end"
|
,.request_path= "/two_chunks_mult_zero_end"
|
||||||
|
@ -355,6 +366,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_POST
|
,.method= HTTP_POST
|
||||||
|
,.request_method = "POST"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= "/chunked_w_trailing_headers"
|
,.request_path= "/chunked_w_trailing_headers"
|
||||||
|
@ -385,6 +397,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_POST
|
,.method= HTTP_POST
|
||||||
|
,.request_method = "POST"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= "/chunked_w_bullshit_after_length"
|
,.request_path= "/chunked_w_bullshit_after_length"
|
||||||
|
@ -407,6 +420,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_GET
|
,.method= HTTP_GET
|
||||||
|
,.request_method = "GET"
|
||||||
,.query_string= "foo=\"bar\""
|
,.query_string= "foo=\"bar\""
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= "/with_\"stupid\"_quotes"
|
,.request_path= "/with_\"stupid\"_quotes"
|
||||||
|
@ -433,6 +447,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 0
|
,.http_minor= 0
|
||||||
,.method= HTTP_GET
|
,.method= HTTP_GET
|
||||||
|
,.request_method = "GET"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= "/test"
|
,.request_path= "/test"
|
||||||
|
@ -456,6 +471,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_GET
|
,.method= HTTP_GET
|
||||||
|
,.request_method = "GET"
|
||||||
,.query_string= "foo=bar?baz"
|
,.query_string= "foo=bar?baz"
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= "/test.cgi"
|
,.request_path= "/test.cgi"
|
||||||
|
@ -477,6 +493,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_GET
|
,.method= HTTP_GET
|
||||||
|
,.request_method = "GET"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= "/test"
|
,.request_path= "/test"
|
||||||
|
@ -504,6 +521,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_GET
|
,.method= HTTP_GET
|
||||||
|
,.request_method = "GET"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= "/demo"
|
,.request_path= "/demo"
|
||||||
|
@ -535,6 +553,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 0
|
,.http_minor= 0
|
||||||
,.method= HTTP_CONNECT
|
,.method= HTTP_CONNECT
|
||||||
|
,.request_method = "CONNECT"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= ""
|
,.request_path= ""
|
||||||
|
@ -557,6 +576,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_REPORT
|
,.method= HTTP_REPORT
|
||||||
|
,.request_method = "REPORT"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= "/test"
|
,.request_path= "/test"
|
||||||
|
@ -576,6 +596,7 @@ const struct message requests[] =
|
||||||
,.http_major= 0
|
,.http_major= 0
|
||||||
,.http_minor= 9
|
,.http_minor= 9
|
||||||
,.method= HTTP_GET
|
,.method= HTTP_GET
|
||||||
|
,.request_method = "GET"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= "/"
|
,.request_path= "/"
|
||||||
|
@ -598,6 +619,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_MSEARCH
|
,.method= HTTP_MSEARCH
|
||||||
|
,.request_method = "M-SEARCH"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= "*"
|
,.request_path= "*"
|
||||||
|
@ -633,6 +655,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_GET
|
,.method= HTTP_GET
|
||||||
|
,.request_method = "GET"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= "/"
|
,.request_path= "/"
|
||||||
|
@ -658,6 +681,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_GET
|
,.method= HTTP_GET
|
||||||
|
,.request_method = "GET"
|
||||||
,.query_string= "hail=all"
|
,.query_string= "hail=all"
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= ""
|
,.request_path= ""
|
||||||
|
@ -678,6 +702,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_GET
|
,.method= HTTP_GET
|
||||||
|
,.request_method = "GET"
|
||||||
,.query_string= "hail=all"
|
,.query_string= "hail=all"
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= ""
|
,.request_path= ""
|
||||||
|
@ -699,6 +724,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_GET
|
,.method= HTTP_GET
|
||||||
|
,.request_method = "GET"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= ""
|
,.request_path= ""
|
||||||
|
@ -725,6 +751,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_PATCH
|
,.method= HTTP_PATCH
|
||||||
|
,.request_method = "PATCH"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= "/file.txt"
|
,.request_path= "/file.txt"
|
||||||
|
@ -750,6 +777,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 0
|
,.http_minor= 0
|
||||||
,.method= HTTP_CONNECT
|
,.method= HTTP_CONNECT
|
||||||
|
,.request_method = "CONNECT"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= ""
|
,.request_path= ""
|
||||||
|
@ -774,6 +802,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_GET
|
,.method= HTTP_GET
|
||||||
|
,.request_method = "GET"
|
||||||
,.query_string= "q=1"
|
,.query_string= "q=1"
|
||||||
,.fragment= "narf"
|
,.fragment= "narf"
|
||||||
,.request_path= "/δ¶/δt/pope"
|
,.request_path= "/δ¶/δt/pope"
|
||||||
|
@ -796,6 +825,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 0
|
,.http_minor= 0
|
||||||
,.method= HTTP_CONNECT
|
,.method= HTTP_CONNECT
|
||||||
|
,.request_method = "CONNECT"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= ""
|
,.request_path= ""
|
||||||
|
@ -823,6 +853,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_POST
|
,.method= HTTP_POST
|
||||||
|
,.request_method = "POST"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= "/"
|
,.request_path= "/"
|
||||||
|
@ -851,6 +882,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_POST
|
,.method= HTTP_POST
|
||||||
|
,.request_method = "POST"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= "/"
|
,.request_path= "/"
|
||||||
|
@ -876,6 +908,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_PURGE
|
,.method= HTTP_PURGE
|
||||||
|
,.request_method = "PURGE"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= "/file.txt"
|
,.request_path= "/file.txt"
|
||||||
|
@ -896,6 +929,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_SEARCH
|
,.method= HTTP_SEARCH
|
||||||
|
,.request_method = "SEARCH"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= "/"
|
,.request_path= "/"
|
||||||
|
@ -915,6 +949,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_GET
|
,.method= HTTP_GET
|
||||||
|
,.request_method = "GET"
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= "/toto"
|
,.request_path= "/toto"
|
||||||
,.request_url= "http://a%12:b!&*$@hypnotoad.org:1234/toto"
|
,.request_url= "http://a%12:b!&*$@hypnotoad.org:1234/toto"
|
||||||
|
@ -949,6 +984,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_GET
|
,.method= HTTP_GET
|
||||||
|
,.request_method = "GET"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= "/"
|
,.request_path= "/"
|
||||||
|
@ -982,6 +1018,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_GET
|
,.method= HTTP_GET
|
||||||
|
,.request_method = "GET"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= "/demo"
|
,.request_path= "/demo"
|
||||||
|
@ -1012,6 +1049,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_GET
|
,.method= HTTP_GET
|
||||||
|
,.request_method = "GET"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= "/demo"
|
,.request_path= "/demo"
|
||||||
|
@ -1037,6 +1075,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_GET
|
,.method= HTTP_GET
|
||||||
|
,.request_method = "GET"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= "/demo"
|
,.request_path= "/demo"
|
||||||
|
@ -1065,6 +1104,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_POST
|
,.method= HTTP_POST
|
||||||
|
,.request_method = "POST"
|
||||||
,.request_path= "/demo"
|
,.request_path= "/demo"
|
||||||
,.request_url= "/demo"
|
,.request_url= "/demo"
|
||||||
,.num_headers= 4
|
,.num_headers= 4
|
||||||
|
@ -1091,6 +1131,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 0
|
,.http_minor= 0
|
||||||
,.method= HTTP_CONNECT
|
,.method= HTTP_CONNECT
|
||||||
|
,.request_method = "CONNECT"
|
||||||
,.request_url= "foo.bar.com:443"
|
,.request_url= "foo.bar.com:443"
|
||||||
,.num_headers= 3
|
,.num_headers= 3
|
||||||
,.upgrade="blarfcicle"
|
,.upgrade="blarfcicle"
|
||||||
|
@ -1118,6 +1159,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_LINK
|
,.method= HTTP_LINK
|
||||||
|
,.request_method = "LINK"
|
||||||
,.request_path= "/images/my_dog.jpg"
|
,.request_path= "/images/my_dog.jpg"
|
||||||
,.request_url= "/images/my_dog.jpg"
|
,.request_url= "/images/my_dog.jpg"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
|
@ -1142,6 +1184,7 @@ const struct message requests[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.method= HTTP_UNLINK
|
,.method= HTTP_UNLINK
|
||||||
|
,.request_method = "UNLINK"
|
||||||
,.request_path= "/images/my_dog.jpg"
|
,.request_path= "/images/my_dog.jpg"
|
||||||
,.request_url= "/images/my_dog.jpg"
|
,.request_url= "/images/my_dog.jpg"
|
||||||
,.query_string= ""
|
,.query_string= ""
|
||||||
|
@ -1153,6 +1196,30 @@ const struct message requests[] =
|
||||||
,.body= ""
|
,.body= ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if HTTP_PARSER_METHOD_CB
|
||||||
|
#define UNKNOWN_METHOD 42
|
||||||
|
, {.name="unknown method"
|
||||||
|
,.type= HTTP_REQUEST
|
||||||
|
,.raw= "NON-STANDARD-METHOD / HTTP/1.1\r\n"
|
||||||
|
"Host: example.com\r\n"
|
||||||
|
"\r\n"
|
||||||
|
,.should_keep_alive= TRUE
|
||||||
|
,.message_complete_on_eof= FALSE
|
||||||
|
,.http_major= 1
|
||||||
|
,.http_minor= 1
|
||||||
|
,.method= HTTP_METHOD_UNKNOWN
|
||||||
|
,.request_method= "NON-STANDARD-METHOD"
|
||||||
|
,.query_string= ""
|
||||||
|
,.fragment= ""
|
||||||
|
,.request_path= "/"
|
||||||
|
,.request_url= "/"
|
||||||
|
,.num_headers= 1
|
||||||
|
,.headers=
|
||||||
|
{ { "Host", "example.com" } }
|
||||||
|
,.body= ""
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
, {.name= NULL } /* sentinel */
|
, {.name= NULL } /* sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1815,6 +1882,19 @@ strlcpy(char *dst, const char *src, size_t len)
|
||||||
return strlncpy(dst, len, src, (size_t) -1);
|
return strlncpy(dst, len, src, (size_t) -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if HTTP_PARSER_METHOD_CB
|
||||||
|
int
|
||||||
|
request_method_cb(http_parser *p, const char *buf, size_t len)
|
||||||
|
{
|
||||||
|
assert(p == parser);
|
||||||
|
strlncat(messages[num_messages].request_method,
|
||||||
|
sizeof(messages[num_messages].request_method),
|
||||||
|
buf,
|
||||||
|
len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int
|
int
|
||||||
request_url_cb (http_parser *p, const char *buf, size_t len)
|
request_url_cb (http_parser *p, const char *buf, size_t len)
|
||||||
{
|
{
|
||||||
|
@ -2117,6 +2197,16 @@ pause_header_value_cb (http_parser *p, const char *buf, size_t len)
|
||||||
return header_value_cb(p, buf, len);
|
return header_value_cb(p, buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if HTTP_PARSER_METHOD_CB
|
||||||
|
int
|
||||||
|
pause_request_method_cb (http_parser *p, const char *buf, size_t len)
|
||||||
|
{
|
||||||
|
http_parser_pause(p, 1);
|
||||||
|
*current_pause_parser = settings_dontcall;
|
||||||
|
return request_method_cb(p, buf, len);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int
|
int
|
||||||
pause_request_url_cb (http_parser *p, const char *buf, size_t len)
|
pause_request_url_cb (http_parser *p, const char *buf, size_t len)
|
||||||
{
|
{
|
||||||
|
@ -2198,6 +2288,9 @@ static http_parser_settings settings_pause =
|
||||||
,.on_message_complete = pause_message_complete_cb
|
,.on_message_complete = pause_message_complete_cb
|
||||||
,.on_chunk_header = pause_chunk_header_cb
|
,.on_chunk_header = pause_chunk_header_cb
|
||||||
,.on_chunk_complete = pause_chunk_complete_cb
|
,.on_chunk_complete = pause_chunk_complete_cb
|
||||||
|
#if HTTP_PARSER_METHOD_CB
|
||||||
|
,.on_method = pause_request_method_cb
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static http_parser_settings settings =
|
static http_parser_settings settings =
|
||||||
|
@ -2211,6 +2304,9 @@ static http_parser_settings settings =
|
||||||
,.on_message_complete = message_complete_cb
|
,.on_message_complete = message_complete_cb
|
||||||
,.on_chunk_header = chunk_header_cb
|
,.on_chunk_header = chunk_header_cb
|
||||||
,.on_chunk_complete = chunk_complete_cb
|
,.on_chunk_complete = chunk_complete_cb
|
||||||
|
#if HTTP_PARSER_METHOD_CB
|
||||||
|
,.on_method = request_method_cb
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static http_parser_settings settings_count_body =
|
static http_parser_settings settings_count_body =
|
||||||
|
@ -2224,6 +2320,9 @@ static http_parser_settings settings_count_body =
|
||||||
,.on_message_complete = message_complete_cb
|
,.on_message_complete = message_complete_cb
|
||||||
,.on_chunk_header = chunk_header_cb
|
,.on_chunk_header = chunk_header_cb
|
||||||
,.on_chunk_complete = chunk_complete_cb
|
,.on_chunk_complete = chunk_complete_cb
|
||||||
|
#if HTTP_PARSER_METHOD_CB
|
||||||
|
,.on_method = request_method_cb
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static http_parser_settings settings_connect =
|
static http_parser_settings settings_connect =
|
||||||
|
@ -2237,6 +2336,9 @@ static http_parser_settings settings_connect =
|
||||||
,.on_message_complete = connect_message_complete_cb
|
,.on_message_complete = connect_message_complete_cb
|
||||||
,.on_chunk_header = chunk_header_cb
|
,.on_chunk_header = chunk_header_cb
|
||||||
,.on_chunk_complete = chunk_complete_cb
|
,.on_chunk_complete = chunk_complete_cb
|
||||||
|
#if HTTP_PARSER_METHOD_CB
|
||||||
|
,.on_method = request_method_cb
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static http_parser_settings settings_null =
|
static http_parser_settings settings_null =
|
||||||
|
@ -2250,6 +2352,9 @@ static http_parser_settings settings_null =
|
||||||
,.on_message_complete = 0
|
,.on_message_complete = 0
|
||||||
,.on_chunk_header = 0
|
,.on_chunk_header = 0
|
||||||
,.on_chunk_complete = 0
|
,.on_chunk_complete = 0
|
||||||
|
#if HTTP_PARSER_METHOD_CB
|
||||||
|
,.on_method = 0
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -2376,6 +2481,9 @@ message_eq (int index, int connect, const struct message *expected)
|
||||||
|
|
||||||
if (expected->type == HTTP_REQUEST) {
|
if (expected->type == HTTP_REQUEST) {
|
||||||
MESSAGE_CHECK_NUM_EQ(expected, m, method);
|
MESSAGE_CHECK_NUM_EQ(expected, m, method);
|
||||||
|
#if HTTP_PARSER_METHOD_CB
|
||||||
|
MESSAGE_CHECK_STR_EQ(expected, m, request_method);
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
MESSAGE_CHECK_NUM_EQ(expected, m, status_code);
|
MESSAGE_CHECK_NUM_EQ(expected, m, status_code);
|
||||||
MESSAGE_CHECK_STR_EQ(expected, m, response_status);
|
MESSAGE_CHECK_STR_EQ(expected, m, response_status);
|
||||||
|
@ -3850,11 +3958,10 @@ test_message_connect (const struct message *msg)
|
||||||
{
|
{
|
||||||
char *buf = (char*) msg->raw;
|
char *buf = (char*) msg->raw;
|
||||||
size_t buflen = strlen(msg->raw);
|
size_t buflen = strlen(msg->raw);
|
||||||
size_t nread;
|
|
||||||
|
|
||||||
parser_init(msg->type);
|
parser_init(msg->type);
|
||||||
|
|
||||||
nread = parse_connect(buf, buflen);
|
parse_connect(buf, buflen);
|
||||||
|
|
||||||
if (num_messages != 1) {
|
if (num_messages != 1) {
|
||||||
printf("\n*** num_messages != 1 after testing '%s' ***\n\n", msg->name);
|
printf("\n*** num_messages != 1 after testing '%s' ***\n\n", msg->name);
|
||||||
|
@ -4074,7 +4181,15 @@ main (void)
|
||||||
for (this_method = bad_methods; *this_method; this_method++) {
|
for (this_method = bad_methods; *this_method; this_method++) {
|
||||||
char buf[200];
|
char buf[200];
|
||||||
sprintf(buf, "%s / HTTP/1.1\r\n\r\n", *this_method);
|
sprintf(buf, "%s / HTTP/1.1\r\n\r\n", *this_method);
|
||||||
|
#if HTTP_PARSER_METHOD_CB
|
||||||
|
if (strchr(*this_method, ' ')) {
|
||||||
|
test_simple(buf, HPE_INVALID_URL);
|
||||||
|
} else {
|
||||||
|
test_simple(buf, HPE_OK);
|
||||||
|
}
|
||||||
|
#else
|
||||||
test_simple(buf, HPE_INVALID_METHOD);
|
test_simple(buf, HPE_INVALID_METHOD);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// illegal header field name line folding
|
// illegal header field name line folding
|
||||||
|
|
Loading…
Reference in New Issue