From 707a0b4103e5ee54d7e3c815987be623a0c8d892 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Fri, 17 Jan 2014 02:16:53 +0900 Subject: [PATCH] Move name/value validation functions to src nghttp2 library itself now accept octet header/value pairs, completely not restricted by HTTP/1 header name/value rule. The applications may impose restriction about them using validators. --- lib/includes/nghttp2/nghttp2.h | 2 - lib/nghttp2_frame.c | 40 ------- lib/nghttp2_frame.h | 19 ---- lib/nghttp2_helper.c | 177 ----------------------------- lib/nghttp2_helper.h | 22 ---- lib/nghttp2_submit.c | 9 -- src/HttpServer.cc | 3 + src/http2.cc | 201 ++++++++++++++++++++++++++++++++- src/http2.h | 28 ++++- src/http2_test.cc | 56 ++++++++- src/http2_test.h | 4 +- src/shrpx-unittest.cc | 8 +- src/shrpx_http2_session.cc | 4 +- src/shrpx_http2_upstream.cc | 4 +- src/shrpx_spdy_upstream.cc | 6 +- tests/main.c | 8 +- tests/nghttp2_frame_test.c | 33 ------ tests/nghttp2_frame_test.h | 1 - tests/nghttp2_helper_test.c | 44 -------- tests/nghttp2_helper_test.h | 2 - tests/nghttp2_session_test.c | 11 +- 21 files changed, 304 insertions(+), 378 deletions(-) diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index c26c27fb..54e0727d 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -2143,8 +2143,6 @@ int nghttp2_submit_settings(nghttp2_session *session, uint8_t flags, * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` * The |nva| includes empty name, or name which contains invalid * characters. - * :enum:`NGHTTP2_ERR_STREAM_CLOSED` - * The stream is already closed or does not exist. * :enum:`NGHTTP2_ERR_NOMEM` * Out of memory. */ diff --git a/lib/nghttp2_frame.c b/lib/nghttp2_frame.c index de6dc06d..eae04011 100644 --- a/lib/nghttp2_frame.c +++ b/lib/nghttp2_frame.c @@ -550,46 +550,6 @@ nghttp2_settings_entry* nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv, return iv_copy; } -int nghttp2_nv_array_check_nocase(const nghttp2_nv *nva, size_t nvlen) -{ - size_t i; - for(i = 0; i < nvlen; ++i) { - if(!nghttp2_check_header_name_nocase(nva[i].name, nva[i].namelen)) { - return 0; - } - if(!nghttp2_check_header_value(nva[i].value, nva[i].valuelen)) { - return 0; - } - } - return 1; -} - -int nghttp2_nv_array_check(const nghttp2_nv *nva, size_t nvlen) -{ - size_t i; - for(i = 0; i < nvlen; ++i) { - if(!nghttp2_check_header_name(nva[i].name, nva[i].namelen)) { - return 0; - } - if(!nghttp2_check_header_value(nva[i].value, nva[i].valuelen)) { - return 0; - } - } - return 1; -} - -int nghttp2_nv_check(const uint8_t *name, size_t namelen, - const uint8_t *value, size_t valuelen) -{ - if(!nghttp2_check_header_name(name, namelen)) { - return 0; - } - if(!nghttp2_check_header_value(value, valuelen)) { - return 0; - } - return 1; -} - int nghttp2_nv_equal(const nghttp2_nv *a, const nghttp2_nv *b) { return a->namelen == b->namelen && a->valuelen == b->valuelen && diff --git a/lib/nghttp2_frame.h b/lib/nghttp2_frame.h index ef6b15b8..46e39759 100644 --- a/lib/nghttp2_frame.h +++ b/lib/nghttp2_frame.h @@ -558,25 +558,6 @@ int nghttp2_nv_equal(const nghttp2_nv *a, const nghttp2_nv *b); */ void nghttp2_nv_array_del(nghttp2_nv *nva); -/* - * Checks header name/value pair is well-formed. This function allows - * captital alphabet letters in name. - * - * This function returns nonzero if it succeeds, or 0. - */ -int nghttp2_nv_array_check_nocase(const nghttp2_nv *nva, size_t nvlen); - -/* - * Checks header name/value pair is well-formed. This function does - * not allow captital alphabet letters in name. - * - * This function returns nonzero if it succeeds, or 0. - */ -int nghttp2_nv_array_check(const nghttp2_nv *nva, size_t nvlen); - -int nghttp2_nv_check(const uint8_t *name, size_t namelen, - const uint8_t *value, size_t valuelen); - /* * Checks that the |iv|, which includes |niv| entries, does not have * invalid values. The |flow_control_opt| is current flow control diff --git a/lib/nghttp2_helper.c b/lib/nghttp2_helper.c index 355b875c..ae0201df 100644 --- a/lib/nghttp2_helper.c +++ b/lib/nghttp2_helper.c @@ -154,183 +154,6 @@ int nghttp2_should_send_window_update(int32_t local_window_size, return recv_window_size >= local_window_size / 2; } -static int VALID_HD_NAME_CHARS[] = { - 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, - 0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, - 0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */, - 0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */, - 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, - 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, - 0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */, - 0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */, - 0 /* SPC */, 1 /* ! */, 0 /* " */, 1 /* # */, - 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */, - 0 /* ( */, 0 /* ) */, 1 /* * */, 1 /* + */, - 0 /* , */, 1 /* - */, 1 /* . */, 0 /* / */, - 1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */, - 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */, - 1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */, - 0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */, - 0 /* @ */, 0 /* A */, 0 /* B */, 0 /* C */, - 0 /* D */, 0 /* E */, 0 /* F */, 0 /* G */, - 0 /* H */, 0 /* I */, 0 /* J */, 0 /* K */, - 0 /* L */, 0 /* M */, 0 /* N */, 0 /* O */, - 0 /* P */, 0 /* Q */, 0 /* R */, 0 /* S */, - 0 /* T */, 0 /* U */, 0 /* V */, 0 /* W */, - 0 /* X */, 0 /* Y */, 0 /* Z */, 0 /* [ */, - 0 /* \ */, 0 /* ] */, 1 /* ^ */, 1 /* _ */, - 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, - 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, - 1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */, - 1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */, - 1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */, - 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, - 1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, - 1 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */, - 0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */, - 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */, - 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */, - 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, - 0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, - 0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */, - 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */, - 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */, - 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, - 0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, - 0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */, - 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */, - 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */, - 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, - 0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, - 0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */, - 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */, - 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */, - 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, - 0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, - 0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */, - 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */, - 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */, - 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, - 0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, - 0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */, - 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */, - 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */, - 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, - 0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, - 0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */, - 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */ -}; - -static int check_header_name(const uint8_t *name, size_t len, int nocase) -{ - const uint8_t *last; - if(len == 0) { - return 0; - } - if(*name == ':') { - if(len == 1) { - return 0; - } - ++name; - --len; - } - for(last = name + len; name != last; ++name) { - if(nocase && 'A' <= *name && *name <= 'Z') continue; - if(!VALID_HD_NAME_CHARS[*name]) { - return 0; - } - } - return 1; -} - -int nghttp2_check_header_name(const uint8_t *name, size_t len) -{ - return check_header_name(name, len, 0); -} - -int nghttp2_check_header_name_nocase(const uint8_t *name, size_t len) -{ - return check_header_name(name, len, 1); -} - -static int VALID_HD_VALUE_CHARS[] = { - 1 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, - 0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, - 0 /* BS */, 1 /* HT */, 0 /* LF */, 0 /* VT */, - 0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */, - 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, - 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, - 0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */, - 0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */, - 1 /* SPC */, 1 /* ! */, 1 /* " */, 1 /* # */, - 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */, - 1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */, - 1 /* , */, 1 /* - */, 1 /* . */, 1 /* / */, - 1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */, - 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */, - 1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */, - 1 /* < */, 1 /* = */, 1 /* > */, 1 /* ? */, - 1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */, - 1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */, - 1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */, - 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */, - 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, - 1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */, - 1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */, - 1 /* \ */, 1 /* ] */, 1 /* ^ */, 1 /* _ */, - 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, - 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, - 1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */, - 1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */, - 1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */, - 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, - 1 /* x */, 1 /* y */, 1 /* z */, 1 /* { */, - 1 /* | */, 1 /* } */, 1 /* ~ */, 0 /* DEL */, - 1 /* 0x80 */, 1 /* 0x81 */, 1 /* 0x82 */, 1 /* 0x83 */, - 1 /* 0x84 */, 1 /* 0x85 */, 1 /* 0x86 */, 1 /* 0x87 */, - 1 /* 0x88 */, 1 /* 0x89 */, 1 /* 0x8a */, 1 /* 0x8b */, - 1 /* 0x8c */, 1 /* 0x8d */, 1 /* 0x8e */, 1 /* 0x8f */, - 1 /* 0x90 */, 1 /* 0x91 */, 1 /* 0x92 */, 1 /* 0x93 */, - 1 /* 0x94 */, 1 /* 0x95 */, 1 /* 0x96 */, 1 /* 0x97 */, - 1 /* 0x98 */, 1 /* 0x99 */, 1 /* 0x9a */, 1 /* 0x9b */, - 1 /* 0x9c */, 1 /* 0x9d */, 1 /* 0x9e */, 1 /* 0x9f */, - 1 /* 0xa0 */, 1 /* 0xa1 */, 1 /* 0xa2 */, 1 /* 0xa3 */, - 1 /* 0xa4 */, 1 /* 0xa5 */, 1 /* 0xa6 */, 1 /* 0xa7 */, - 1 /* 0xa8 */, 1 /* 0xa9 */, 1 /* 0xaa */, 1 /* 0xab */, - 1 /* 0xac */, 1 /* 0xad */, 1 /* 0xae */, 1 /* 0xaf */, - 1 /* 0xb0 */, 1 /* 0xb1 */, 1 /* 0xb2 */, 1 /* 0xb3 */, - 1 /* 0xb4 */, 1 /* 0xb5 */, 1 /* 0xb6 */, 1 /* 0xb7 */, - 1 /* 0xb8 */, 1 /* 0xb9 */, 1 /* 0xba */, 1 /* 0xbb */, - 1 /* 0xbc */, 1 /* 0xbd */, 1 /* 0xbe */, 1 /* 0xbf */, - 1 /* 0xc0 */, 1 /* 0xc1 */, 1 /* 0xc2 */, 1 /* 0xc3 */, - 1 /* 0xc4 */, 1 /* 0xc5 */, 1 /* 0xc6 */, 1 /* 0xc7 */, - 1 /* 0xc8 */, 1 /* 0xc9 */, 1 /* 0xca */, 1 /* 0xcb */, - 1 /* 0xcc */, 1 /* 0xcd */, 1 /* 0xce */, 1 /* 0xcf */, - 1 /* 0xd0 */, 1 /* 0xd1 */, 1 /* 0xd2 */, 1 /* 0xd3 */, - 1 /* 0xd4 */, 1 /* 0xd5 */, 1 /* 0xd6 */, 1 /* 0xd7 */, - 1 /* 0xd8 */, 1 /* 0xd9 */, 1 /* 0xda */, 1 /* 0xdb */, - 1 /* 0xdc */, 1 /* 0xdd */, 1 /* 0xde */, 1 /* 0xdf */, - 1 /* 0xe0 */, 1 /* 0xe1 */, 1 /* 0xe2 */, 1 /* 0xe3 */, - 1 /* 0xe4 */, 1 /* 0xe5 */, 1 /* 0xe6 */, 1 /* 0xe7 */, - 1 /* 0xe8 */, 1 /* 0xe9 */, 1 /* 0xea */, 1 /* 0xeb */, - 1 /* 0xec */, 1 /* 0xed */, 1 /* 0xee */, 1 /* 0xef */, - 1 /* 0xf0 */, 1 /* 0xf1 */, 1 /* 0xf2 */, 1 /* 0xf3 */, - 1 /* 0xf4 */, 1 /* 0xf5 */, 1 /* 0xf6 */, 1 /* 0xf7 */, - 1 /* 0xf8 */, 1 /* 0xf9 */, 1 /* 0xfa */, 1 /* 0xfb */, - 1 /* 0xfc */, 1 /* 0xfd */, 1 /* 0xfe */, 1 /* 0xff */ -}; - -int nghttp2_check_header_value(const uint8_t* value, size_t len) -{ - const uint8_t *last; - for(last = value + len; value != last; ++value) { - if(!VALID_HD_VALUE_CHARS[*value]) { - return 0; - } - } - return 1; -} - const char* nghttp2_strerror(int error_code) { switch(error_code) { diff --git a/lib/nghttp2_helper.h b/lib/nghttp2_helper.h index 56d09523..716cc211 100644 --- a/lib/nghttp2_helper.h +++ b/lib/nghttp2_helper.h @@ -118,28 +118,6 @@ int nghttp2_adjust_local_window_size(int32_t *local_window_size_ptr, int nghttp2_should_send_window_update(int32_t local_window_size, int32_t recv_window_size); -/* - * Checks the header name in |name| with |len| bytes is well-formed. - * - * This function returns nonzero if it succeeds, or 0. - */ -int nghttp2_check_header_name(const uint8_t *name, size_t len); - -/* - * Checks the header name in |name| with |len| bytes is - * well-formed. This function accepts also characters in [A-Z]. - * - * This function returns nonzero if it succeeds, or 0. - */ -int nghttp2_check_header_name_nocase(const uint8_t *name, size_t len); - -/* - * Checks the header value in |value| with |len| bytes is well-formed. - * - * This function returns nonzero if it succeeds, or 0. - */ -int nghttp2_check_header_value(const uint8_t* value, size_t len); - /* * Deallocates memory space pointed by |ptr|. This function exists for * the application to free the memory space allocated by the library diff --git a/lib/nghttp2_submit.c b/lib/nghttp2_submit.c index 68c92e34..f4a20165 100644 --- a/lib/nghttp2_submit.c +++ b/lib/nghttp2_submit.c @@ -110,9 +110,6 @@ static int nghttp2_submit_headers_shared_nva { ssize_t rv; nghttp2_nv *nva_copy; - if(!nghttp2_nv_array_check_nocase(nva, nvlen)) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } rv = nghttp2_nv_array_copy(&nva_copy, nva, nvlen); if(rv < 0) { return rv; @@ -195,12 +192,6 @@ int nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags, uint8_t flags_copy; int rv; - if(!nghttp2_nv_array_check_nocase(nva, nvlen)) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - if(nghttp2_session_get_stream(session, stream_id) == NULL) { - return NGHTTP2_ERR_STREAM_CLOSED; - } frame = malloc(sizeof(nghttp2_frame)); if(frame == NULL) { return NGHTTP2_ERR_NOMEM; diff --git a/src/HttpServer.cc b/src/HttpServer.cc index a77a8ac6..624338af 100644 --- a/src/HttpServer.cc +++ b/src/HttpServer.cc @@ -791,6 +791,9 @@ int on_header_callback(nghttp2_session *session, if(!stream) { return 0; } + if(!http2::check_nv(name, namelen, value, valuelen)) { + return 0; + } http2::split_add_header(stream->headers, name, namelen, value, valuelen); return 0; } diff --git a/src/http2.cc b/src/http2.cc index 0094e306..f94f17b8 100644 --- a/src/http2.cc +++ b/src/http2.cc @@ -90,7 +90,7 @@ void capitalize(std::string& s, size_t offset) } } -bool check_header_value(const char *value) +bool lws(const char *value) { for(; *value; ++value) { switch(*value) { @@ -98,10 +98,10 @@ bool check_header_value(const char *value) case ' ': continue; default: - return true; + return false; } } - return false; + return true; } void sanitize_header_value(std::string& s, size_t offset) @@ -535,6 +535,201 @@ std::string rewrite_location_uri(const std::string& uri, return res; } +namespace { +int VALID_HD_NAME_CHARS[] = { + 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, + 0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, + 0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */, + 0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */, + 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, + 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, + 0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */, + 0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */, + 0 /* SPC */, 1 /* ! */, 0 /* " */, 1 /* # */, + 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */, + 0 /* ( */, 0 /* ) */, 1 /* * */, 1 /* + */, + 0 /* , */, 1 /* - */, 1 /* . */, 0 /* / */, + 1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */, + 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */, + 1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */, + 0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */, + 0 /* @ */, 0 /* A */, 0 /* B */, 0 /* C */, + 0 /* D */, 0 /* E */, 0 /* F */, 0 /* G */, + 0 /* H */, 0 /* I */, 0 /* J */, 0 /* K */, + 0 /* L */, 0 /* M */, 0 /* N */, 0 /* O */, + 0 /* P */, 0 /* Q */, 0 /* R */, 0 /* S */, + 0 /* T */, 0 /* U */, 0 /* V */, 0 /* W */, + 0 /* X */, 0 /* Y */, 0 /* Z */, 0 /* [ */, + 0 /* \ */, 0 /* ] */, 1 /* ^ */, 1 /* _ */, + 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, + 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, + 1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */, + 1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */, + 1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */, + 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, + 1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, + 1 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */, + 0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */, + 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */, + 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */, + 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, + 0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, + 0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */, + 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */, + 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */, + 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, + 0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, + 0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */, + 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */, + 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */, + 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, + 0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, + 0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */, + 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */, + 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */, + 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, + 0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, + 0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */, + 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */, + 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */, + 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, + 0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, + 0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */, + 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */, + 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */, + 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, + 0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, + 0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */, + 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */ +}; +} // namespace + +namespace { +int check_header_name(const uint8_t *name, size_t len, int nocase) +{ + const uint8_t *last; + if(len == 0) { + return 0; + } + if(*name == ':') { + if(len == 1) { + return 0; + } + ++name; + --len; + } + for(last = name + len; name != last; ++name) { + if(nocase && 'A' <= *name && *name <= 'Z') continue; + if(!VALID_HD_NAME_CHARS[*name]) { + return 0; + } + } + return 1; +} +} // namespace + +int check_header_name(const uint8_t *name, size_t len) +{ + return check_header_name(name, len, 0); +} + +int check_header_name_nocase(const uint8_t *name, size_t len) +{ + return check_header_name(name, len, 1); +} + +namespace { +int VALID_HD_VALUE_CHARS[] = { + 1 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, + 0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, + 0 /* BS */, 1 /* HT */, 0 /* LF */, 0 /* VT */, + 0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */, + 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, + 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, + 0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */, + 0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */, + 1 /* SPC */, 1 /* ! */, 1 /* " */, 1 /* # */, + 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */, + 1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */, + 1 /* , */, 1 /* - */, 1 /* . */, 1 /* / */, + 1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */, + 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */, + 1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */, + 1 /* < */, 1 /* = */, 1 /* > */, 1 /* ? */, + 1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */, + 1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */, + 1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */, + 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */, + 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, + 1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */, + 1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */, + 1 /* \ */, 1 /* ] */, 1 /* ^ */, 1 /* _ */, + 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, + 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, + 1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */, + 1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */, + 1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */, + 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, + 1 /* x */, 1 /* y */, 1 /* z */, 1 /* { */, + 1 /* | */, 1 /* } */, 1 /* ~ */, 0 /* DEL */, + 1 /* 0x80 */, 1 /* 0x81 */, 1 /* 0x82 */, 1 /* 0x83 */, + 1 /* 0x84 */, 1 /* 0x85 */, 1 /* 0x86 */, 1 /* 0x87 */, + 1 /* 0x88 */, 1 /* 0x89 */, 1 /* 0x8a */, 1 /* 0x8b */, + 1 /* 0x8c */, 1 /* 0x8d */, 1 /* 0x8e */, 1 /* 0x8f */, + 1 /* 0x90 */, 1 /* 0x91 */, 1 /* 0x92 */, 1 /* 0x93 */, + 1 /* 0x94 */, 1 /* 0x95 */, 1 /* 0x96 */, 1 /* 0x97 */, + 1 /* 0x98 */, 1 /* 0x99 */, 1 /* 0x9a */, 1 /* 0x9b */, + 1 /* 0x9c */, 1 /* 0x9d */, 1 /* 0x9e */, 1 /* 0x9f */, + 1 /* 0xa0 */, 1 /* 0xa1 */, 1 /* 0xa2 */, 1 /* 0xa3 */, + 1 /* 0xa4 */, 1 /* 0xa5 */, 1 /* 0xa6 */, 1 /* 0xa7 */, + 1 /* 0xa8 */, 1 /* 0xa9 */, 1 /* 0xaa */, 1 /* 0xab */, + 1 /* 0xac */, 1 /* 0xad */, 1 /* 0xae */, 1 /* 0xaf */, + 1 /* 0xb0 */, 1 /* 0xb1 */, 1 /* 0xb2 */, 1 /* 0xb3 */, + 1 /* 0xb4 */, 1 /* 0xb5 */, 1 /* 0xb6 */, 1 /* 0xb7 */, + 1 /* 0xb8 */, 1 /* 0xb9 */, 1 /* 0xba */, 1 /* 0xbb */, + 1 /* 0xbc */, 1 /* 0xbd */, 1 /* 0xbe */, 1 /* 0xbf */, + 1 /* 0xc0 */, 1 /* 0xc1 */, 1 /* 0xc2 */, 1 /* 0xc3 */, + 1 /* 0xc4 */, 1 /* 0xc5 */, 1 /* 0xc6 */, 1 /* 0xc7 */, + 1 /* 0xc8 */, 1 /* 0xc9 */, 1 /* 0xca */, 1 /* 0xcb */, + 1 /* 0xcc */, 1 /* 0xcd */, 1 /* 0xce */, 1 /* 0xcf */, + 1 /* 0xd0 */, 1 /* 0xd1 */, 1 /* 0xd2 */, 1 /* 0xd3 */, + 1 /* 0xd4 */, 1 /* 0xd5 */, 1 /* 0xd6 */, 1 /* 0xd7 */, + 1 /* 0xd8 */, 1 /* 0xd9 */, 1 /* 0xda */, 1 /* 0xdb */, + 1 /* 0xdc */, 1 /* 0xdd */, 1 /* 0xde */, 1 /* 0xdf */, + 1 /* 0xe0 */, 1 /* 0xe1 */, 1 /* 0xe2 */, 1 /* 0xe3 */, + 1 /* 0xe4 */, 1 /* 0xe5 */, 1 /* 0xe6 */, 1 /* 0xe7 */, + 1 /* 0xe8 */, 1 /* 0xe9 */, 1 /* 0xea */, 1 /* 0xeb */, + 1 /* 0xec */, 1 /* 0xed */, 1 /* 0xee */, 1 /* 0xef */, + 1 /* 0xf0 */, 1 /* 0xf1 */, 1 /* 0xf2 */, 1 /* 0xf3 */, + 1 /* 0xf4 */, 1 /* 0xf5 */, 1 /* 0xf6 */, 1 /* 0xf7 */, + 1 /* 0xf8 */, 1 /* 0xf9 */, 1 /* 0xfa */, 1 /* 0xfb */, + 1 /* 0xfc */, 1 /* 0xfd */, 1 /* 0xfe */, 1 /* 0xff */ +}; +} // namespace + +int check_header_value(const uint8_t* value, size_t len) +{ + const uint8_t *last; + for(last = value + len; value != last; ++value) { + if(!VALID_HD_VALUE_CHARS[*value]) { + return 0; + } + } + return 1; +} + +int check_nv(const uint8_t *name, size_t namelen, + const uint8_t *value, size_t valuelen) +{ + if(!check_header_name(name, namelen)) { + return 0; + } + if(!check_header_value(value, valuelen)) { + return 0; + } + return 1; +} + } // namespace http2 } // namespace nghttp2 diff --git a/src/http2.h b/src/http2.h index 9e4645e6..3a177522 100644 --- a/src/http2.h +++ b/src/http2.h @@ -46,8 +46,8 @@ std::string get_status_string(unsigned int status_code); void capitalize(std::string& s, size_t offset); -// Returns false if |value| is LWS -bool check_header_value(const char *value); +// Returns true if |value| is LWS +bool lws(const char *value); void sanitize_header_value(std::string& s, size_t offset); @@ -197,6 +197,30 @@ std::string rewrite_location_uri(const std::string& uri, const std::string& upstream_scheme, uint16_t upstream_port); + +// Checks the header name in |name| with |len| bytes is well-formed. +// +// This function returns nonzero if it succeeds, or 0. +int check_header_name(const uint8_t *name, size_t len); + + +// Checks the header name in |name| with |len| bytes is +// well-formed. This function accepts also characters in [A-Z]. +// +// This function returns nonzero if it succeeds, or 0. +int check_header_name_nocase(const uint8_t *name, size_t len); + +// Checks the header value in |value| with |len| bytes is well-formed. +// +// This function returns nonzero if it succeeds, or 0. +int check_header_value(const uint8_t* value, size_t len); + +// Checks the header name/value pair using check_header_name() and +// check_header_value(). If both function returns nonzero, this +// function returns nonzero. +int check_nv(const uint8_t *name, size_t namelen, + const uint8_t *value, size_t valuelen); + } // namespace http2 } // namespace nghttp2 diff --git a/src/http2_test.cc b/src/http2_test.cc index db4f42a2..2283f6ce 100644 --- a/src/http2_test.cc +++ b/src/http2_test.cc @@ -244,11 +244,11 @@ void test_http2_build_http1_headers_from_norm_headers(void) // CU_ASSERT(hdrs == "Alpha: bravo charlie \r\n"); } -void test_http2_check_header_value(void) +void test_http2_lws(void) { - CU_ASSERT(http2::check_header_value("alpha")); - CU_ASSERT(!http2::check_header_value(" ")); - CU_ASSERT(!http2::check_header_value("")); + CU_ASSERT(!http2::lws("alpha")); + CU_ASSERT(http2::lws(" ")); + CU_ASSERT(http2::lws("")); } namespace { @@ -297,4 +297,52 @@ void test_http2_rewrite_location_uri(void) "localhost", "https", 3000); } +namespace { +int check_header_name(const char *s) +{ + return http2::check_header_name((const uint8_t*)s, strlen(s)); +} +} // namespace + +namespace { +int check_header_name_nocase(const char *s) +{ + return http2::check_header_name_nocase((const uint8_t*)s, strlen(s)); +} +} // namespace + +void test_http2_check_header_name(void) +{ + CU_ASSERT(check_header_name(":path")); + CU_ASSERT(check_header_name("path")); + CU_ASSERT(check_header_name("!#$%&'*+-.^_`|~")); + CU_ASSERT(!check_header_name(":PATH")); + CU_ASSERT(!check_header_name("path:")); + CU_ASSERT(!check_header_name("")); + CU_ASSERT(!check_header_name(":")); + + CU_ASSERT(check_header_name_nocase(":path")); + CU_ASSERT(check_header_name_nocase("path")); + CU_ASSERT(check_header_name_nocase("!#$%&'*+-.^_`|~")); + CU_ASSERT(check_header_name_nocase(":PATH")); + CU_ASSERT(!check_header_name_nocase("path:")); + CU_ASSERT(!check_header_name_nocase("")); + CU_ASSERT(!check_header_name_nocase(":")); +} + +#define check_header_value(S) \ + http2::check_header_value((const uint8_t*)S, sizeof(S) - 1) + +void test_http2_check_header_value(void) +{ + uint8_t goodval[] = { 'a', '\0', 'b', 0x80u, 'c', 0xffu, 'd', '\t', ' ' }; + uint8_t badval1[] = { 'a', 0x1fu, 'b' }; + uint8_t badval2[] = { 'a', 0x7fu, 'b' }; + + CU_ASSERT(check_header_value(" !|}~")); + CU_ASSERT(check_header_value(goodval)); + CU_ASSERT(!check_header_value(badval1)); + CU_ASSERT(!check_header_value(badval2)); +} + } // namespace shrpx diff --git a/src/http2_test.h b/src/http2_test.h index d3662444..837d0d61 100644 --- a/src/http2_test.h +++ b/src/http2_test.h @@ -36,8 +36,10 @@ void test_http2_value_lws(void); void test_http2_concat_norm_headers(void); void test_http2_copy_norm_headers_to_nva(void); void test_http2_build_http1_headers_from_norm_headers(void); -void test_http2_check_header_value(void); +void test_http2_lws(void); void test_http2_rewrite_location_uri(void); +void test_http2_check_header_name(void); +void test_http2_check_header_value(void); } // namespace shrpx diff --git a/src/shrpx-unittest.cc b/src/shrpx-unittest.cc index c5434c67..10b6b76a 100644 --- a/src/shrpx-unittest.cc +++ b/src/shrpx-unittest.cc @@ -87,10 +87,14 @@ int main(int argc, char* argv[]) shrpx::test_http2_copy_norm_headers_to_nva) || !CU_add_test(pSuite, "http2_build_http1_headers_from_norm_headers", shrpx::test_http2_build_http1_headers_from_norm_headers) || - !CU_add_test(pSuite, "http2_check_header_value", - shrpx::test_http2_check_header_value) || + !CU_add_test(pSuite, "http2_lws", + shrpx::test_http2_lws) || !CU_add_test(pSuite, "http2_rewrite_location_uri", shrpx::test_http2_rewrite_location_uri) || + !CU_add_test(pSuite, "http2_check_header_name", + shrpx::test_http2_check_header_name) || + !CU_add_test(pSuite, "http2_check_header_value", + shrpx::test_http2_check_header_value) || !CU_add_test(pSuite, "downstream_normalize_request_headers", shrpx::test_downstream_normalize_request_headers) || !CU_add_test(pSuite, "downstream_normalize_response_headers", diff --git a/src/shrpx_http2_session.cc b/src/shrpx_http2_session.cc index 3427c841..dabc8237 100644 --- a/src/shrpx_http2_session.cc +++ b/src/shrpx_http2_session.cc @@ -816,7 +816,9 @@ int on_header_callback(nghttp2_session *session, if(!downstream) { return 0; } - // TODO Discard malformed header here + if(!http2::check_nv(name, namelen, value, valuelen)) { + return 0; + } downstream->split_add_response_header(name, namelen, value, valuelen); return 0; } diff --git a/src/shrpx_http2_upstream.cc b/src/shrpx_http2_upstream.cc index 5f004b89..1f396f95 100644 --- a/src/shrpx_http2_upstream.cc +++ b/src/shrpx_http2_upstream.cc @@ -233,7 +233,9 @@ int on_header_callback(nghttp2_session *session, if(!downstream) { return 0; } - // TODO Discard malformed header here + if(!http2::check_nv(name, namelen, value, valuelen)) { + return 0; + } downstream->split_add_request_header(name, namelen, value, valuelen); return 0; } diff --git a/src/shrpx_spdy_upstream.cc b/src/shrpx_spdy_upstream.cc index ead01af6..0e3acca9 100644 --- a/src/shrpx_spdy_upstream.cc +++ b/src/shrpx_spdy_upstream.cc @@ -179,10 +179,8 @@ void on_ctrl_recv_callback } bool is_connect = method && strcmp("CONNECT", method) == 0; if(!path || !host || !method || - !http2::check_header_value(host) || - !http2::check_header_value(path) || - !http2::check_header_value(method) || - (!is_connect && (!scheme || !http2::check_header_value(scheme)))) { + http2::lws(host) || http2::lws(path) || http2::lws(method) || + (!is_connect && (!scheme || http2::lws(scheme)))) { upstream->rst_stream(downstream, SPDYLAY_INTERNAL_ERROR); return; } diff --git a/tests/main.c b/tests/main.c index 26e7364c..2d40f94e 100644 --- a/tests/main.c +++ b/tests/main.c @@ -215,8 +215,6 @@ int main(int argc, char* argv[]) test_nghttp2_frame_pack_goaway) || !CU_add_test(pSuite, "frame_pack_window_update", test_nghttp2_frame_pack_window_update) || - !CU_add_test(pSuite, "nv_array_check", - test_nghttp2_nv_array_check) || !CU_add_test(pSuite, "nv_array_copy", test_nghttp2_nv_array_copy) || !CU_add_test(pSuite, "iv_check", test_nghttp2_iv_check) || !CU_add_test(pSuite, "hd_deflate", test_nghttp2_hd_deflate) || @@ -248,11 +246,7 @@ int main(int argc, char* argv[]) test_nghttp2_hd_deflate_inflate) || !CU_add_test(pSuite, "gzip_inflate", test_nghttp2_gzip_inflate) || !CU_add_test(pSuite, "adjust_local_window_size", - test_nghttp2_adjust_local_window_size) || - !CU_add_test(pSuite, "check_header_name", - test_nghttp2_check_header_name) || - !CU_add_test(pSuite, "check_header_value", - test_nghttp2_check_header_value) + test_nghttp2_adjust_local_window_size) ) { CU_cleanup_registry(); return CU_get_error(); diff --git a/tests/nghttp2_frame_test.c b/tests/nghttp2_frame_test.c index 314cd3a3..b2b64a68 100644 --- a/tests/nghttp2_frame_test.c +++ b/tests/nghttp2_frame_test.c @@ -370,39 +370,6 @@ void test_nghttp2_frame_pack_window_update(void) nghttp2_frame_window_update_free(&frame); } -void test_nghttp2_nv_array_check(void) -{ - nghttp2_nv nva1[] = {MAKE_NV("path", "/"), - MAKE_NV("host", "a")}; - nghttp2_nv nva2[] = {MAKE_NV("", "/"), - MAKE_NV("host", "a")}; - nghttp2_nv nva3[] = {MAKE_NV("path", "/"), - MAKE_NV("host\x01", "a")}; - nghttp2_nv nva4[] = {MAKE_NV("PATH", "/")}; - nghttp2_nv nva5[] = {MAKE_NV("path", "foo"), - MAKE_NV("host", "foo\x00")}; - nghttp2_nv nva6[] = {MAKE_NV("path", "foo"), - MAKE_NV("host", "foo\x01")}; - - CU_ASSERT(nghttp2_nv_array_check(nva1, ARRLEN(nva1))); - CU_ASSERT(nghttp2_nv_array_check_nocase(nva1, ARRLEN(nva1))); - - CU_ASSERT(0 == nghttp2_nv_array_check(nva2, ARRLEN(nva2))); - CU_ASSERT(0 == nghttp2_nv_array_check_nocase(nva2, ARRLEN(nva2))); - - CU_ASSERT(0 == nghttp2_nv_array_check(nva3, ARRLEN(nva3))); - CU_ASSERT(0 == nghttp2_nv_array_check_nocase(nva3, ARRLEN(nva3))); - - CU_ASSERT(0 == nghttp2_nv_array_check(nva4, ARRLEN(nva4))); - CU_ASSERT(nghttp2_nv_array_check_nocase(nva4, ARRLEN(nva4))); - - CU_ASSERT(nghttp2_nv_array_check(nva5, ARRLEN(nva5))); - CU_ASSERT(nghttp2_nv_array_check_nocase(nva5, ARRLEN(nva5))); - - CU_ASSERT(0 == nghttp2_nv_array_check(nva6, ARRLEN(nva6))); - CU_ASSERT(0 == nghttp2_nv_array_check_nocase(nva6, ARRLEN(nva6))); -} - void test_nghttp2_nv_array_copy(void) { nghttp2_nv *nva; diff --git a/tests/nghttp2_frame_test.h b/tests/nghttp2_frame_test.h index 56c8ac48..9a04c23d 100644 --- a/tests/nghttp2_frame_test.h +++ b/tests/nghttp2_frame_test.h @@ -34,7 +34,6 @@ void test_nghttp2_frame_pack_push_promise(void); void test_nghttp2_frame_pack_ping(void); void test_nghttp2_frame_pack_goaway(void); void test_nghttp2_frame_pack_window_update(void); -void test_nghttp2_nv_array_check(void); void test_nghttp2_nv_array_copy(void); void test_nghttp2_iv_check(void); diff --git a/tests/nghttp2_helper_test.c b/tests/nghttp2_helper_test.c index 2e7652bb..6985d46d 100644 --- a/tests/nghttp2_helper_test.c +++ b/tests/nghttp2_helper_test.c @@ -152,47 +152,3 @@ void test_nghttp2_adjust_local_window_size(void) CU_ASSERT(0 == recv_reduction); CU_ASSERT(INT32_MIN == delta); } - -static int check_header_name(const char *s) -{ - return nghttp2_check_header_name((const uint8_t*)s, strlen(s)); -} - -static int check_header_name_nocase(const char *s) -{ - return nghttp2_check_header_name_nocase((const uint8_t*)s, strlen(s)); -} - -void test_nghttp2_check_header_name(void) -{ - CU_ASSERT(check_header_name(":path")); - CU_ASSERT(check_header_name("path")); - CU_ASSERT(check_header_name("!#$%&'*+-.^_`|~")); - CU_ASSERT(!check_header_name(":PATH")); - CU_ASSERT(!check_header_name("path:")); - CU_ASSERT(!check_header_name("")); - CU_ASSERT(!check_header_name(":")); - - CU_ASSERT(check_header_name_nocase(":path")); - CU_ASSERT(check_header_name_nocase("path")); - CU_ASSERT(check_header_name_nocase("!#$%&'*+-.^_`|~")); - CU_ASSERT(check_header_name_nocase(":PATH")); - CU_ASSERT(!check_header_name_nocase("path:")); - CU_ASSERT(!check_header_name_nocase("")); - CU_ASSERT(!check_header_name_nocase(":")); -} - -#define check_header_value(S) \ - nghttp2_check_header_value((const uint8_t*)S, sizeof(S) - 1) - -void test_nghttp2_check_header_value(void) -{ - uint8_t goodval[] = { 'a', '\0', 'b', 0x80u, 'c', 0xffu, 'd', '\t', ' ' }; - uint8_t badval1[] = { 'a', 0x1fu, 'b' }; - uint8_t badval2[] = { 'a', 0x7fu, 'b' }; - - CU_ASSERT(check_header_value(" !|}~")); - CU_ASSERT(check_header_value(goodval)); - CU_ASSERT(!check_header_value(badval1)); - CU_ASSERT(!check_header_value(badval2)); -} diff --git a/tests/nghttp2_helper_test.h b/tests/nghttp2_helper_test.h index 8cc6f511..c4940d2c 100644 --- a/tests/nghttp2_helper_test.h +++ b/tests/nghttp2_helper_test.h @@ -26,7 +26,5 @@ #define NGHTTP2_HELPER_TEST_H void test_nghttp2_adjust_local_window_size(void); -void test_nghttp2_check_header_name(void); -void test_nghttp2_check_header_value(void); #endif /* NGHTTP2_HELPER_TEST_H */ diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index 3028a41e..056ba7fa 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -2670,31 +2670,34 @@ void test_nghttp2_submit_invalid_nv(void) MAKE_NV("", "empty name") }; + /* Now invalid header name/value pair in HTTP/1.1 is accepted in + nghttp2 */ + memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, NULL)); /* nghttp2_submit_request */ - CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == + CU_ASSERT(0 == nghttp2_submit_request(session, NGHTTP2_PRI_DEFAULT, empty_name_nv, ARRLEN(empty_name_nv), NULL, NULL)); /* nghttp2_submit_response */ - CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == + CU_ASSERT(0 == nghttp2_submit_response(session, 2, empty_name_nv, ARRLEN(empty_name_nv), NULL)); /* nghttp2_submit_headers */ - CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == + CU_ASSERT(0 == nghttp2_submit_headers(session, NGHTTP2_FLAG_NONE, -1, NGHTTP2_PRI_DEFAULT, empty_name_nv, ARRLEN(empty_name_nv), NULL)); /* nghttp2_submit_push_promise */ - CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == + CU_ASSERT(0 == nghttp2_submit_push_promise(session, NGHTTP2_FLAG_NONE, 2, empty_name_nv, ARRLEN(empty_name_nv)));