nghttpx: Return 400 for multiple CLs for HTTP/1 upstream
This commit is contained in:
parent
506177e1bd
commit
f1bec6f05c
|
@ -1,9 +1,11 @@
|
|||
package nghttp2
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"github.com/bradfitz/http2"
|
||||
"github.com/bradfitz/http2/hpack"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
@ -46,6 +48,27 @@ func TestH1H1PlainGETClose(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestH1H1DuplicateRequestCL(t *testing.T) {
|
||||
st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
|
||||
t.Errorf("server should not forward bad request")
|
||||
})
|
||||
defer st.Close()
|
||||
|
||||
if _, err := io.WriteString(st.conn, fmt.Sprintf("GET / HTTP/1.1\r\nHost: %v\r\nTest-Case: TestH1H1DuplicateRequestCL\r\nContent-Length: 0\r\nContent-Length: 1\r\n\r\n", st.authority)); 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)
|
||||
}
|
||||
|
||||
want := 400
|
||||
if got := resp.StatusCode; got != want {
|
||||
t.Errorf("status: %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestH2H1PlainGET(t *testing.T) {
|
||||
st := newServerTester(nil, t, noopHandler)
|
||||
defer st.Close()
|
||||
|
|
|
@ -286,11 +286,31 @@ const std::string &Downstream::get_assembled_request_cookie() const {
|
|||
return assembled_request_cookie_;
|
||||
}
|
||||
|
||||
void Downstream::index_request_headers() {
|
||||
for (auto &kv : request_headers_) {
|
||||
int Downstream::index_request_headers() {
|
||||
for (size_t i = 0; i < request_headers_.size(); ++i) {
|
||||
auto &kv = request_headers_[i];
|
||||
util::inp_strlower(kv.name);
|
||||
|
||||
auto token = http2::lookup_token(
|
||||
reinterpret_cast<const uint8_t *>(kv.name.c_str()), kv.name.size());
|
||||
if (token < 0) {
|
||||
continue;
|
||||
}
|
||||
http2::index_headers(request_hdidx_, request_headers_);
|
||||
|
||||
http2::index_header(request_hdidx_, token, i);
|
||||
|
||||
if (token == http2::HD_CONTENT_LENGTH) {
|
||||
auto len = util::parse_uint(kv.value);
|
||||
if (len == -1) {
|
||||
return -1;
|
||||
}
|
||||
if (request_content_length_ != -1 && request_content_length_ != len) {
|
||||
return -1;
|
||||
}
|
||||
request_content_length_ = len;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const Headers::value_type *Downstream::get_request_header(int token) const {
|
||||
|
@ -758,11 +778,13 @@ void Downstream::inspect_http1_request() {
|
|||
}
|
||||
}
|
||||
auto idx = request_hdidx_[http2::HD_TRANSFER_ENCODING];
|
||||
if (idx != -1 &&
|
||||
util::strifind(request_headers_[idx].value.c_str(), "chunked")) {
|
||||
if (idx != -1) {
|
||||
request_content_length_ = -1;
|
||||
if (util::strifind(request_headers_[idx].value.c_str(), "chunked")) {
|
||||
chunked_request_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Downstream::inspect_http1_response() {
|
||||
auto idx = response_hdidx_[http2::HD_TRANSFER_ENCODING];
|
||||
|
|
|
@ -100,8 +100,10 @@ public:
|
|||
Headers crumble_request_cookie();
|
||||
void assemble_request_cookie();
|
||||
const std::string &get_assembled_request_cookie() const;
|
||||
// Lower the request header field names and indexes request headers
|
||||
void index_request_headers();
|
||||
// Lower the request header field names and indexes request headers.
|
||||
// If there is any invalid headers (e.g., multiple Content-Length
|
||||
// having different values), returns -1.
|
||||
int index_request_headers();
|
||||
// Returns pointer to the request header with the name |name|. If
|
||||
// multiple header have |name| as name, return last occurrence from
|
||||
// the beginning. If no such header is found, returns nullptr.
|
||||
|
|
|
@ -157,7 +157,9 @@ int htp_hdrs_completecb(http_parser *htp) {
|
|||
ULOG(INFO, upstream) << "HTTP request headers\n" << ss.str();
|
||||
}
|
||||
|
||||
downstream->index_request_headers();
|
||||
if (downstream->index_request_headers() != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
downstream->inspect_http1_request();
|
||||
|
||||
|
|
Loading…
Reference in New Issue