Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
nghttp2
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
nghttp2
Commits
3ae44ef2
Commit
3ae44ef2
authored
Jan 04, 2015
by
Tatsuhiro Tsujikawa
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
nghttpd, nghttpx: Rework incoming header handling
parent
730d47f7
Changes
19
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
812 additions
and
893 deletions
+812
-893
genheaderfunc.py
genheaderfunc.py
+18
-9
src/HttpServer.cc
src/HttpServer.cc
+21
-12
src/http2.cc
src/http2.cc
+188
-289
src/http2.h
src/http2.h
+52
-64
src/http2_test.cc
src/http2_test.cc
+71
-63
src/http2_test.h
src/http2_test.h
+6
-4
src/nghttp.cc
src/nghttp.cc
+87
-54
src/shrpx-unittest.cc
src/shrpx-unittest.cc
+22
-19
src/shrpx_downstream.cc
src/shrpx_downstream.cc
+125
-141
src/shrpx_downstream.h
src/shrpx_downstream.h
+34
-43
src/shrpx_downstream_test.cc
src/shrpx_downstream_test.cc
+54
-56
src/shrpx_downstream_test.h
src/shrpx_downstream_test.h
+5
-5
src/shrpx_http2_downstream_connection.cc
src/shrpx_http2_downstream_connection.cc
+23
-19
src/shrpx_http2_session.cc
src/shrpx_http2_session.cc
+14
-16
src/shrpx_http2_upstream.cc
src/shrpx_http2_upstream.cc
+22
-26
src/shrpx_http_downstream_connection.cc
src/shrpx_http_downstream_connection.cc
+14
-17
src/shrpx_https_upstream.cc
src/shrpx_https_upstream.cc
+13
-13
src/shrpx_log.cc
src/shrpx_log.cc
+1
-1
src/shrpx_spdy_upstream.cc
src/shrpx_spdy_upstream.cc
+42
-42
No files found.
genheaderfunc.py
View file @
3ae44ef2
...
...
@@ -5,14 +5,25 @@ HEADERS = [
':method'
,
':path'
,
':scheme'
,
# disallowed h1 headers
'
connection'
,
':status'
,
'
:host'
,
# for spdy
'expect'
,
'host'
,
'if-modified-since'
,
"te"
,
"cookie"
,
"http2-settings"
,
"server"
,
"via"
,
"x-forwarded-for"
,
"x-forwarded-proto"
,
"alt-svc"
,
"content-length"
,
"location"
,
# disallowed h1 headers
'connection'
,
'keep-alive'
,
'proxy-connection'
,
'te'
,
'transfer-encoding'
,
'upgrade'
]
...
...
@@ -20,9 +31,7 @@ HEADERS = [
def
to_enum_hd
(
k
):
res
=
'HD_'
for
c
in
k
.
upper
():
if
c
==
':'
:
continue
if
c
==
'-'
:
if
c
==
':'
or
c
==
'-'
:
res
+=
'_'
continue
res
+=
c
...
...
@@ -54,7 +63,7 @@ enum {'''
def
gen_index_header
():
print
'''
\
void index_header(int *hdidx, const uint8_t *name, size_t namelen, size_t idx
) {
int lookup_token(const uint8_t *name, size_t namelen
) {
switch (namelen) {'''
b
=
build_header
(
HEADERS
)
for
size
in
sorted
(
b
.
keys
()):
...
...
@@ -70,8 +79,7 @@ void index_header(int *hdidx, const uint8_t *name, size_t namelen, size_t idx) {
for
k
in
headers
:
print
'''
\
if (util::streq("{}", name, {})) {{
hdidx[{}] = idx;
return;
return {};
}}'''
.
format
(
k
[:
-
1
],
size
-
1
,
to_enum_hd
(
k
))
print
'''
\
break;'''
...
...
@@ -80,6 +88,7 @@ void index_header(int *hdidx, const uint8_t *name, size_t namelen, size_t idx) {
break;'''
print
'''
\
}
return -1;
}'''
if
__name__
==
'__main__'
:
...
...
src/HttpServer.cc
View file @
3ae44ef2
...
...
@@ -89,9 +89,12 @@ void print_session_id(int64_t id) { std::cout << "[id=" << id << "] "; }
namespace
{
void
append_nv
(
Stream
*
stream
,
const
std
::
vector
<
nghttp2_nv
>
&
nva
)
{
size_t
idx
=
0
;
for
(
auto
&
nv
:
nva
)
{
http2
::
index_header
(
stream
->
hdidx
,
nv
.
name
,
nv
.
namelen
,
idx
++
);
for
(
size_t
i
=
0
;
i
<
nva
.
size
();
++
i
)
{
auto
&
nv
=
nva
[
i
];
auto
token
=
http2
::
lookup_token
(
nv
.
name
,
nv
.
namelen
);
if
(
token
!=
-
1
)
{
http2
::
index_header
(
stream
->
hdidx
,
token
,
i
);
}
http2
::
add_header
(
stream
->
headers
,
nv
.
name
,
nv
.
namelen
,
nv
.
value
,
nv
.
valuelen
,
nv
.
flags
&
NGHTTP2_NV_FLAG_NO_INDEX
);
}
...
...
@@ -739,7 +742,7 @@ int Http2Handler::submit_non_final_response(const std::string &status,
int
Http2Handler
::
submit_push_promise
(
Stream
*
stream
,
const
std
::
string
&
push_path
)
{
auto
authority
=
http2
::
get_header
(
stream
->
hdidx
,
http2
::
HD_AUTHORITY
,
stream
->
headers
);
http2
::
get_header
(
stream
->
hdidx
,
http2
::
HD_
_
AUTHORITY
,
stream
->
headers
);
if
(
!
authority
)
{
authority
=
...
...
@@ -900,9 +903,9 @@ void prepare_redirect_response(Stream *stream, Http2Handler *hd,
const
std
::
string
&
path
,
const
std
::
string
&
status
)
{
auto
scheme
=
http2
::
get_header
(
stream
->
hdidx
,
http2
::
HD_SCHEME
,
stream
->
headers
);
http2
::
get_header
(
stream
->
hdidx
,
http2
::
HD_
_
SCHEME
,
stream
->
headers
);
auto
authority
=
http2
::
get_header
(
stream
->
hdidx
,
http2
::
HD_AUTHORITY
,
stream
->
headers
);
http2
::
get_header
(
stream
->
hdidx
,
http2
::
HD_
_
AUTHORITY
,
stream
->
headers
);
if
(
!
authority
)
{
authority
=
http2
::
get_header
(
stream
->
hdidx
,
http2
::
HD_HOST
,
stream
->
headers
);
...
...
@@ -924,7 +927,7 @@ void prepare_response(Stream *stream, Http2Handler *hd,
bool
allow_push
=
true
)
{
int
rv
;
auto
reqpath
=
http2
::
get_header
(
stream
->
hdidx
,
http2
::
HD_PATH
,
stream
->
headers
)
->
value
;
http2
::
get_header
(
stream
->
hdidx
,
http2
::
HD_
_
PATH
,
stream
->
headers
)
->
value
;
auto
ims
=
get_header
(
stream
->
hdidx
,
http2
::
HD_IF_MODIFIED_SINCE
,
stream
->
headers
);
...
...
@@ -1038,11 +1041,12 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
return
0
;
}
if
(
namelen
>
0
&&
name
[
0
]
==
':'
)
{
auto
token
=
http2
::
lookup_token
(
name
,
namelen
);
if
(
name
[
0
]
==
':'
)
{
if
((
!
stream
->
headers
.
empty
()
&&
stream
->
headers
.
back
().
name
.
c_str
()[
0
]
!=
':'
)
||
!
http2
::
check_http2_request_pseudo_header
(
stream
->
hdidx
,
name
,
namelen
))
{
!
http2
::
check_http2_request_pseudo_header
(
stream
->
hdidx
,
token
))
{
nghttp2_submit_rst_stream
(
session
,
NGHTTP2_FLAG_NONE
,
frame
->
hd
.
stream_id
,
NGHTTP2_PROTOCOL_ERROR
);
...
...
@@ -1050,8 +1054,13 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
}
}
http2
::
index_header
(
stream
->
hdidx
,
name
,
namelen
,
stream
->
headers
.
size
());
if
(
!
http2
::
http2_header_allowed
(
token
))
{
nghttp2_submit_rst_stream
(
session
,
NGHTTP2_FLAG_NONE
,
frame
->
hd
.
stream_id
,
NGHTTP2_PROTOCOL_ERROR
);
return
NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE
;
}
http2
::
index_header
(
stream
->
hdidx
,
token
,
stream
->
headers
.
size
());
http2
::
add_header
(
stream
->
headers
,
name
,
namelen
,
value
,
valuelen
,
flags
&
NGHTTP2_NV_FLAG_NO_INDEX
);
return
0
;
...
...
@@ -1113,7 +1122,7 @@ int hd_on_frame_recv_callback(nghttp2_session *session,
if
(
frame
->
headers
.
cat
==
NGHTTP2_HCAT_REQUEST
)
{
if
(
!
http2
::
check_http2_request_headers
(
stream
->
hdidx
))
{
if
(
!
http2
::
http2_mandatory_request_headers_presence
(
stream
->
hdidx
))
{
hd
->
submit_rst_stream
(
stream
,
NGHTTP2_PROTOCOL_ERROR
);
return
0
;
}
...
...
src/http2.cc
View file @
3ae44ef2
This diff is collapsed.
Click to expand it.
src/http2.h
View file @
3ae44ef2
...
...
@@ -76,35 +76,6 @@ void sanitize_header_value(std::string &s, size_t offset);
void
copy_url_component
(
std
::
string
&
dest
,
const
http_parser_url
*
u
,
int
field
,
const
char
*
url
);
// Returns true if the header field |name| with length |namelen| bytes
// is valid for HTTP/2.
bool
check_http2_allowed_header
(
const
uint8_t
*
name
,
size_t
namelen
);
// Calls check_http2_allowed_header with |name| and strlen(name),
// assuming |name| is null-terminated string.
bool
check_http2_allowed_header
(
const
char
*
name
);
// Checks that headers |nva| do not contain disallowed header fields
// in HTTP/2 spec. This function returns true if |nva| does not
// contains such headers.
bool
check_http2_headers
(
const
Headers
&
nva
);
// Calls check_http2_headers()
bool
check_http2_request_headers
(
const
Headers
&
nva
);
// Calls check_http2_headers()
bool
check_http2_response_headers
(
const
Headers
&
nva
);
// Returns true if |name| is allowed pusedo header for request.
bool
check_http2_request_pseudo_header
(
const
uint8_t
*
name
,
size_t
namelen
);
// Returns true if |name| is allowed pusedo header for response.
bool
check_http2_response_pseudo_header
(
const
uint8_t
*
name
,
size_t
namelen
);
bool
name_less
(
const
Headers
::
value_type
&
lhs
,
const
Headers
::
value_type
&
rhs
);
void
normalize_headers
(
Headers
&
nva
);
Headers
::
value_type
to_header
(
const
uint8_t
*
name
,
size_t
namelen
,
const
uint8_t
*
value
,
size_t
valuelen
,
bool
no_index
);
...
...
@@ -115,16 +86,9 @@ Headers::value_type to_header(const uint8_t *name, size_t namelen,
void
add_header
(
Headers
&
nva
,
const
uint8_t
*
name
,
size_t
namelen
,
const
uint8_t
*
value
,
size_t
valuelen
,
bool
no_index
);
// Returns the iterator to the entry in |nva| which has name |name|
// and the |name| is uinque in the |nva|. If no such entry exist,
// returns nullptr.
const
Headers
::
value_type
*
get_unique_header
(
const
Headers
&
nva
,
const
char
*
name
);
// Returns the iterator to the entry in |nva| which has name
// |name|. If more than one entries which have the name |name|, first
// occurrence in |nva| is returned. If no such entry exist, returns
// nullptr.
// Returns pointer to the entry in |nva| which has name |name|. If
// more than one entries which have the name |name|, last occurrence
// in |nva| is returned. If no such entry exist, returns nullptr.
const
Headers
::
value_type
*
get_header
(
const
Headers
&
nva
,
const
char
*
name
);
// Returns nv->second if nv is not nullptr. Otherwise, returns "".
...
...
@@ -165,14 +129,13 @@ nghttp2_nv make_nv_ls(const char (&name)[N], const std::string &value) {
// Appends headers in |headers| to |nv|. Certain headers, including
// disallowed headers in HTTP/2 spec and headers which require
// special handling (i.e. via), are not copied.
void
copy_norm_headers_to_nva
(
std
::
vector
<
nghttp2_nv
>
&
nva
,
const
Headers
&
headers
);
void
copy_headers_to_nva
(
std
::
vector
<
nghttp2_nv
>
&
nva
,
const
Headers
&
headers
);
// Appends HTTP/1.1 style header lines to |hdrs| from headers in
// |headers|. Certain headers, which requires special handling
// (i.e. via and cookie), are not appended.
void
build_http1_headers_from_
norm_
headers
(
std
::
string
&
hdrs
,
const
Headers
&
headers
);
void
build_http1_headers_from_headers
(
std
::
string
&
hdrs
,
const
Headers
&
headers
);
// Return positive window_size_increment if WINDOW_UPDATE should be
// sent for the stream |stream_id|. If |stream_id| == 0, this function
...
...
@@ -218,43 +181,68 @@ int check_nv(const uint8_t *name, size_t namelen, const uint8_t *value,
// Returns parsed HTTP status code. Returns -1 on failure.
int
parse_http_status_code
(
const
std
::
string
&
src
);
// Header fields to be indexed, except HD_MAXIDX which is convenient
// member to get maximum value.
enum
{
HD_AUTHORITY
,
HD_METHOD
,
HD_PATH
,
HD_SCHEME
,
HD__AUTHORITY
,
HD__HOST
,
HD__METHOD
,
HD__PATH
,
HD__SCHEME
,
HD__STATUS
,
HD_ALT_SVC
,
HD_CONNECTION
,
HD_CONTENT_LENGTH
,
HD_COOKIE
,
HD_EXPECT
,
HD_HOST
,
HD_HTTP2_SETTINGS
,
HD_IF_MODIFIED_SINCE
,
HD_KEEP_ALIVE
,
HD_LOCATION
,
HD_PROXY_CONNECTION
,
HD_SERVER
,
HD_TE
,
HD_TRANSFER_ENCODING
,
HD_UPGRADE
,
HD_VIA
,
HD_X_FORWARDED_FOR
,
HD_X_FORWARDED_PROTO
,
HD_MAXIDX
,
};
// Looks up header token for header name |name| of length |namelen|.
// Only headers we are interested in are tokenized. If header name
// cannot be tokenized, returns -1.
int
lookup_token
(
const
uint8_t
*
name
,
size_t
namelen
);
int
lookup_token
(
const
std
::
string
&
name
);
// Initializes |hdidx|, header index. The |hdidx| must point to the
// array containing at least HD_MAXIDX elements.
void
init_hdidx
(
int
*
hdidx
);
// Indexes header |name| of length |namelen| using index |idx|.
void
index_header
(
int
*
hdidx
,
const
uint8_t
*
name
,
size_t
namelen
,
size_t
idx
);
// Checks pseudo header |name| of length |namelen| are unique and
// allowed for HTTP/2 request.
bool
check_http2_request_pseudo_header
(
int
*
hdidx
,
const
uint8_t
*
name
,
size_t
namelen
);
// Checks |hdidx| does not contain disallowed headers.
bool
check_http2_headers
(
int
*
hdidx
);
// Checks |hdidx| does not contain disallowed headers and contains
// mandatory headers. This funtions internally calls
// check_http2_headers().
bool
check_http2_request_headers
(
int
*
hdidx
);
// Returns header denoted by |hdkey| using index |hdidx|.
const
Headers
::
value_type
*
get_header
(
int
*
hdidx
,
int
hdkey
,
// Indexes header |token| using index |idx|.
void
index_header
(
int
*
hdidx
,
int
token
,
size_t
idx
);
// Iterates |headers| and for each element, call index_header.
void
index_headers
(
int
*
hdidx
,
const
Headers
&
headers
);
// Returns true if HTTP/2 request pseudo header |token| is not indexed
// yet and not -1.
bool
check_http2_request_pseudo_header
(
const
int
*
hdidx
,
int
token
);
// Returns true if HTTP/2 response pseudo header |token| is not
// indexed yet and not -1.
bool
check_http2_response_pseudo_header
(
const
int
*
hdidx
,
int
token
);
// Returns true if header field denoted by |token| is allowed for
// HTTP/2.
bool
http2_header_allowed
(
int
token
);
// Returns true that |hdidx| contains mandatory HTTP/2 request
// headers.
bool
http2_mandatory_request_headers_presence
(
const
int
*
hdidx
);
// Returns header denoted by |token| using index |hdidx|.
const
Headers
::
value_type
*
get_header
(
const
int
*
hdidx
,
int
token
,
const
Headers
&
nva
);
}
// namespace http2
...
...
src/http2_test.cc
View file @
3ae44ef2
...
...
@@ -100,55 +100,14 @@ void test_http2_add_header(void) {
CU_ASSERT
(
Headers
::
value_type
(
"a"
,
""
)
==
nva
[
0
]);
}
void
test_http2_check_http2_headers
(
void
)
{
auto
nva1
=
Headers
{{
"alpha"
,
"1"
},
{
"bravo"
,
"2"
},
{
"upgrade"
,
"http2"
}};
CU_ASSERT
(
!
http2
::
check_http2_headers
(
nva1
));
auto
nva2
=
Headers
{{
"connection"
,
"1"
},
{
"delta"
,
"2"
},
{
"echo"
,
"3"
}};
CU_ASSERT
(
!
http2
::
check_http2_headers
(
nva2
));
auto
nva3
=
Headers
{{
"alpha"
,
"1"
},
{
"bravo"
,
"2"
},
{
"te2"
,
"3"
}};
CU_ASSERT
(
http2
::
check_http2_headers
(
nva3
));
auto
n1
=
":authority"
;
auto
n1u8
=
reinterpret_cast
<
const
uint8_t
*>
(
n1
);
CU_ASSERT
(
http2
::
check_http2_request_pseudo_header
(
n1u8
,
strlen
(
n1
)));
CU_ASSERT
(
!
http2
::
check_http2_response_pseudo_header
(
n1u8
,
strlen
(
n1
)));
auto
n2
=
":status"
;
auto
n2u8
=
reinterpret_cast
<
const
uint8_t
*>
(
n2
);
CU_ASSERT
(
!
http2
::
check_http2_request_pseudo_header
(
n2u8
,
strlen
(
n2
)));
CU_ASSERT
(
http2
::
check_http2_response_pseudo_header
(
n2u8
,
strlen
(
n2
)));
}
void
test_http2_get_unique_header
(
void
)
{
auto
nva
=
Headers
{{
"alpha"
,
"1"
},
{
"bravo"
,
"2"
},
{
"bravo"
,
"3"
},
{
"charlie"
,
"4"
},
{
"delta"
,
"5"
},
{
"echo"
,
"6"
}};
const
Headers
::
value_type
*
rv
;
rv
=
http2
::
get_unique_header
(
nva
,
"delta"
);
CU_ASSERT
(
rv
!=
nullptr
);
CU_ASSERT
(
"delta"
==
rv
->
name
);
rv
=
http2
::
get_unique_header
(
nva
,
"bravo"
);
CU_ASSERT
(
rv
==
nullptr
);
rv
=
http2
::
get_unique_header
(
nva
,
"foxtrot"
);
CU_ASSERT
(
rv
==
nullptr
);
}
void
test_http2_get_header
(
void
)
{
auto
nva
=
Headers
{{
"alpha"
,
"1"
},
{
"bravo"
,
"2"
},
{
"bravo"
,
"3"
},
{
"charlie"
,
"4"
},
{
"delta"
,
"5"
},
{
"echo"
,
"6"
}};
{
"echo"
,
"6"
},
{
"content-length"
,
"7"
}};
const
Headers
::
value_type
*
rv
;
rv
=
http2
::
get_header
(
nva
,
"delta"
);
CU_ASSERT
(
rv
!=
nullptr
);
...
...
@@ -160,6 +119,12 @@ void test_http2_get_header(void) {
rv
=
http2
::
get_header
(
nva
,
"foxtrot"
);
CU_ASSERT
(
rv
==
nullptr
);
int
hdidx
[
http2
::
HD_MAXIDX
];
http2
::
init_hdidx
(
hdidx
);
hdidx
[
http2
::
HD_CONTENT_LENGTH
]
=
6
;
rv
=
http2
::
get_header
(
hdidx
,
http2
::
HD_CONTENT_LENGTH
,
nva
);
CU_ASSERT
(
"content-length"
==
rv
->
name
);
}
namespace
{
...
...
@@ -178,11 +143,11 @@ auto headers = Headers{{"alpha", "0", true},
{
"zulu"
,
"12"
}};
}
// namespace
void
test_http2_copy_
norm_
headers_to_nva
(
void
)
{
void
test_http2_copy_headers_to_nva
(
void
)
{
std
::
vector
<
nghttp2_nv
>
nva
;
http2
::
copy_
norm_
headers_to_nva
(
nva
,
headers
);
CU_ASSERT
(
7
==
nva
.
size
());
auto
ans
=
std
::
vector
<
int
>
{
0
,
1
,
4
,
5
,
6
,
7
,
12
};
http2
::
copy_headers_to_nva
(
nva
,
headers
);
CU_ASSERT
(
9
==
nva
.
size
());
auto
ans
=
std
::
vector
<
int
>
{
0
,
1
,
4
,
5
,
6
,
7
,
8
,
9
,
12
};
for
(
size_t
i
=
0
;
i
<
ans
.
size
();
++
i
)
{
check_nv
(
headers
[
ans
[
i
]],
&
nva
[
i
]);
...
...
@@ -194,9 +159,9 @@ void test_http2_copy_norm_headers_to_nva(void) {
}
}
void
test_http2_build_http1_headers_from_
norm_
headers
(
void
)
{
void
test_http2_build_http1_headers_from_headers
(
void
)
{
std
::
string
hdrs
;
http2
::
build_http1_headers_from_
norm_
headers
(
hdrs
,
headers
);
http2
::
build_http1_headers_from_headers
(
hdrs
,
headers
);
CU_ASSERT
(
hdrs
==
"Alpha: 0
\r\n
"
"Bravo: 1
\r\n
"
"Delta: 4
\r\n
"
...
...
@@ -206,15 +171,6 @@ void test_http2_build_http1_headers_from_norm_headers(void) {
"Te: 8
\r\n
"
"Te: 9
\r\n
"
"Zulu: 12
\r\n
"
);
hdrs
.
clear
();
// Both nghttp2 and spdylay do not allow \r and \n in header value
// now.
// auto hd2 = std::vector<std::pair<std::string, std::string>>
// {{"alpha", "bravo\r\ncharlie\r\n"}};
// http2::build_http1_headers_from_norm_headers(hdrs, hd2);
// CU_ASSERT(hdrs == "Alpha: bravo charlie \r\n");
}
void
test_http2_lws
(
void
)
{
...
...
@@ -274,12 +230,64 @@ void test_http2_index_header(void) {
int
hdidx
[
http2
::
HD_MAXIDX
];
http2
::
init_hdidx
(
hdidx
);
http2
::
index_header
(
hdidx
,
reinterpret_cast
<
const
uint8_t
*>
(
":authority"
),
10
,
0
);
http2
::
index_header
(
hdidx
,
reinterpret_cast
<
const
uint8_t
*>
(
"hos"
),
3
,
1
);
http2
::
index_header
(
hdidx
,
http2
::
HD__AUTHORITY
,
0
);
http2
::
index_header
(
hdidx
,
-
1
,
1
);
CU_ASSERT
(
0
==
hdidx
[
http2
::
HD__AUTHORITY
]);
}
void
test_http2_lookup_token
(
void
)
{
CU_ASSERT
(
http2
::
HD__AUTHORITY
==
http2
::
lookup_token
(
":authority"
));
CU_ASSERT
(
-
1
==
http2
::
lookup_token
(
":authorit"
));
CU_ASSERT
(
-
1
==
http2
::
lookup_token
(
":Authority"
));
CU_ASSERT
(
http2
::
HD_EXPECT
==
http2
::
lookup_token
(
"expect"
));
}
void
test_http2_check_http2_pseudo_header
(
void
)
{
int
hdidx
[
http2
::
HD_MAXIDX
];
http2
::
init_hdidx
(
hdidx
);
CU_ASSERT
(
http2
::
check_http2_request_pseudo_header
(
hdidx
,
http2
::
HD__METHOD
));
hdidx
[
http2
::
HD__PATH
]
=
0
;
CU_ASSERT
(
http2
::
check_http2_request_pseudo_header
(
hdidx
,
http2
::
HD__METHOD
));
hdidx
[
http2
::
HD__METHOD
]
=
1
;
CU_ASSERT
(
!
http2
::
check_http2_request_pseudo_header
(
hdidx
,
http2
::
HD__METHOD
));
CU_ASSERT
(
!
http2
::
check_http2_request_pseudo_header
(
hdidx
,
http2
::
HD_VIA
));
http2
::
init_hdidx
(
hdidx
);
CU_ASSERT
(
http2
::
check_http2_response_pseudo_header
(
hdidx
,
http2
::
HD__STATUS
));
hdidx
[
http2
::
HD__STATUS
]
=
0
;
CU_ASSERT
(
!
http2
::
check_http2_response_pseudo_header
(
hdidx
,
http2
::
HD__STATUS
));
CU_ASSERT
(
!
http2
::
check_http2_response_pseudo_header
(
hdidx
,
http2
::
HD_VIA
));
}
void
test_http2_http2_header_allowed
(
void
)
{
CU_ASSERT
(
http2
::
http2_header_allowed
(
http2
::
HD__PATH
));
CU_ASSERT
(
http2
::
http2_header_allowed
(
http2
::
HD_CONTENT_LENGTH
));
CU_ASSERT
(
!
http2
::
http2_header_allowed
(
http2
::
HD_CONNECTION
));
}
void
test_http2_mandatory_request_headers_presence
(
void
)
{
int
hdidx
[
http2
::
HD_MAXIDX
];
http2
::
init_hdidx
(
hdidx
);
CU_ASSERT
(
0
==
hdidx
[
http2
::
HD_AUTHORITY
]);
CU_ASSERT
(
-
1
==
hdidx
[
http2
::
HD_HOST
]);
CU_ASSERT
(
!
http2
::
http2_mandatory_request_headers_presence
(
hdidx
));
hdidx
[
http2
::
HD__AUTHORITY
]
=
0
;
CU_ASSERT
(
!
http2
::
http2_mandatory_request_headers_presence
(
hdidx
));
hdidx
[
http2
::
HD__METHOD
]
=
1
;
CU_ASSERT
(
!
http2
::
http2_mandatory_request_headers_presence
(
hdidx
));
hdidx
[
http2
::
HD__PATH
]
=
2
;
CU_ASSERT
(
!
http2
::
http2_mandatory_request_headers_presence
(
hdidx
));
hdidx
[
http2
::
HD__SCHEME
]
=
3
;
CU_ASSERT
(
http2
::
http2_mandatory_request_headers_presence
(
hdidx
));
hdidx
[
http2
::
HD__AUTHORITY
]
=
-
1
;
hdidx
[
http2
::
HD_HOST
]
=
0
;
CU_ASSERT
(
http2
::
http2_mandatory_request_headers_presence
(
hdidx
));
}
}
// namespace shrpx
src/http2_test.h
View file @
3ae44ef2
...
...
@@ -28,15 +28,17 @@
namespace
shrpx
{
void
test_http2_add_header
(
void
);
void
test_http2_check_http2_headers
(
void
);
void
test_http2_get_unique_header
(
void
);
void
test_http2_get_header
(
void
);
void
test_http2_copy_
norm_
headers_to_nva
(
void
);
void
test_http2_build_http1_headers_from_
norm_
headers
(
void
);
void
test_http2_copy_headers_to_nva
(
void
);
void
test_http2_build_http1_headers_from_headers
(
void
);
void
test_http2_lws
(
void
);
void
test_http2_rewrite_location_uri
(
void
);
void
test_http2_parse_http_status_code
(
void
);
void
test_http2_index_header
(
void
);
void
test_http2_lookup_token
(
void
);
void
test_http2_check_http2_pseudo_header
(
void
);
void
test_http2_http2_header_allowed
(
void
);
void
test_http2_mandatory_request_headers_presence
(
void
);
}
// namespace shrpx
...
...
src/nghttp.cc
View file @
3ae44ef2
...
...
@@ -224,6 +224,9 @@ struct Request {
int
level
;
// RequestPriority value defined in HtmlParser.h
int
pri
;
int
res_hdidx
[
http2
::
HD_MAXIDX
];
// used for incoming PUSH_PROMISE
int
req_hdidx
[
http2
::
HD_MAXIDX
];
bool
expect_final_response
;
// For pushed request, |uri| is empty and |u| is zero-cleared.
...
...
@@ -235,7 +238,10 @@ struct Request {
data_length
(
data_length
),
data_offset
(
0
),
response_len
(
0
),
inflater
(
nullptr
),
html_parser
(
nullptr
),
data_prd
(
data_prd
),
stream_id
(
-
1
),
status
(
0
),
level
(
level
),
pri
(
pri
),
expect_final_response
(
false
)
{}
expect_final_response
(
false
)
{
http2
::
init_hdidx
(
res_hdidx
);
http2
::
init_hdidx
(
req_hdidx
);
}
~
Request
()
{
nghttp2_gzip_inflate_del
(
inflater
);
...
...
@@ -354,12 +360,47 @@ struct Request {
}
}
bool
response_pseudo_header_allowed
()
const
{
return
res_nva
.
empty
()
||
res_nva
.
back
().
name
.
c_str
()[
0
]
==
':'
;
bool
response_pseudo_header_allowed
(
int
token
)
const
{
if
(
!
res_nva
.
empty
()
&&
res_nva
.
back
().
name
.
c_str
()[
0
]
!=
':'
)
{
return
false
;
}
switch
(
token
)
{
case
http2
:
:
HD__STATUS
:
return
res_hdidx
[
token
]
==
-
1
;
default:
return
false
;
}
}
bool
push_request_pseudo_header_allowed
(
int
token
)
const
{
if
(
!
req_nva
.
empty
()
&&
req_nva
.
back
().
name
.
c_str
()[
0
]
!=
':'
)
{
return
false
;
}
switch
(
token
)
{
case
http2
:
:
HD__AUTHORITY
:
case
http2
:
:
HD__METHOD
:
case
http2
:
:
HD__PATH
:
case
http2
:
:
HD__SCHEME
:
return
req_hdidx
[
token
]
==
-
1
;
default:
return
false
;
}
}
Headers
::
value_type
*
get_res_header
(
int
token
)
{
auto
idx
=
res_hdidx
[
token
];
if
(
idx
==
-
1
)
{
return
nullptr
;
}
return
&
res_nva
[
idx
];
}
bool
push_request_pseudo_header_allowed
()
const
{
return
res_nva
.
empty
()
||
req_nva
.
back
().
name
.
c_str
()[
0
]
==
':'
;
Headers
::
value_type
*
get_req_header
(
int
token
)
{
auto
idx
=
req_hdidx
[
token
];
if
(
idx
==
-
1
)
{
return
nullptr
;
}
return
&
req_nva
[
idx
];
}
void
record_request_time
()
{
...
...
@@ -1537,8 +1578,6 @@ int submit_request(HttpClient *client, const Headers &headers, Request *req) {
build_headers
.
emplace_back
(
kv
.
name
,
kv
.
value
,
kv
.
no_index
);
}
std
::
stable_sort
(
std
::
begin
(
build_headers
),
std
::
end
(
build_headers
),
http2
::
name_less
);
auto
nva
=
std
::
vector
<
nghttp2_nv
>
();
nva
.
reserve
(
build_headers
.
size
());
...
...
@@ -1690,32 +1729,31 @@ void check_response_header(nghttp2_session *session, Request *req) {
req
->
expect_final_response
=
false
;
for
(
auto
&
nv
:
req
->
res_nva
)
{
if
(
"content-encoding"
==
nv
.
name
)
{
gzip
=
util
::
strieq
(
"gzip"
,
nv
.
value
)
||
util
::
strieq
(
"deflate"
,
nv
.
value
);
continue
;
}
if
(
":status"
==
nv
.
name
)
{
int
status
;
if
(
req
->
status
!=
0
||
(
status
=
http2
::
parse_http_status_code
(
nv
.
value
))
==
-
1
)
{
nghttp2_submit_rst_stream
(
session
,
NGHTTP2_FLAG_NONE
,
req
->
stream_id
,
NGHTTP2_PROTOCOL_ERROR
);
return
;
}
auto
status_hd
=
req
->
get_res_header
(
http2
::
HD__STATUS
);
req
->
status
=
status
;
}
if
(
!
status_hd
)
{
nghttp2_submit_rst_stream
(
session
,
NGHTTP2_FLAG_NONE
,
req
->
stream_id
,
NGHTTP2_PROTOCOL_ERROR
);
return
;
}
if
(
req
->
status
==
0
)
{
auto
status
=
http2
::
parse_http_status_code
(
status_hd
->
value
);
if
(
status
==
-
1
)
{
nghttp2_submit_rst_stream
(
session
,
NGHTTP2_FLAG_NONE
,
req
->
stream_id
,
NGHTTP2_PROTOCOL_ERROR
);
return
;
}
req
->
status
=
status
;
for
(
auto
&
nv
:
req
->
res_nva
)
{
if
(
"content-encoding"
==
nv
.
name
)
{
gzip
=
util
::
strieq
(
"gzip"
,
nv
.
value
)
||
util
::
strieq
(
"deflate"
,
nv
.
value
);
continue
;
}
}
if
(
req
->
status
/
100
==
1
)
{
req
->
expect_final_response
=
true
;
req
->
status
=
0
;
...
...
@@ -1797,15 +1835,17 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
break
;
}
if
(
namelen
>
0
&&
name
[
0
]
==
':'
)
{
if
(
!
req
->
response_pseudo_header_allowed
()
||
!
http2
::
check_http2_response_pseudo_header
(
name
,
namelen
))
{
auto
token
=
http2
::
lookup_token
(
name
,
namelen
);
if
(
name
[
0
]
==
':'
)
{
if
(
!
req
->
response_pseudo_header_allowed
(
token
))
{
nghttp2_submit_rst_stream
(
session
,
NGHTTP2_FLAG_NONE
,
frame
->
hd
.
stream_id
,
NGHTTP2_PROTOCOL_ERROR
);
return
NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE
;
}
}
http2
::
index_header
(
req
->
res_hdidx
,
token
,
req
->
res_nva
.
size
());
http2
::
add_header
(
req
->
res_nva
,
name
,
namelen
,
value
,
valuelen
,
flags
&
NGHTTP2_NV_FLAG_NO_INDEX
);
break
;
...
...
@@ -1818,9 +1858,10 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
break
;
}
if
(
namelen
>
0
&&
name
[
0
]
==
':'
)
{
if
(
!
req
->
push_request_pseudo_header_allowed
()
||
!
http2
::
check_http2_request_pseudo_header
(
name
,
namelen
))
{
auto
token
=
http2
::
lookup_token
(
name
,
namelen
);
if
(
name
[
0
]
==
':'
)
{
if
(
!
req
->
push_request_pseudo_header_allowed
(
token
))
{
nghttp2_submit_rst_stream
(
session
,
NGHTTP2_FLAG_NONE
,
frame
->
push_promise
.
promised_stream_id
,
NGHTTP2_PROTOCOL_ERROR
);
...
...
@@ -1828,6 +1869,7 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
}
}
http2
::
index_header
(
req
->
req_hdidx
,
token
,
req
->
req_nva
.
size
());
http2
::
add_header
(
req
->
req_nva
,
name
,
namelen
,
value
,
valuelen
,
flags
&
NGHTTP2_NV_FLAG_NO_INDEX
);
break
;
...
...
@@ -1895,36 +1937,27 @@ int on_frame_recv_callback2(nghttp2_session *session,
if
(
!
req
)
{
break
;
}
std
::
string
scheme
,
authority
,
method
,
path
;
for
(
auto
&
nv
:
req
->
req_nva
)
{
if
(
nv
.
name
==
":scheme"
)
{
scheme
=
nv
.
value
;
continue
;
}
if
(
nv
.
name
==
":authority"
||
nv
.
name
==
"host"
)
{
authority
=
nv
.
value
;
continue
;
}
if
(
nv
.
name
==
":method"
)
{
method
=
nv
.
value
;
continue
;
}
if
(
nv
.
name
==
":path"
)
{
path
=
nv
.
value
;
continue
;
}
auto
scheme
=
req
->
get_req_header
(
http2
::
HD__SCHEME
);
auto
authority
=
req
->
get_req_header
(
http2
::
HD__AUTHORITY
);
auto
method
=
req
->
get_req_header
(
http2
::
HD__METHOD
);
auto
path
=
req
->
get_req_header
(
http2
::
HD__PATH
);
if
(
!
authority
)
{
authority
=
req
->
get_req_header
(
http2
::
HD_HOST
);
}
if
(
scheme
.
empty
()
||
authority
.
empty
()
||
method
.
empty
()
||
path
.
empty
()
||
path
[
0
]
!=
'/'
)
{
if
(
!
scheme
||
!
authority
||
!
method
||
!
path
||
scheme
->
value
.
empty
()
||
authority
->
value
.
empty
()
||
method
->
value
.
empty
()
||
path
->
value
.
empty
()
||
path
->
value
[
0
]
!=
'/'
)
{
nghttp2_submit_rst_stream
(
session
,
NGHTTP2_FLAG_NONE
,
frame
->
push_promise
.
promised_stream_id
,
NGHTTP2_PROTOCOL_ERROR
);
break
;
}
std
::
string
uri
=
scheme
;
std
::
string
uri
=
scheme
->
value
;
uri
+=
"://"
;
uri
+=
authority
;
uri
+=
path
;
uri
+=
authority
->
value
;
uri
+=
path
->
value
;
http_parser_url
u
;
memset
(
&
u
,
0
,
sizeof
(
u
));
if
(
http_parser_parse_url
(
uri
.
c_str
(),
uri
.
size
(),
0
,
&
u
)
!=
0
)
{
...
...
src/shrpx-unittest.cc
View file @
3ae44ef2
...
...
@@ -72,15 +72,11 @@ int main(int argc, char *argv[]) {
!
CU_add_test
(
pSuite
,
"ssl_cert_lookup_tree_add_cert_from_file"
,
shrpx
::
test_shrpx_ssl_cert_lookup_tree_add_cert_from_file
)
||
!
CU_add_test
(
pSuite
,
"http2_add_header"
,
shrpx
::
test_http2_add_header
)
||
!
CU_add_test
(
pSuite
,
"http2_check_http2_headers"
,
shrpx
::
test_http2_check_http2_headers
)
||
!
CU_add_test
(
pSuite
,
"http2_get_unique_header"
,
shrpx
::
test_http2_get_unique_header
)
||
!
CU_add_test
(
pSuite
,
"http2_get_header"
,
shrpx
::
test_http2_get_header
)
||
!
CU_add_test
(
pSuite
,
"http2_copy_
norm_
headers_to_nva"
,
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_copy_headers_to_nva"
,
shrpx
::
test_http2_copy_headers_to_nva
)
||
!
CU_add_test
(
pSuite
,
"http2_build_http1_headers_from_headers"
,
shrpx
::
test_http2_build_http1_headers_from_headers
)
||
!
CU_add_test
(
pSuite
,
"http2_lws"
,
shrpx
::
test_http2_lws
)
||
!
CU_add_test
(
pSuite
,
"http2_rewrite_location_uri"
,
shrpx
::
test_http2_rewrite_location_uri
)
||
...
...
@@ -88,21 +84,28 @@ int main(int argc, char *argv[]) {
shrpx
::
test_http2_parse_http_status_code
)
||
!
CU_add_test
(
pSuite
,
"http2_index_header"
,
shrpx
::
test_http2_index_header
)
||
!
CU_add_test
(
pSuite
,
"downstream_normalize_request_headers"
,
shrpx
::
test_downstream_normalize_request_headers
)
||
!
CU_add_test
(
pSuite
,
"downstream_normalize_response_headers"
,
shrpx
::
test_downstream_normalize_response_headers
)
||
!
CU_add_test
(
pSuite
,
"downstream_get_norm_request_header"
,
shrpx
::
test_downstream_get_norm_request_header
)
||
!
CU_add_test
(
pSuite
,
"downstream_get_norm_response_header"
,
shrpx
::
test_downstream_get_norm_response_header
)
||
!
CU_add_test
(
pSuite
,
"http2_lookup_token"
,
shrpx
::
test_http2_lookup_token
)
||
!
CU_add_test
(
pSuite
,
"http2_check_http2_pseudo_header"
,
shrpx
::
test_http2_check_http2_pseudo_header
)
||
!
CU_add_test
(
pSuite
,
"http2_http2_header_allowed"
,
shrpx
::
test_http2_http2_header_allowed
)
||
!
CU_add_test
(
pSuite
,
"http2_mandatory_request_headers_presence"
,
shrpx
::
test_http2_mandatory_request_headers_presence
)
||
!
CU_add_test
(
pSuite
,
"downstream_index_request_headers"
,
shrpx
::
test_downstream_index_request_headers
)
||
!
CU_add_test
(
pSuite
,
"downstream_index_response_headers"
,
shrpx
::
test_downstream_index_response_headers
)
||
!
CU_add_test
(
pSuite
,
"downstream_get_request_header"
,
shrpx
::
test_downstream_get_request_header
)
||
!
CU_add_test
(
pSuite
,
"downstream_get_response_header"
,
shrpx
::
test_downstream_get_response_header
)
||
!
CU_add_test
(
pSuite
,
"downstream_crumble_request_cookie"
,
shrpx
::
test_downstream_crumble_request_cookie
)
||
!
CU_add_test
(
pSuite
,
"downstream_assemble_request_cookie"
,
shrpx
::
test_downstream_assemble_request_cookie
)
||
!
CU_add_test
(
pSuite
,
"downstream_rewrite_norm_location_response_header"
,
shrpx
::
test_downstream_rewrite_norm_location_response_header
)
||
!
CU_add_test
(
pSuite
,
"downstream_rewrite_location_response_header"
,
shrpx
::
test_downstream_rewrite_location_response_header
)
||
!
CU_add_test
(
pSuite
,
"config_parse_config_str_list"
,
shrpx
::
test_shrpx_config_parse_config_str_list
)
||
!
CU_add_test
(
pSuite
,
"config_parse_header"
,
...
...
src/shrpx_downstream.cc
View file @
3ae44ef2
This diff is collapsed.
Click to expand it.
src/shrpx_downstream.h
View file @
3ae44ef2
...
...
@@ -95,30 +95,27 @@ public:
const
std
::
string
&
get_http2_settings
()
const
;
// downstream request API
const
Headers
&
get_request_headers
()
const
;
void
crumble_request_cookie
();
// Crumbles (split cookie by ";") in request_headers_ and returns
// them. Headers::no_index is inherited.
Headers
crumble_request_cookie
();
void
assemble_request_cookie
();
const
std
::
string
&
get_assembled_request_cookie
()
const
;
// Makes key lowercase and sort headers by name using <
void
normalize_request_headers
();
// Returns iterator pointing to the request header with the name
// |name|. If multiple header have |name| as name, return first
// occurrence from the beginning. If no such header is found,
// returns std::end(get_request_headers()). This function must be
// called after calling normalize_request_headers().
Headers
::
const_iterator
get_norm_request_header
(
const
std
::
string
&
name
)
const
;
// Returns iterator pointing to the request header with the name
// |name|. This function acts like get_norm_request_header(), but
// if request_headers_ was not normalized, use linear search to find
// the header. Otherwise, get_norm_request_header() is used.
Headers
::
const_iterator
get_request_header
(
const
std
::
string
&
name
)
const
;
bool
get_request_headers_normalized
()
const
;
// Lower the request header field names and indexes request headers
void
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.
// This function must be called after headers are indexed
const
Headers
::
value_type
*
get_request_header
(
int
token
)
const
;
// Returns pointer to the request header with the name |name|. If
// no such header is found, returns nullptr.
const
Headers
::
value_type
*
get_request_header
(
const
std
::
string
&
name
)
const
;
void
add_request_header
(
std
::
string
name
,
std
::
string
value
);
void
set_last_request_header_value
(
std
::
string
value
);
void
split_
add_request_header
(
const
uint8_t
*
name
,
size_t
namelen
,
const
uint8_t
*
value
,
size_t
valuelen
,
bool
no_index
);
void
add_request_header
(
const
uint8_t
*
name
,
size_t
namelen
,
const
uint8_t
*
value
,
size_t
valuelen
,
bool
no_index
,
int
token
);
bool
get_request_header_key_prev
()
const
;
void
append_last_request_header_key
(
const
char
*
data
,
size_t
len
);
...
...
@@ -161,7 +158,7 @@ public:
size_t
get_request_datalen
()
const
;
void
dec_request_datalen
(
size_t
len
);
void
reset_request_datalen
();
bool
request_pseudo_header_allowed
()
const
;
bool
request_pseudo_header_allowed
(
int
token
)
const
;
bool
expect_response_body
()
const
;
enum
{
INITIAL
,
...
...
@@ -177,26 +174,22 @@ public:
Memchunks4K
*
get_request_buf
();
// downstream response API
const
Headers
&
get_response_headers
()
const
;
// Makes key lowercase and sort headers by name using <
void
normalize_response_headers
();
// Returns iterator pointing to the response header with the name
// |name|. If multiple header have |name| as name, return first
// occurrence from the beginning. If no such header is found,
// returns std::end(get_response_headers()). This function must be
// called after calling normalize_response_headers().
Headers
::
const_iterator
get_norm_response_header
(
const
std
::
string
&
name
)
const
;
// Rewrites the location response header field. This function must
// be called after calling normalize_response_headers() and
// normalize_request_headers().
void
rewrite_norm_location_response_header
(
const
std
::
string
&
upstream_scheme
,
uint16_t
upstream_port
);
// Lower the response header field names and indexes response headers
void
index_response_headers
();
// Returns pointer to the response 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.
// This function must be called after response headers are indexed.
const
Headers
::
value_type
*
get_response_header
(
int
token
)
const
;
// Rewrites the location response header field.
void
rewrite_location_response_header
(
const
std
::
string
&
upstream_scheme
,
uint16_t
upstream_port
);
void
add_response_header
(
std
::
string
name
,
std
::
string
value
);
void
set_last_response_header_value
(
std
::
string
value
);
void
split_
add_response_header
(
const
uint8_t
*
name
,
size_t
namelen
,
const
uint8_t
*
value
,
size_t
valuelen
,
bool
no_index
);
void
add_response_header
(
const
uint8_t
*
name
,
size_t
namelen
,
const
uint8_t
*
value
,
size_t
valuelen
,
bool
no_index
,
int
token
);
bool
get_response_header_key_prev
()
const
;
void
append_last_response_header_key
(
const
char
*
data
,
size_t
len
);
...
...
@@ -238,7 +231,7 @@ public:
void
dec_response_datalen
(
size_t
len
);
size_t
get_response_datalen
()
const
;
void
reset_response_datalen
();
bool
response_pseudo_header_allowed
()
const
;
bool
response_pseudo_header_allowed
(
int
token
)
const
;
// Call this method when there is incoming data in downstream
// connection.
...
...
@@ -298,7 +291,6 @@ private:
std
::
string
request_http2_authority_
;
std
::
chrono
::
high_resolution_clock
::
time_point
request_start_time_
;
std
::
string
assembled_request_cookie_
;
std
::
string
http2_settings_
;
Memchunks4K
request_buf_
;
Memchunks4K
response_buf_
;
...
...
@@ -343,6 +335,9 @@ private:
int
response_major_
;
int
response_minor_
;
int
request_hdidx_
[
http2
::
HD_MAXIDX
];
int
response_hdidx_
[
http2
::
HD_MAXIDX
];
// true if the request contains upgrade token (HTTP Upgrade or
// CONNECT)
bool
upgrade_request_
;
...
...
@@ -350,7 +345,6 @@ private:
bool
upgraded_
;
bool
http2_upgrade_seen_
;
bool
http2_settings_seen_
;
bool
chunked_request_
;
bool
request_connection_close_
;
...
...
@@ -362,9 +356,6 @@ private:
bool
response_header_key_prev_
;
bool
expect_final_response_
;
// true if request_headers_ is normalized
bool
request_headers_normalized_
;
bool
use_timer_
;
};
...
...
src/shrpx_downstream_test.cc
View file @
3ae44ef2
...
...
@@ -32,7 +32,7 @@
namespace
shrpx
{
void
test_downstream_
normalize
_request_headers
(
void
)
{
void
test_downstream_
index
_request_headers
(
void
)
{
Downstream
d
(
nullptr
,
0
,
0
);
d
.
add_request_header
(
"1"
,
"0"
);
d
.
add_request_header
(
"2"
,
"1"
);
...
...
@@ -42,88 +42,83 @@ void test_downstream_normalize_request_headers(void) {
d
.
add_request_header
(
"BravO"
,
"5"
);
d
.
add_request_header
(
":method"
,
"6"
);
d
.
add_request_header
(
":authority"
,
"7"
);
d
.
normalize
_request_headers
();
d
.
index
_request_headers
();
auto
ans
=
Headers
{{
":authority"
,
"7"
},
{
":method"
,
"6"
},
{
"1"
,
"0"
},
auto
ans
=
Headers
{{
"1"
,
"0"
},
{
"2"
,
"1"
},
{
"charlie"
,
"2"
},
{
"alpha"
,
"3"
},
{
"delta"
,
"4"
},
{
"bravo"
,
"5"
},
{
"
charlie"
,
"2
"
},
{
"
delta"
,
"4
"
}};
{
"
:method"
,
"6
"
},
{
"
:authority"
,
"7
"
}};
CU_ASSERT
(
ans
==
d
.
get_request_headers
());
}
void
test_downstream_
normalize
_response_headers
(
void
)
{
void
test_downstream_
index
_response_headers
(
void
)
{
Downstream
d
(
nullptr
,
0
,
0
);
d
.
add_response_header
(
"Charlie"
,
"0"
);
d
.
add_response_header
(
"Alpha"
,
"1"
);
d
.
add_response_header
(
"Delta"
,
"2"
);
d
.
add_response_header
(
"BravO"
,
"3"
);
d
.
normalize
_response_headers
();
d
.
index
_response_headers
();
auto
ans
=
Headers
{{
"
alpha"
,
"1"
},
{
"bravo"
,
"3"
},
{
"charlie"
,
"0"
},
{
"delta"
,
"2
"
}};
Headers
{{
"
charlie"
,
"0"
},
{
"alpha"
,
"1"
},
{
"delta"
,
"2"
},
{
"bravo"
,
"3
"
}};
CU_ASSERT
(
ans
==
d
.
get_response_headers
());
}
void
test_downstream_get_
norm_
request_header
(
void
)
{
void
test_downstream_get_request_header
(
void
)
{
Downstream
d
(
nullptr
,
0
,
0
);
d
.
add_request_header
(
"alpha"
,
"0"
);
d
.
add_request_header
(
"bravo"
,
"1"
);
d
.
add_request_header
(
"bravo"
,
"2"
);
d
.
add_request_header
(
"charlie"
,
"3"
);
d
.
add_request_header
(
"delta"
,
"4"
);
d
.
add_request_header
(
"echo"
,
"5"
);
auto
i
=
d
.
get_norm_request_header
(
"alpha"
);
CU_ASSERT
(
Header
(
"alpha"
,
"0"
)
==
*
i
);
i
=
d
.
get_norm_request_header
(
"bravo"
);
CU_ASSERT
(
Header
(
"bravo"
,
"1"
)
==
*
i
);
i
=
d
.
get_norm_request_header
(
"delta"
);
CU_ASSERT
(
Header
(
"delta"
,
"4"
)
==
*
i
);
i
=
d
.
get_norm_request_header
(
"echo"
);
CU_ASSERT
(
Header
(
"echo"
,
"5"
)
==
*
i
);
i
=
d
.
get_norm_request_header
(
"foxtrot"
);
CU_ASSERT
(
i
==
std
::
end
(
d
.
get_request_headers
()));
d
.
add_request_header
(
":authority"
,
"1"
);
d
.
add_request_header
(
"content-length"
,
"2"
);
d
.
index_request_headers
();
// By token
CU_ASSERT
(
Header
(
":authority"
,
"1"
)
==
*
d
.
get_request_header
(
http2
::
HD__AUTHORITY
));
CU_ASSERT
(
nullptr
==
d
.
get_request_header
(
http2
::
HD__METHOD
));
// By name
CU_ASSERT
(
Header
(
"alpha"
,
"0"
)
==
*
d
.
get_request_header
(
"alpha"
));
CU_ASSERT
(
nullptr
==
d
.
get_request_header
(
"bravo"
));
}
void
test_downstream_get_
norm_
response_header
(
void
)
{
void
test_downstream_get_response_header
(
void
)
{
Downstream
d
(
nullptr
,
0
,
0
);
d
.
add_response_header
(
"alpha"
,
"0"
);
d
.
add_response_header
(
"bravo"
,
"1"
);
d
.
add_response_header
(
"bravo"
,
"2"
);
d
.
add_response_header
(
"charlie"
,
"3"
);
d
.
add_response_header
(
"delta"
,
"4"
);
d
.
add_response_header
(
"echo"
,
"5"
);
auto
i
=
d
.
get_norm_response_header
(
"alpha"
);
CU_ASSERT
(
Header
(
"alpha"
,
"0"
)
==
*
i
);
i
=
d
.
get_norm_response_header
(
"bravo"
);
CU_ASSERT
(
Header
(
"bravo"
,
"1"
)
==
*
i
);
i
=
d
.
get_norm_response_header
(
"delta"
);
CU_ASSERT
(
Header
(
"delta"
,
"4"
)
==
*
i
);
i
=
d
.
get_norm_response_header
(
"echo"
);
CU_ASSERT
(
Header
(
"echo"
,
"5"
)
==
*
i
);
i
=
d
.
get_norm_response_header
(
"foxtrot"
);
CU_ASSERT
(
i
==
std
::
end
(
d
.
get_response_headers
()));
d
.
add_response_header
(
":status"
,
"1"
);
d
.
add_response_header
(
"content-length"
,
"2"
);
d
.
index_response_headers
();
// By token
CU_ASSERT
(
Header
(
":status"
,
"1"
)
==
*
d
.
get_response_header
(
http2
::
HD__STATUS
));
CU_ASSERT
(
nullptr
==
d
.
get_response_header
(
http2
::
HD__METHOD
));
}
void
test_downstream_crumble_request_cookie
(
void
)
{
Downstream
d
(
nullptr
,
0
,
0
);
d
.
add_request_header
(
":method"
,
"get"
);
d
.
add_request_header
(
":path"
,
"/"
);
d
.
add_request_header
(
"cookie"
,
"alpha; bravo; ; ;; charlie;;"
);
auto
val
=
"alpha; bravo; ; ;; charlie;;"
;
d
.
add_request_header
(
reinterpret_cast
<
const
uint8_t
*>
(
"cookie"
),
sizeof
(
"cookie"
)
-
1
,
reinterpret_cast
<
const
uint8_t
*>
(
val
),
strlen
(
val
),
true
,
-
1
);
d
.
add_request_header
(
"cookie"
,
";delta"
);
d
.
add_request_header
(
"cookie"
,
"echo"
);
d
.
crumble_request_cookie
();
Headers
ans
=
{{
":method"
,
"get"
},
{
":path"
,
"/"
},
{
"cookie"
,
"alpha"
},
{
"cookie"
,
"delta"
},
{
"cookie"
,
"echo"
},
auto
cookies
=
d
.
crumble_request_cookie
();
Headers
ans
=
{{
"cookie"
,
"alpha"
},
{
"cookie"
,
"bravo"
},
{
"cookie"
,
"charlie"
}};
CU_ASSERT
(
ans
==
d
.
get_request_headers
());
{
"cookie"
,
"charlie"
},
{
"cookie"
,
"delta"
},
{
"cookie"
,
"echo"
}};
CU_ASSERT
(
ans
==
cookies
);
CU_ASSERT
(
cookies
[
0
].
no_index
);
CU_ASSERT
(
cookies
[
1
].
no_index
);
CU_ASSERT
(
cookies
[
2
].
no_index
);
}
void
test_downstream_assemble_request_cookie
(
void
)
{
...
...
@@ -138,21 +133,24 @@ void test_downstream_assemble_request_cookie(void) {
CU_ASSERT
(
"alpha; bravo; charlie; delta"
==
d
.
get_assembled_request_cookie
());
}
void
test_downstream_rewrite_
norm_
location_response_header
(
void
)
{
void
test_downstream_rewrite_location_response_header
(
void
)
{
{
Downstream
d
(
nullptr
,
0
,
0
);
d
.
add_request_header
(
"host"
,
"localhost:3000"
);
d
.
add_response_header
(
"location"
,
"http://localhost:3000/"
);
d
.
rewrite_norm_location_response_header
(
"https"
,
443
);
auto
location
=
d
.
get_norm_response_header
(
"location"
);
d
.
index_request_headers
();
d
.
index_response_headers
();
d
.
rewrite_location_response_header
(
"https"
,
443
);
auto
location
=
d
.
get_response_header
(
http2
::
HD_LOCATION
);
CU_ASSERT
(
"https://localhost/"
==
(
*
location
).
value
);
}
{
Downstream
d
(
nullptr
,
0
,
0
);
d
.
set_request_http2_authority
(
"localhost"
);
d
.
add_response_header
(
"location"
,
"http://localhost/"
);
d
.
rewrite_norm_location_response_header
(
"https"
,
443
);
auto
location
=
d
.
get_norm_response_header
(
"location"
);
d
.
index_response_headers
();
d
.
rewrite_location_response_header
(
"https"
,
443
);
auto
location
=
d
.
get_response_header
(
http2
::
HD_LOCATION
);
CU_ASSERT
(
"https://localhost/"
==
(
*
location
).
value
);
}
}
...
...
src/shrpx_downstream_test.h
View file @
3ae44ef2
...
...
@@ -27,13 +27,13 @@
namespace
shrpx
{
void
test_downstream_
normalize
_request_headers
(
void
);
void
test_downstream_
normalize
_response_headers
(
void
);
void
test_downstream_get_
norm_
request_header
(
void
);
void
test_downstream_get_
norm_
response_header
(
void
);
void
test_downstream_
index
_request_headers
(
void
);
void
test_downstream_
index
_response_headers
(
void
);
void
test_downstream_get_request_header
(
void
);
void
test_downstream_get_response_header
(
void
);
void
test_downstream_crumble_request_cookie
(
void
);
void
test_downstream_assemble_request_cookie
(
void
);
void
test_downstream_rewrite_
norm_
location_response_header
(
void
);
void
test_downstream_rewrite_location_response_header
(
void
);
}
// namespace shrpx
...
...
src/shrpx_http2_downstream_connection.cc
View file @
3ae44ef2
...
...
@@ -233,14 +233,12 @@ int Http2DownstreamConnection::push_request_headers() {
return
0
;
}
size_t
nheader
=
downstream_
->
get_request_headers
().
size
();
Headers
cookies
;
if
(
!
get_config
()
->
http2_no_cookie_crumbling
)
{
downstream_
->
crumble_request_cookie
();
cookies
=
downstream_
->
crumble_request_cookie
();
}
assert
(
downstream_
->
get_request_headers_normalized
());
auto
end_headers
=
std
::
end
(
downstream_
->
get_request_headers
());
// 7 means:
// 1. :method
// 2. :scheme
...
...
@@ -250,10 +248,12 @@ int Http2DownstreamConnection::push_request_headers() {
// 6. x-forwarded-for (optional)
// 7. x-forwarded-proto (optional)
auto
nva
=
std
::
vector
<
nghttp2_nv
>
();
nva
.
reserve
(
nheader
+
7
);
nva
.
reserve
(
nheader
+
7
+
cookies
.
size
());
std
::
string
via_value
;
std
::
string
xff_value
;
std
::
string
scheme
,
authority
,
path
,
query
;
// To reconstruct HTTP/1 status line and headers, proxy should
// preserve host header field. See draft-09 section 8.1.3.1.
if
(
downstream_
->
get_request_method
()
==
"CONNECT"
)
{
...
...
@@ -273,7 +273,7 @@ int Http2DownstreamConnection::push_request_headers() {
if
(
!
downstream_
->
get_request_http2_authority
().
empty
())
{
nva
.
push_back
(
http2
::
make_nv_ls
(
":authority"
,
downstream_
->
get_request_http2_authority
()));
}
else
if
(
downstream_
->
get_norm_request_header
(
"host"
)
==
end_headers
)
{
}
else
if
(
!
downstream_
->
get_request_header
(
http2
::
HD_HOST
)
)
{
if
(
LOG_ENABLED
(
INFO
))
{
DCLOG
(
INFO
,
this
)
<<
"host header field missing"
;
}
...
...
@@ -330,7 +330,7 @@ int Http2DownstreamConnection::push_request_headers() {
authority
+=
util
::
utos
(
u
.
port
);
}
nva
.
push_back
(
http2
::
make_nv_ls
(
":authority"
,
authority
));
}
else
if
(
downstream_
->
get_norm_request_header
(
"host"
)
==
end_headers
)
{
}
else
if
(
!
downstream_
->
get_request_header
(
http2
::
HD_HOST
)
)
{
if
(
LOG_ENABLED
(
INFO
))
{
DCLOG
(
INFO
,
this
)
<<
"host header field missing"
;
}
...
...
@@ -341,27 +341,30 @@ int Http2DownstreamConnection::push_request_headers() {
nva
.
push_back
(
http2
::
make_nv_ls
(
":method"
,
downstream_
->
get_request_method
()));
http2
::
copy_
norm_
headers_to_nva
(
nva
,
downstream_
->
get_request_headers
());
http2
::
copy_headers_to_nva
(
nva
,
downstream_
->
get_request_headers
());
bool
chunked_encoding
=
false
;
auto
transfer_encoding
=
downstream_
->
get_
norm_request_header
(
"transfer-encoding"
);
if
(
transfer_encoding
!=
end_headers
&&
downstream_
->
get_
request_header
(
http2
::
HD_TRANSFER_ENCODING
);
if
(
transfer_encoding
&&
util
::
strieq
((
*
transfer_encoding
).
value
.
c_str
(),
"chunked"
))
{
chunked_encoding
=
true
;
}
auto
xff
=
downstream_
->
get_norm_request_header
(
"x-forwarded-for"
);
for
(
auto
&
nv
:
cookies
)
{
nva
.
push_back
(
http2
::
make_nv
(
nv
.
name
,
nv
.
value
,
nv
.
no_index
));
}
auto
xff
=
downstream_
->
get_request_header
(
http2
::
HD_X_FORWARDED_FOR
);
if
(
get_config
()
->
add_x_forwarded_for
)
{
if
(
xff
!=
end_headers
&&
!
get_config
()
->
strip_incoming_x_forwarded_for
)
{
if
(
xff
&&
!
get_config
()
->
strip_incoming_x_forwarded_for
)
{
xff_value
=
(
*
xff
).
value
;
xff_value
+=
", "
;
}
xff_value
+=
downstream_
->
get_upstream
()
->
get_client_handler
()
->
get_ipaddr
();
nva
.
push_back
(
http2
::
make_nv_ls
(
"x-forwarded-for"
,
xff_value
));
}
else
if
(
xff
!=
end_headers
&&
!
get_config
()
->
strip_incoming_x_forwarded_for
)
{
}
else
if
(
xff
&&
!
get_config
()
->
strip_incoming_x_forwarded_for
)
{
nva
.
push_back
(
http2
::
make_nv_ls
(
"x-forwarded-for"
,
(
*
xff
).
value
));
}
...
...
@@ -379,13 +382,13 @@ int Http2DownstreamConnection::push_request_headers() {
}
}
auto
via
=
downstream_
->
get_
norm_request_header
(
"via"
);
auto
via
=
downstream_
->
get_
request_header
(
http2
::
HD_VIA
);
if
(
get_config
()
->
no_via
)
{
if
(
via
!=
end_headers
)
{
if
(
via
)
{
nva
.
push_back
(
http2
::
make_nv_ls
(
"via"
,
(
*
via
).
value
));
}
}
else
{
if
(
via
!=
end_headers
)
{
if
(
via
)
{
via_value
=
(
*
via
).
value
;
via_value
+=
", "
;
}
...
...
@@ -407,7 +410,8 @@ int Http2DownstreamConnection::push_request_headers() {
}
auto
content_length
=
downstream_
->
get_norm_request_header
(
"content-length"
)
!=
end_headers
;
downstream_
->
get_request_header
(
http2
::
HD_CONTENT_LENGTH
);
// TODO check content-length: 0 case
if
(
downstream_
->
get_request_method
()
==
"CONNECT"
||
chunked_encoding
||
content_length
||
downstream_
->
get_request_http2_expect_body
())
{
...
...
src/shrpx_http2_session.cc
View file @
3ae44ef2
...
...
@@ -709,18 +709,24 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
return
0
;
}
if
(
namelen
>
0
&&
name
[
0
]
==
':'
)
{
if
(
!
downstream
->
response_pseudo_header_allowed
()
||
!
http2
::
check_http2_response_pseudo_header
(
name
,
namelen
))
{
auto
token
=
http2
::
lookup_token
(
name
,
namelen
);
if
(
name
[
0
]
==
':'
)
{
if
(
!
downstream
->
response_pseudo_header_allowed
(
token
))
{
http2session
->
submit_rst_stream
(
frame
->
hd
.
stream_id
,
NGHTTP2_PROTOCOL_ERROR
);
return
NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE
;
}
}
downstream
->
split_add_response_header
(
name
,
namelen
,
value
,
valuelen
,
flags
&
NGHTTP2_NV_FLAG_NO_INDEX
);
if
(
!
http2
::
http2_header_allowed
(
token
))
{
http2session
->
submit_rst_stream
(
frame
->
hd
.
stream_id
,
NGHTTP2_PROTOCOL_ERROR
);
return
NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE
;
}
downstream
->
add_response_header
(
name
,
namelen
,
value
,
valuelen
,
flags
&
NGHTTP2_NV_FLAG_NO_INDEX
,
token
);
return
0
;
}
}
// namespace
...
...
@@ -763,20 +769,11 @@ int on_response_headers(Http2Session *http2session, Downstream *downstream,
auto
upstream
=
downstream
->
get_upstream
();
downstream
->
normalize_response_headers
();
auto
&
nva
=
downstream
->
get_response_headers
();
downstream
->
set_expect_final_response
(
false
);
if
(
!
http2
::
check_http2_response_headers
(
nva
))
{
http2session
->
submit_rst_stream
(
frame
->
hd
.
stream_id
,
NGHTTP2_PROTOCOL_ERROR
);
downstream
->
set_response_state
(
Downstream
::
MSG_RESET
);
call_downstream_readcb
(
http2session
,
downstream
);
return
0
;
}
auto
status
=
http2
::
get_unique_header
(
nva
,
":status"
);
auto
status
=
downstream
->
get_response_header
(
http2
::
HD__STATUS
);
int
status_code
;
if
(
!
http2
::
non_empty_value
(
status
)
||
...
...
@@ -824,7 +821,8 @@ int on_response_headers(Http2Session *http2session, Downstream *downstream,
return
0
;
}
auto
content_length
=
http2
::
get_header
(
nva
,
"content-length"
);
auto
content_length
=
downstream
->
get_response_header
(
http2
::
HD_CONTENT_LENGTH
);
if
(
!
content_length
&&
downstream
->
get_request_method
()
!=
"HEAD"
&&
downstream
->
get_request_method
()
!=
"CONNECT"
)
{
unsigned
int
status
;
...
...
src/shrpx_http2_upstream.cc
View file @
3ae44ef2
...
...
@@ -185,17 +185,22 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
return
0
;
}
if
(
namelen
>
0
&&
name
[
0
]
==
':'
)
{
if
(
!
downstream
->
request_pseudo_header_allowed
()
||
!
http2
::
check_http2_request_pseudo_header
(
name
,
namelen
))
{
auto
token
=
http2
::
lookup_token
(
name
,
namelen
);
if
(
name
[
0
]
==
':'
)
{
if
(
!
downstream
->
request_pseudo_header_allowed
(
token
))
{
upstream
->
rst_stream
(
downstream
,
NGHTTP2_PROTOCOL_ERROR
);
return
NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE
;
}
}
downstream
->
split_add_request_header
(
name
,
namelen
,
value
,
valuelen
,
flags
&
NGHTTP2_NV_FLAG_NO_INDEX
);
if
(
!
http2
::
http2_header_allowed
(
token
))
{
upstream
->
rst_stream
(
downstream
,
NGHTTP2_PROTOCOL_ERROR
);
return
NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE
;
}
downstream
->
add_request_header
(
name
,
namelen
,
value
,
valuelen
,
flags
&
NGHTTP2_NV_FLAG_NO_INDEX
,
token
);
return
0
;
}
}
// namespace
...
...
@@ -238,7 +243,6 @@ int on_request_headers(Http2Upstream *upstream, Downstream *downstream,
return
0
;
}
downstream
->
normalize_request_headers
();
auto
&
nva
=
downstream
->
get_request_headers
();
if
(
LOG_ENABLED
(
INFO
))
{
...
...
@@ -254,17 +258,11 @@ int on_request_headers(Http2Upstream *upstream, Downstream *downstream,
http2
::
dump_nv
(
get_config
()
->
http2_upstream_dump_request_header
,
nva
);
}
if
(
!
http2
::
check_http2_request_headers
(
nva
))
{
upstream
->
rst_stream
(
downstream
,
NGHTTP2_PROTOCOL_ERROR
);
return
0
;
}
auto
host
=
http2
::
get_unique_header
(
nva
,
"host"
);
auto
authority
=
http2
::
get_unique_header
(
nva
,
":authority"
);
auto
path
=
http2
::
get_unique_header
(
nva
,
":path"
);
auto
method
=
http2
::
get_unique_header
(
nva
,
":method"
);
auto
scheme
=
http2
::
get_unique_header
(
nva
,
":scheme"
);
auto
host
=
downstream
->
get_request_header
(
http2
::
HD_HOST
);
auto
authority
=
downstream
->
get_request_header
(
http2
::
HD__AUTHORITY
);
auto
path
=
downstream
->
get_request_header
(
http2
::
HD__PATH
);
auto
method
=
downstream
->
get_request_header
(
http2
::
HD__METHOD
);
auto
scheme
=
downstream
->
get_request_header
(
http2
::
HD__SCHEME
);
bool
is_connect
=
method
&&
"CONNECT"
==
method
->
value
;
bool
having_host
=
http2
::
non_empty_value
(
host
);
...
...
@@ -1101,14 +1099,12 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) {
}
}
downstream
->
normalize_response_headers
();
if
(
!
get_config
()
->
http2_proxy
&&
!
get_config
()
->
client_proxy
&&
!
get_config
()
->
no_location_rewrite
)
{
downstream
->
rewrite_
norm_
location_response_header
(
downstream
->
rewrite_location_response_header
(
get_client_handler
()
->
get_upstream_scheme
(),
get_config
()
->
port
);
}
auto
end_headers
=
std
::
end
(
downstream
->
get_response_headers
());
size_t
nheader
=
downstream
->
get_response_headers
().
size
();
auto
nva
=
std
::
vector
<
nghttp2_nv
>
();
// 3 means :status and possible server and via header field.
...
...
@@ -1117,7 +1113,7 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) {
auto
response_status
=
util
::
utos
(
downstream
->
get_response_http_status
());
nva
.
push_back
(
http2
::
make_nv_ls
(
":status"
,
response_status
));
http2
::
copy_
norm_
headers_to_nva
(
nva
,
downstream
->
get_response_headers
());
http2
::
copy_headers_to_nva
(
nva
,
downstream
->
get_response_headers
());
if
(
downstream
->
get_non_final_response
())
{
if
(
LOG_ENABLED
(
INFO
))
{
...
...
@@ -1141,19 +1137,19 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) {
if
(
!
get_config
()
->
http2_proxy
&&
!
get_config
()
->
client_proxy
)
{
nva
.
push_back
(
http2
::
make_nv_lc
(
"server"
,
get_config
()
->
server_name
));
}
else
{
auto
server
=
downstream
->
get_
norm_response_header
(
"server"
);
if
(
server
!=
end_headers
)
{
auto
server
=
downstream
->
get_
response_header
(
http2
::
HD_SERVER
);
if
(
server
)
{
nva
.
push_back
(
http2
::
make_nv_ls
(
"server"
,
(
*
server
).
value
));
}
}
auto
via
=
downstream
->
get_
norm_response_header
(
"via"
);
auto
via
=
downstream
->
get_
response_header
(
http2
::
HD_VIA
);
if
(
get_config
()
->
no_via
)
{
if
(
via
!=
end_headers
)
{
if
(
via
)
{
nva
.
push_back
(
http2
::
make_nv_ls
(
"via"
,
(
*
via
).
value
));
}
}
else
{
if
(
via
!=
end_headers
)
{
if
(
via
)
{
via_value
=
(
*
via
).
value
;
via_value
+=
", "
;
}
...
...
src/shrpx_http_downstream_connection.cc
View file @
3ae44ef2
...
...
@@ -213,11 +213,8 @@ int HttpDownstreamConnection::attach_downstream(Downstream *downstream) {
}
int
HttpDownstreamConnection
::
push_request_headers
()
{
assert
(
downstream_
->
get_request_headers_normalized
());
downstream_
->
assemble_request_cookie
();
auto
end_headers
=
std
::
end
(
downstream_
->
get_request_headers
());
// Assume that method and request path do not contain \r\n.
std
::
string
hdrs
=
downstream_
->
get_request_method
();
hdrs
+=
" "
;
...
...
@@ -253,14 +250,14 @@ int HttpDownstreamConnection::push_request_headers() {
hdrs
+=
downstream_
->
get_request_path
();
}
hdrs
+=
" HTTP/1.1
\r\n
"
;
if
(
downstream_
->
get_norm_request_header
(
"host"
)
==
end_headers
&&
if
(
!
downstream_
->
get_request_header
(
http2
::
HD_HOST
)
&&
!
downstream_
->
get_request_http2_authority
().
empty
())
{
hdrs
+=
"Host: "
;
hdrs
+=
downstream_
->
get_request_http2_authority
();
hdrs
+=
"
\r\n
"
;
}
http2
::
build_http1_headers_from_
norm_headers
(
hdrs
,
downstream_
->
get_request_headers
());
http2
::
build_http1_headers_from_
headers
(
hdrs
,
downstream_
->
get_request_headers
());
if
(
!
downstream_
->
get_assembled_request_cookie
().
empty
())
{
hdrs
+=
"Cookie: "
;
...
...
@@ -270,7 +267,7 @@ int HttpDownstreamConnection::push_request_headers() {
if
(
downstream_
->
get_request_method
()
!=
"CONNECT"
&&
downstream_
->
get_request_http2_expect_body
()
&&
downstream_
->
get_norm_request_header
(
"content-length"
)
==
end_headers
)
{
!
downstream_
->
get_request_header
(
http2
::
HD_CONTENT_LENGTH
)
)
{
downstream_
->
set_chunked_request
(
true
);
hdrs
+=
"Transfer-Encoding: chunked
\r\n
"
;
...
...
@@ -279,18 +276,17 @@ int HttpDownstreamConnection::push_request_headers() {
if
(
downstream_
->
get_request_connection_close
())
{
hdrs
+=
"Connection: close
\r\n
"
;
}
auto
xff
=
downstream_
->
get_
norm_request_header
(
"x-forwarded-for"
);
auto
xff
=
downstream_
->
get_
request_header
(
http2
::
HD_X_FORWARDED_FOR
);
if
(
get_config
()
->
add_x_forwarded_for
)
{
hdrs
+=
"X-Forwarded-For: "
;
if
(
xff
!=
end_headers
&&
!
get_config
()
->
strip_incoming_x_forwarded_for
)
{
if
(
xff
&&
!
get_config
()
->
strip_incoming_x_forwarded_for
)
{
hdrs
+=
(
*
xff
).
value
;
http2
::
sanitize_header_value
(
hdrs
,
hdrs
.
size
()
-
(
*
xff
).
value
.
size
());
hdrs
+=
", "
;
}
hdrs
+=
client_handler_
->
get_ipaddr
();
hdrs
+=
"
\r\n
"
;
}
else
if
(
xff
!=
end_headers
&&
!
get_config
()
->
strip_incoming_x_forwarded_for
)
{
}
else
if
(
xff
&&
!
get_config
()
->
strip_incoming_x_forwarded_for
)
{
hdrs
+=
"X-Forwarded-For: "
;
hdrs
+=
(
*
xff
).
value
;
http2
::
sanitize_header_value
(
hdrs
,
hdrs
.
size
()
-
(
*
xff
).
value
.
size
());
...
...
@@ -308,17 +304,16 @@ int HttpDownstreamConnection::push_request_headers() {
hdrs
+=
"http
\r\n
"
;
}
}
auto
expect
=
downstream_
->
get_norm_request_header
(
"expect"
);
if
(
expect
!=
end_headers
&&
!
util
::
strifind
((
*
expect
).
value
.
c_str
(),
"100-continue"
))
{
auto
expect
=
downstream_
->
get_request_header
(
http2
::
HD_EXPECT
);
if
(
expect
&&
!
util
::
strifind
((
*
expect
).
value
.
c_str
(),
"100-continue"
))
{
hdrs
+=
"Expect: "
;
hdrs
+=
(
*
expect
).
value
;
http2
::
sanitize_header_value
(
hdrs
,
hdrs
.
size
()
-
(
*
expect
).
value
.
size
());
hdrs
+=
"
\r\n
"
;
}
auto
via
=
downstream_
->
get_
norm_request_header
(
"via"
);
auto
via
=
downstream_
->
get_
request_header
(
http2
::
HD_VIA
);
if
(
get_config
()
->
no_via
)
{
if
(
via
!=
end_headers
)
{
if
(
via
)
{
hdrs
+=
"Via: "
;
hdrs
+=
(
*
via
).
value
;
http2
::
sanitize_header_value
(
hdrs
,
hdrs
.
size
()
-
(
*
via
).
value
.
size
());
...
...
@@ -326,7 +321,7 @@ int HttpDownstreamConnection::push_request_headers() {
}
}
else
{
hdrs
+=
"Via: "
;
if
(
via
!=
end_headers
)
{
if
(
via
)
{
hdrs
+=
(
*
via
).
value
;
http2
::
sanitize_header_value
(
hdrs
,
hdrs
.
size
()
-
(
*
via
).
value
.
size
());
hdrs
+=
", "
;
...
...
@@ -473,6 +468,8 @@ int htp_hdrs_completecb(http_parser *htp) {
downstream
->
set_response_major
(
htp
->
http_major
);
downstream
->
set_response_minor
(
htp
->
http_minor
);
downstream
->
index_response_headers
();
if
(
downstream
->
get_non_final_response
())
{
// For non-final response code, we just call
// on_downstream_header_complete() without changing response
...
...
src/shrpx_https_upstream.cc
View file @
3ae44ef2
...
...
@@ -149,7 +149,7 @@ int htp_hdrs_completecb(http_parser *htp) {
ULOG
(
INFO
,
upstream
)
<<
"HTTP request headers
\n
"
<<
ss
.
str
();
}
downstream
->
normalize
_request_headers
();
downstream
->
index
_request_headers
();
downstream
->
inspect_http1_request
();
...
...
@@ -620,15 +620,15 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
hdrs
+=
" "
;
hdrs
+=
http2
::
get_status_string
(
downstream
->
get_response_http_status
());
hdrs
+=
"
\r\n
"
;
downstream
->
normalize_response_headers
();
if
(
!
get_config
()
->
http2_proxy
&&
!
get_config
()
->
client_proxy
&&
!
get_config
()
->
no_location_rewrite
)
{
downstream
->
rewrite_
norm_
location_response_header
(
downstream
->
rewrite_location_response_header
(
get_client_handler
()
->
get_upstream_scheme
(),
get_config
()
->
port
);
}
auto
end_headers
=
std
::
end
(
downstream
->
get_response_headers
());
http2
::
build_http1_headers_from_
norm_headers
(
hdrs
,
downstream
->
get_response_headers
());
http2
::
build_http1_headers_from_
headers
(
hdrs
,
downstream
->
get_response_headers
());
auto
output
=
downstream
->
get_response_buf
();
...
...
@@ -660,8 +660,8 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
hdrs
+=
"Connection: close
\r\n
"
;
}
if
(
downstream
->
get_norm_response_header
(
"alt-svc"
)
==
end_headers
)
{
// We won't change or alter alt-svc from backend
at the moment.
if
(
!
downstream
->
get_response_header
(
http2
::
HD_ALT_SVC
)
)
{
// We won't change or alter alt-svc from backend
for now
if
(
!
get_config
()
->
altsvcs
.
empty
())
{
hdrs
+=
"Alt-Svc: "
;
...
...
@@ -684,17 +684,17 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
hdrs
+=
get_config
()
->
server_name
;
hdrs
+=
"
\r\n
"
;
}
else
{
auto
server
=
downstream
->
get_
norm_response_header
(
"server"
);
if
(
server
!=
end_headers
)
{
auto
server
=
downstream
->
get_
response_header
(
http2
::
HD_SERVER
);
if
(
server
)
{
hdrs
+=
"Server: "
;
hdrs
+=
(
*
server
).
value
;
hdrs
+=
"
\r\n
"
;
}
}
auto
via
=
downstream
->
get_
norm_response_header
(
"via"
);
auto
via
=
downstream
->
get_
response_header
(
http2
::
HD_VIA
);
if
(
get_config
()
->
no_via
)
{
if
(
via
!=
end_headers
)
{
if
(
via
)
{
hdrs
+=
"Via: "
;
hdrs
+=
(
*
via
).
value
;
http2
::
sanitize_header_value
(
hdrs
,
hdrs
.
size
()
-
(
*
via
).
value
.
size
());
...
...
@@ -702,7 +702,7 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
}
}
else
{
hdrs
+=
"Via: "
;
if
(
via
!=
end_headers
)
{
if
(
via
)
{
hdrs
+=
(
*
via
).
value
;
http2
::
sanitize_header_value
(
hdrs
,
hdrs
.
size
()
-
(
*
via
).
value
.
size
());
hdrs
+=
", "
;
...
...
src/shrpx_log.cc
View file @
3ae44ef2
...
...
@@ -206,7 +206,7 @@ void upstream_accesslog(const std::vector<LogFragment> &lfv, LogSpec *lgsp) {
case
SHRPX_LOGF_HTTP
:
if
(
downstream
)
{
auto
hd
=
downstream
->
get_request_header
(
lf
.
value
.
get
());
if
(
hd
!=
std
::
end
(
downstream
->
get_request_headers
())
)
{
if
(
hd
)
{
std
::
tie
(
p
,
avail
)
=
copy
((
*
hd
).
value
.
c_str
(),
avail
,
p
);
break
;
}
...
...
src/shrpx_spdy_upstream.cc
View file @
3ae44ef2
...
...
@@ -156,42 +156,33 @@ void on_ctrl_recv_callback(spdylay_session *session, spdylay_frame_type type,
downstream
->
reset_upstream_rtimer
();
auto
nv
=
frame
->
syn_stream
.
nv
;
const
char
*
path
=
nullptr
;
const
char
*
scheme
=
nullptr
;
const
char
*
host
=
nullptr
;
const
char
*
method
=
nullptr
;
for
(
size_t
i
=
0
;
nv
[
i
];
i
+=
2
)
{
if
(
strcmp
(
nv
[
i
],
":path"
)
==
0
)
{
path
=
nv
[
i
+
1
];
}
else
if
(
strcmp
(
nv
[
i
],
":scheme"
)
==
0
)
{
scheme
=
nv
[
i
+
1
];
}
else
if
(
strcmp
(
nv
[
i
],
":method"
)
==
0
)
{
method
=
nv
[
i
+
1
];
}
else
if
(
strcmp
(
nv
[
i
],
":host"
)
==
0
)
{
host
=
nv
[
i
+
1
];
}
else
if
(
nv
[
i
][
0
]
!=
':'
)
{
downstream
->
add_request_header
(
nv
[
i
],
nv
[
i
+
1
]);
}
downstream
->
add_request_header
(
nv
[
i
],
nv
[
i
+
1
]);
}
downstream
->
normalize_request_headers
();
downstream
->
index_request_headers
();
auto
path
=
downstream
->
get_request_header
(
http2
::
HD__PATH
);
auto
scheme
=
downstream
->
get_request_header
(
http2
::
HD__SCHEME
);
auto
host
=
downstream
->
get_request_header
(
http2
::
HD__HOST
);
auto
method
=
downstream
->
get_request_header
(
http2
::
HD__METHOD
);
bool
is_connect
=
method
&&
strcmp
(
"CONNECT"
,
method
)
==
0
;
if
(
!
path
||
!
host
||
!
method
||
http2
::
lws
(
host
)
||
http2
::
lws
(
path
)
||
http2
::
lws
(
method
)
||
(
!
is_connect
&&
(
!
scheme
||
http2
::
lws
(
scheme
))))
{
bool
is_connect
=
method
&&
"CONNECT"
==
method
->
value
;
if
(
!
path
||
!
host
||
!
method
||
!
http2
::
non_empty_value
(
host
)
||
!
http2
::
non_empty_value
(
path
)
||
!
http2
::
non_empty_value
(
method
)
||
(
!
is_connect
&&
(
!
scheme
||
!
http2
::
non_empty_value
(
scheme
))))
{
upstream
->
rst_stream
(
downstream
,
SPDYLAY_INTERNAL_ERROR
);
return
;
}
downstream
->
set_request_method
(
method
);
downstream
->
set_request_method
(
method
->
value
);
if
(
is_connect
)
{
downstream
->
set_request_http2_authority
(
path
);
downstream
->
set_request_http2_authority
(
path
->
value
);
}
else
{
downstream
->
set_request_http2_scheme
(
scheme
);
downstream
->
set_request_http2_authority
(
host
);
downstream
->
set_request_path
(
path
);
downstream
->
set_request_http2_scheme
(
scheme
->
value
);
downstream
->
set_request_http2_authority
(
host
->
value
);
downstream
->
set_request_path
(
path
->
value
);
}
downstream
->
set_request_start_time
(
...
...
@@ -824,10 +815,10 @@ int SpdyUpstream::on_downstream_header_complete(Downstream *downstream) {
if
(
LOG_ENABLED
(
INFO
))
{
DLOG
(
INFO
,
downstream
)
<<
"HTTP response header completed"
;
}
downstream
->
normalize_response_headers
();
if
(
!
get_config
()
->
http2_proxy
&&
!
get_config
()
->
client_proxy
&&
!
get_config
()
->
no_location_rewrite
)
{
downstream
->
rewrite_
norm_
location_response_header
(
downstream
->
rewrite_location_response_header
(
get_client_handler
()
->
get_upstream_scheme
(),
get_config
()
->
port
);
}
size_t
nheader
=
downstream
->
get_response_headers
().
size
();
...
...
@@ -844,30 +835,39 @@ int SpdyUpstream::on_downstream_header_complete(Downstream *downstream) {
nv
[
hdidx
++
]
=
":version"
;
nv
[
hdidx
++
]
=
"HTTP/1.1"
;
for
(
auto
&
hd
:
downstream
->
get_response_headers
())
{
if
(
hd
.
name
.
empty
()
||
hd
.
name
.
c_str
()[
0
]
==
':'
||
util
::
strieq
(
hd
.
name
.
c_str
(),
"transfer-encoding"
)
||
util
::
strieq
(
hd
.
name
.
c_str
(),
"keep-alive"
)
||
// HTTP/1.0?
util
::
strieq
(
hd
.
name
.
c_str
(),
"connection"
)
||
util
::
strieq
(
hd
.
name
.
c_str
(),
"proxy-connection"
))
{
// These are ignored
}
else
if
(
!
get_config
()
->
no_via
&&
util
::
strieq
(
hd
.
name
.
c_str
(),
"via"
))
{
via_value
=
hd
.
value
;
}
else
if
(
!
get_config
()
->
http2_proxy
&&
!
get_config
()
->
client_proxy
&&
util
::
strieq
(
hd
.
name
.
c_str
(),
"server"
))
{
// Rewrite server header field later
}
else
{
nv
[
hdidx
++
]
=
hd
.
name
.
c_str
();
nv
[
hdidx
++
]
=
hd
.
value
.
c_str
();
if
(
hd
.
name
.
empty
()
||
hd
.
name
.
c_str
()[
0
]
==
':'
)
{
continue
;
}
auto
token
=
http2
::
lookup_token
(
hd
.
name
);
switch
(
token
)
{
case
http2
:
:
HD_CONNECTION
:
case
http2
:
:
HD_KEEP_ALIVE
:
case
http2
:
:
HD_PROXY_CONNECTION
:
case
http2
:
:
HD_TRANSFER_ENCODING
:
case
http2
:
:
HD_VIA
:
case
http2
:
:
HD_SERVER
:
continue
;
}
nv
[
hdidx
++
]
=
hd
.
name
.
c_str
();
nv
[
hdidx
++
]
=
hd
.
value
.
c_str
();
}
if
(
!
get_config
()
->
http2_proxy
&&
!
get_config
()
->
client_proxy
)
{
nv
[
hdidx
++
]
=
"server"
;
nv
[
hdidx
++
]
=
get_config
()
->
server_name
;
}
else
{
auto
server
=
downstream
->
get_response_header
(
http2
::
HD_SERVER
);
if
(
server
)
{
nv
[
hdidx
++
]
=
"server"
;
nv
[
hdidx
++
]
=
server
->
value
.
c_str
();
}
}
if
(
!
get_config
()
->
no_via
)
{
if
(
!
via_value
.
empty
())
{
auto
via
=
downstream
->
get_response_header
(
http2
::
HD_VIA
);
if
(
via
)
{
via_value
=
via
->
value
;
via_value
+=
", "
;
}
via_value
+=
http
::
create_via_header_value
(
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment