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
e217e789
Commit
e217e789
authored
Aug 08, 2014
by
Tatsuhiro Tsujikawa
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
nghttp: Support non-final response and check pseudo headers
parent
d4d56e18
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
147 additions
and
15 deletions
+147
-15
src/http2.cc
src/http2.cc
+22
-0
src/http2.h
src/http2.h
+3
-0
src/http2_test.cc
src/http2_test.cc
+11
-0
src/http2_test.h
src/http2_test.h
+1
-0
src/nghttp.cc
src/nghttp.cc
+108
-15
src/shrpx-unittest.cc
src/shrpx-unittest.cc
+2
-0
No files found.
src/http2.cc
View file @
e217e789
...
...
@@ -556,6 +556,28 @@ int check_nv(const uint8_t *name, size_t namelen,
return
1
;
}
int
parse_http_status_code
(
const
std
::
string
&
src
)
{
if
(
src
.
size
()
!=
3
)
{
return
-
1
;
}
int
status
=
0
;
for
(
auto
c
:
src
)
{
if
(
!
isdigit
(
c
))
{
return
-
1
;
}
status
*=
10
;
status
+=
c
-
'0'
;
}
if
(
status
<
100
)
{
return
-
1
;
}
return
status
;
}
}
// namespace http2
}
// namespace nghttp2
src/http2.h
View file @
e217e789
...
...
@@ -230,6 +230,9 @@ std::string rewrite_location_uri(const std::string& uri,
int
check_nv
(
const
uint8_t
*
name
,
size_t
namelen
,
const
uint8_t
*
value
,
size_t
valuelen
);
// Returns parsed HTTP status code. Returns -1 on failure.
int
parse_http_status_code
(
const
std
::
string
&
src
);
}
// namespace http2
}
// namespace nghttp2
...
...
src/http2_test.cc
View file @
e217e789
...
...
@@ -280,4 +280,15 @@ void test_http2_rewrite_location_uri(void)
"localhost"
,
"https"
,
3000
);
}
void
test_http2_parse_http_status_code
(
void
)
{
CU_ASSERT
(
200
==
http2
::
parse_http_status_code
(
"200"
));
CU_ASSERT
(
102
==
http2
::
parse_http_status_code
(
"102"
));
CU_ASSERT
(
-
1
==
http2
::
parse_http_status_code
(
"099"
));
CU_ASSERT
(
-
1
==
http2
::
parse_http_status_code
(
"99"
));
CU_ASSERT
(
-
1
==
http2
::
parse_http_status_code
(
"-1"
));
CU_ASSERT
(
-
1
==
http2
::
parse_http_status_code
(
"20a"
));
CU_ASSERT
(
-
1
==
http2
::
parse_http_status_code
(
""
));
}
}
// namespace shrpx
src/http2_test.h
View file @
e217e789
...
...
@@ -36,6 +36,7 @@ void test_http2_copy_norm_headers_to_nva(void);
void
test_http2_build_http1_headers_from_norm_headers
(
void
);
void
test_http2_lws
(
void
);
void
test_http2_rewrite_location_uri
(
void
);
void
test_http2_parse_http_status_code
(
void
);
}
// namespace shrpx
...
...
src/nghttp.cc
View file @
e217e789
...
...
@@ -178,7 +178,6 @@ struct Request {
Headers
push_req_nva
;
// URI without fragment
std
::
string
uri
;
std
::
string
status
;
http_parser_url
u
;
std
::
shared_ptr
<
Dependency
>
dep
;
nghttp2_priority_spec
pri_spec
;
...
...
@@ -189,10 +188,12 @@ struct Request {
HtmlParser
*
html_parser
;
const
nghttp2_data_provider
*
data_prd
;
int32_t
stream_id
;
int
status
;
// Recursion level: 0: first entity, 1: entity linked from first entity
int
level
;
// RequestPriority value defined in HtmlParser.h
int
pri
;
bool
expect_final_response
;
// For pushed request, |uri| is empty and |u| is zero-cleared.
Request
(
const
std
::
string
&
uri
,
const
http_parser_url
&
u
,
...
...
@@ -209,8 +210,10 @@ struct Request {
html_parser
(
nullptr
),
data_prd
(
data_prd
),
stream_id
(
-
1
),
status
(
0
),
level
(
level
),
pri
(
pri
)
pri
(
pri
),
expect_final_response
(
false
)
{}
~
Request
()
...
...
@@ -316,6 +319,16 @@ struct Request {
}
}
bool
response_pseudo_header_allowed
()
const
{
return
res_nva
.
empty
()
||
res_nva
.
back
().
name
.
c_str
()[
0
]
==
':'
;
}
bool
push_request_pseudo_header_allowed
()
const
{
return
res_nva
.
empty
()
||
push_req_nva
.
back
().
name
.
c_str
()[
0
]
==
':'
;
}
void
record_request_time
()
{
stat
.
stage
=
STAT_ON_REQUEST
;
...
...
@@ -1122,6 +1135,12 @@ int on_data_chunk_recv_callback
return
0
;
}
if
(
req
->
status
==
0
)
{
nghttp2_submit_rst_stream
(
session
,
NGHTTP2_FLAG_NONE
,
stream_id
,
NGHTTP2_PROTOCOL_ERROR
);
return
0
;
}
if
(
req
->
inflater
)
{
while
(
len
>
0
)
{
const
size_t
MAX_OUTLEN
=
4096
;
...
...
@@ -1181,6 +1200,9 @@ namespace {
void
check_response_header
(
nghttp2_session
*
session
,
Request
*
req
)
{
bool
gzip
=
false
;
req
->
expect_final_response
=
false
;
for
(
auto
&
nv
:
req
->
res_nva
)
{
if
(
"content-encoding"
==
nv
.
name
)
{
gzip
=
util
::
strieq
(
"gzip"
,
nv
.
value
)
||
...
...
@@ -1188,9 +1210,32 @@ void check_response_header(nghttp2_session *session, Request* req)
continue
;
}
if
(
":status"
==
nv
.
name
)
{
req
->
status
.
assign
(
nv
.
value
);
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
;
}
req
->
status
=
status
;
}
}
if
(
req
->
status
==
0
)
{
nghttp2_submit_rst_stream
(
session
,
NGHTTP2_FLAG_NONE
,
req
->
stream_id
,
NGHTTP2_PROTOCOL_ERROR
);
return
;
}
if
(
req
->
status
/
100
==
1
)
{
req
->
expect_final_response
=
true
;
req
->
status
=
0
;
req
->
res_nva
.
clear
();
return
;
}
if
(
gzip
)
{
if
(
!
req
->
inflater
)
{
req
->
init_inflater
();
...
...
@@ -1257,15 +1302,30 @@ int on_header_callback(nghttp2_session *session,
switch
(
frame
->
hd
.
type
)
{
case
NGHTTP2_HEADERS
:
{
if
(
frame
->
headers
.
cat
!=
NGHTTP2_HCAT_RESPONSE
&&
frame
->
headers
.
cat
!=
NGHTTP2_HCAT_PUSH_RESPONSE
)
{
break
;
}
auto
req
=
(
Request
*
)
nghttp2_session_get_stream_user_data
(
session
,
frame
->
hd
.
stream_id
);
if
(
!
req
)
{
break
;
}
if
(
frame
->
headers
.
cat
!=
NGHTTP2_HCAT_RESPONSE
&&
frame
->
headers
.
cat
!=
NGHTTP2_HCAT_PUSH_RESPONSE
&&
(
frame
->
headers
.
cat
!=
NGHTTP2_HCAT_HEADERS
||
!
req
->
expect_final_response
))
{
break
;
}
if
(
namelen
>
0
&&
name
[
0
]
==
':'
)
{
if
(
!
req
->
response_pseudo_header_allowed
()
||
!
http2
::
check_http2_response_pseudo_header
(
name
,
namelen
))
{
nghttp2_submit_rst_stream
(
session
,
NGHTTP2_FLAG_NONE
,
frame
->
hd
.
stream_id
,
NGHTTP2_PROTOCOL_ERROR
);
return
NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE
;
}
}
http2
::
add_header
(
req
->
res_nva
,
name
,
namelen
,
value
,
valuelen
,
flags
&
NGHTTP2_NV_FLAG_NO_INDEX
);
break
;
...
...
@@ -1273,9 +1333,21 @@ int on_header_callback(nghttp2_session *session,
case
NGHTTP2_PUSH_PROMISE
:
{
auto
req
=
(
Request
*
)
nghttp2_session_get_stream_user_data
(
session
,
frame
->
push_promise
.
promised_stream_id
);
if
(
!
req
)
{
break
;
}
if
(
namelen
>
0
&&
name
[
0
]
==
':'
)
{
if
(
!
req
->
push_request_pseudo_header_allowed
()
||
!
http2
::
check_http2_request_pseudo_header
(
name
,
namelen
))
{
nghttp2_submit_rst_stream
(
session
,
NGHTTP2_FLAG_NONE
,
frame
->
push_promise
.
promised_stream_id
,
NGHTTP2_PROTOCOL_ERROR
);
break
;
}
}
http2
::
add_header
(
req
->
push_req_nva
,
name
,
namelen
,
value
,
valuelen
,
flags
&
NGHTTP2_NV_FLAG_NO_INDEX
);
break
;
...
...
@@ -1291,21 +1363,45 @@ int on_frame_recv_callback2
{
int
rv
=
0
;
if
(
config
.
verbose
)
{
verbose_on_frame_recv_callback
(
session
,
frame
,
user_data
);
}
auto
client
=
get_session
(
user_data
);
switch
(
frame
->
hd
.
type
)
{
case
NGHTTP2_HEADERS
:
{
if
(
frame
->
headers
.
cat
!=
NGHTTP2_HCAT_RESPONSE
&&
frame
->
headers
.
cat
!=
NGHTTP2_HCAT_PUSH_RESPONSE
)
{
break
;
}
auto
req
=
(
Request
*
)
nghttp2_session_get_stream_user_data
(
session
,
frame
->
hd
.
stream_id
);
// If this is the HTTP Upgrade with OPTIONS method to avoid POST,
// req is nullptr.
if
(
req
)
{
if
(
!
req
)
{
break
;
}
if
(
frame
->
headers
.
cat
==
NGHTTP2_HCAT_RESPONSE
||
frame
->
headers
.
cat
==
NGHTTP2_HCAT_PUSH_RESPONSE
)
{
req
->
record_response_time
();
check_response_header
(
session
,
req
);
break
;
}
if
(
frame
->
headers
.
cat
==
NGHTTP2_HCAT_HEADERS
)
{
if
(
req
->
expect_final_response
)
{
check_response_header
(
session
,
req
);
}
else
{
nghttp2_submit_rst_stream
(
session
,
NGHTTP2_FLAG_NONE
,
frame
->
hd
.
stream_id
,
NGHTTP2_PROTOCOL_ERROR
);
break
;
}
}
if
(
req
->
status
==
0
&&
(
frame
->
hd
.
flags
&
NGHTTP2_FLAG_END_STREAM
))
{
nghttp2_submit_rst_stream
(
session
,
NGHTTP2_FLAG_NONE
,
frame
->
hd
.
stream_id
,
NGHTTP2_PROTOCOL_ERROR
);
break
;
}
break
;
}
case
NGHTTP2_SETTINGS
:
...
...
@@ -1367,9 +1463,6 @@ int on_frame_recv_callback2
break
;
}
}
if
(
config
.
verbose
)
{
verbose_on_frame_recv_callback
(
session
,
frame
,
user_data
);
}
return
rv
;
}
}
// namespace
...
...
src/shrpx-unittest.cc
View file @
e217e789
...
...
@@ -88,6 +88,8 @@ int main(int argc, char* argv[])
shrpx
::
test_http2_lws
)
||
!
CU_add_test
(
pSuite
,
"http2_rewrite_location_uri"
,
shrpx
::
test_http2_rewrite_location_uri
)
||
!
CU_add_test
(
pSuite
,
"http2_parse_http_status_code"
,
shrpx
::
test_http2_parse_http_status_code
)
||
!
CU_add_test
(
pSuite
,
"downstream_normalize_request_headers"
,
shrpx
::
test_downstream_normalize_request_headers
)
||
!
CU_add_test
(
pSuite
,
"downstream_normalize_response_headers"
,
...
...
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