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
bff5a28d
Commit
bff5a28d
authored
Mar 08, 2015
by
Tatsuhiro Tsujikawa
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'nghttpx-trailer'
parents
c4b487be
5c31c130
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
465 additions
and
88 deletions
+465
-88
integration-tests/nghttpx_http1_test.go
integration-tests/nghttpx_http1_test.go
+35
-0
integration-tests/nghttpx_http2_test.go
integration-tests/nghttpx_http2_test.go
+35
-0
integration-tests/server_tester.go
integration-tests/server_tester.go
+56
-3
src/HttpServer.cc
src/HttpServer.cc
+16
-3
src/http2.cc
src/http2.cc
+0
-2
src/nghttp.cc
src/nghttp.cc
+15
-2
src/shrpx_downstream.cc
src/shrpx_downstream.cc
+137
-34
src/shrpx_downstream.h
src/shrpx_downstream.h
+29
-2
src/shrpx_http2_downstream_connection.cc
src/shrpx_http2_downstream_connection.cc
+26
-2
src/shrpx_http2_session.cc
src/shrpx_http2_session.cc
+18
-7
src/shrpx_http2_upstream.cc
src/shrpx_http2_upstream.cc
+32
-3
src/shrpx_http_downstream_connection.cc
src/shrpx_http_downstream_connection.cc
+33
-15
src/shrpx_https_upstream.cc
src/shrpx_https_upstream.cc
+33
-15
No files found.
integration-tests/nghttpx_http1_test.go
View file @
bff5a28d
...
...
@@ -211,6 +211,41 @@ func TestH1H1HTTP10NoHostRewrite(t *testing.T) {
}
}
// TestH1H1RequestTrailer tests request trailer part is forwarded to
// backend.
func
TestH1H1RequestTrailer
(
t
*
testing
.
T
)
{
st
:=
newServerTester
(
nil
,
t
,
func
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
buf
:=
make
([]
byte
,
4096
)
for
{
_
,
err
:=
r
.
Body
.
Read
(
buf
)
if
err
==
io
.
EOF
{
break
}
if
err
!=
nil
{
t
.
Fatalf
(
"r.Body.Read() = %v"
,
err
)
}
}
if
got
,
want
:=
r
.
Trailer
.
Get
(
"foo"
),
"bar"
;
got
!=
want
{
t
.
Errorf
(
"r.Trailer.Get(foo): %v; want %v"
,
got
,
want
)
}
})
defer
st
.
Close
()
res
,
err
:=
st
.
http1
(
requestParam
{
name
:
"TestH1H1RequestTrailer"
,
body
:
[]
byte
(
"1"
),
trailer
:
[]
hpack
.
HeaderField
{
pair
(
"foo"
,
"bar"
),
},
})
if
err
!=
nil
{
t
.
Fatalf
(
"Error st.http1() = %v"
,
err
)
}
if
got
,
want
:=
res
.
status
,
200
;
got
!=
want
{
t
.
Errorf
(
"res.status: %v; want %v"
,
got
,
want
)
}
}
// TestH1H2ConnectFailure tests that server handles the situation that
// connection attempt to HTTP/2 backend failed.
func
TestH1H2ConnectFailure
(
t
*
testing
.
T
)
{
...
...
integration-tests/nghttpx_http2_test.go
View file @
bff5a28d
...
...
@@ -520,6 +520,41 @@ func TestH2H1ServerPush(t *testing.T) {
}
}
// TestH2H1RequestTrailer tests request trailer part is forwarded to
// backend.
func
TestH2H1RequestTrailer
(
t
*
testing
.
T
)
{
st
:=
newServerTester
(
nil
,
t
,
func
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
buf
:=
make
([]
byte
,
4096
)
for
{
_
,
err
:=
r
.
Body
.
Read
(
buf
)
if
err
==
io
.
EOF
{
break
}
if
err
!=
nil
{
t
.
Fatalf
(
"r.Body.Read() = %v"
,
err
)
}
}
if
got
,
want
:=
r
.
Trailer
.
Get
(
"foo"
),
"bar"
;
got
!=
want
{
t
.
Errorf
(
"r.Trailer.Get(foo): %v; want %v"
,
got
,
want
)
}
})
defer
st
.
Close
()
res
,
err
:=
st
.
http2
(
requestParam
{
name
:
"TestH2H1RequestTrailer"
,
body
:
[]
byte
(
"1"
),
trailer
:
[]
hpack
.
HeaderField
{
pair
(
"foo"
,
"bar"
),
},
})
if
err
!=
nil
{
t
.
Fatalf
(
"Error st.http2() = %v"
,
err
)
}
if
got
,
want
:=
res
.
status
,
200
;
got
!=
want
{
t
.
Errorf
(
"res.status: %v; want %v"
,
got
,
want
)
}
}
// TestH2H1GracefulShutdown tests graceful shutdown.
func
TestH2H1GracefulShutdown
(
t
*
testing
.
T
)
{
st
:=
newServerTester
(
nil
,
t
,
noopHandler
)
...
...
integration-tests/server_tester.go
View file @
bff5a28d
...
...
@@ -255,6 +255,27 @@ type requestParam struct {
path
string
// path, defaults to /
header
[]
hpack
.
HeaderField
// additional request header fields
body
[]
byte
// request body
trailer
[]
hpack
.
HeaderField
// trailer part
}
// wrapper for request body to set trailer part
type
chunkedBodyReader
struct
{
trailer
[]
hpack
.
HeaderField
trailerWritten
bool
body
io
.
Reader
req
*
http
.
Request
}
func
(
cbr
*
chunkedBodyReader
)
Read
(
p
[]
byte
)
(
n
int
,
err
error
)
{
// document says that we have to set http.Request.Trailer
// after request was sent and before body returns EOF.
if
!
cbr
.
trailerWritten
{
cbr
.
trailerWritten
=
true
for
_
,
h
:=
range
cbr
.
trailer
{
cbr
.
req
.
Trailer
.
Set
(
h
.
Name
,
h
.
Value
)
}
}
return
cbr
.
body
.
Read
(
p
)
}
func
(
st
*
serverTester
)
http1
(
rp
requestParam
)
(
*
serverResponse
,
error
)
{
...
...
@@ -264,8 +285,16 @@ func (st *serverTester) http1(rp requestParam) (*serverResponse, error) {
}
var
body
io
.
Reader
var
cbr
*
chunkedBodyReader
if
rp
.
body
!=
nil
{
body
=
bytes
.
NewBuffer
(
rp
.
body
)
if
len
(
rp
.
trailer
)
!=
0
{
cbr
=
&
chunkedBodyReader
{
trailer
:
rp
.
trailer
,
body
:
body
,
}
body
=
cbr
}
}
req
,
err
:=
http
.
NewRequest
(
method
,
st
.
url
,
body
)
if
err
!=
nil
{
...
...
@@ -275,7 +304,15 @@ func (st *serverTester) http1(rp requestParam) (*serverResponse, error) {
req
.
Header
.
Add
(
h
.
Name
,
h
.
Value
)
}
req
.
Header
.
Add
(
"Test-Case"
,
rp
.
name
)
if
cbr
!=
nil
{
cbr
.
req
=
req
// this makes request use chunked encoding
req
.
ContentLength
=
-
1
req
.
Trailer
=
make
(
http
.
Header
)
for
_
,
h
:=
range
cbr
.
trailer
{
req
.
Trailer
.
Set
(
h
.
Name
,
""
)
}
}
if
err
:=
req
.
Write
(
st
.
conn
);
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -473,7 +510,7 @@ func (st *serverTester) http2(rp requestParam) (*serverResponse, error) {
err
:=
st
.
fr
.
WriteHeaders
(
http2
.
HeadersFrameParam
{
StreamID
:
id
,
EndStream
:
len
(
rp
.
body
)
==
0
,
EndStream
:
len
(
rp
.
body
)
==
0
&&
len
(
rp
.
trailer
)
==
0
,
EndHeaders
:
true
,
BlockFragment
:
st
.
headerBlkBuf
.
Bytes
(),
})
...
...
@@ -483,7 +520,23 @@ func (st *serverTester) http2(rp requestParam) (*serverResponse, error) {
if
len
(
rp
.
body
)
!=
0
{
// TODO we assume rp.body fits in 1 frame
if
err
:=
st
.
fr
.
WriteData
(
id
,
true
,
rp
.
body
);
err
!=
nil
{
if
err
:=
st
.
fr
.
WriteData
(
id
,
len
(
rp
.
trailer
)
==
0
,
rp
.
body
);
err
!=
nil
{
return
nil
,
err
}
}
if
len
(
rp
.
trailer
)
!=
0
{
st
.
headerBlkBuf
.
Reset
()
for
_
,
h
:=
range
rp
.
trailer
{
_
=
st
.
enc
.
WriteField
(
h
)
}
err
:=
st
.
fr
.
WriteHeaders
(
http2
.
HeadersFrameParam
{
StreamID
:
id
,
EndStream
:
true
,
EndHeaders
:
true
,
BlockFragment
:
st
.
headerBlkBuf
.
Bytes
(),
})
if
err
!=
nil
{
return
nil
,
err
}
}
...
...
src/HttpServer.cc
View file @
bff5a28d
...
...
@@ -690,12 +690,22 @@ int Http2Handler::submit_file_response(const std::string &status,
http2
::
make_nv_ls
(
"content-length"
,
content_length
),
http2
::
make_nv_ll
(
"cache-control"
,
"max-age=3600"
),
http2
::
make_nv_ls
(
"date"
,
sessions_
->
get_cached_date
()),
http2
::
make_nv_ll
(
""
,
""
));
http2
::
make_nv_ll
(
""
,
""
)
,
http2
::
make_nv_ll
(
""
,
""
)
);
size_t
nvlen
=
5
;
if
(
last_modified
!=
0
)
{
last_modified_str
=
util
::
http_date
(
last_modified
);
nva
[
nvlen
++
]
=
http2
::
make_nv_ls
(
"last-modified"
,
last_modified_str
);
}
auto
&
trailer
=
get_config
()
->
trailer
;
std
::
string
trailer_names
;
if
(
!
trailer
.
empty
())
{
trailer_names
=
trailer
[
0
].
name
;
for
(
size_t
i
=
1
;
i
<
trailer
.
size
();
++
i
)
{
trailer_names
+=
", "
;
trailer_names
+=
trailer
[
i
].
name
;
}
nva
[
nvlen
++
]
=
http2
::
make_nv_ls
(
"trailer"
,
trailer_names
);
}
return
nghttp2_submit_response
(
session_
,
stream
->
stream_id
,
nva
.
data
(),
nvlen
,
data_prd
);
}
...
...
@@ -832,7 +842,6 @@ ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id,
auto
config
=
hd
->
get_config
();
if
(
!
config
->
trailer
.
empty
())
{
*
data_flags
|=
NGHTTP2_DATA_FLAG_NO_END_STREAM
;
std
::
vector
<
nghttp2_nv
>
nva
;
nva
.
reserve
(
config
->
trailer
.
size
());
for
(
auto
&
kv
:
config
->
trailer
)
{
...
...
@@ -840,7 +849,11 @@ ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id,
}
rv
=
nghttp2_submit_trailer
(
session
,
stream_id
,
nva
.
data
(),
nva
.
size
());
if
(
rv
!=
0
)
{
*
data_flags
&=
~
NGHTTP2_DATA_FLAG_NO_END_STREAM
;
if
(
nghttp2_is_fatal
(
rv
))
{
return
NGHTTP2_ERR_CALLBACK_FAILURE
;
}
}
else
{
*
data_flags
|=
NGHTTP2_DATA_FLAG_NO_END_STREAM
;
}
}
...
...
src/http2.cc
View file @
bff5a28d
...
...
@@ -230,7 +230,6 @@ void copy_headers_to_nva(std::vector<nghttp2_nv> &nva, const Headers &headers) {
case
HD_KEEP_ALIVE
:
case
HD_PROXY_CONNECTION
:
case
HD_SERVER
:
case
HD_TRAILER
:
case
HD_TRANSFER_ENCODING
:
case
HD_UPGRADE
:
case
HD_VIA
:
...
...
@@ -256,7 +255,6 @@ void build_http1_headers_from_headers(std::string &hdrs,
case
HD_KEEP_ALIVE
:
case
HD_PROXY_CONNECTION
:
case
HD_SERVER
:
case
HD_TRAILER
:
case
HD_UPGRADE
:
case
HD_VIA
:
case
HD_X_FORWARDED_FOR
:
...
...
src/nghttp.cc
View file @
bff5a28d
...
...
@@ -376,6 +376,16 @@ int submit_request(HttpClient *client, const Headers &headers, Request *req) {
nva
.
push_back
(
http2
::
make_nv
(
kv
.
name
,
kv
.
value
,
kv
.
no_index
));
}
std
::
string
trailer_names
;
if
(
!
config
.
trailer
.
empty
())
{
trailer_names
=
config
.
trailer
[
0
].
name
;
for
(
size_t
i
=
1
;
i
<
config
.
trailer
.
size
();
++
i
)
{
trailer_names
+=
", "
;
trailer_names
+=
config
.
trailer
[
i
].
name
;
}
nva
.
push_back
(
http2
::
make_nv_ls
(
"trailer"
,
trailer_names
));
}
auto
stream_id
=
nghttp2_submit_request
(
client
->
session
,
&
req
->
pri_spec
,
nva
.
data
(),
nva
.
size
(),
req
->
data_prd
,
req
);
...
...
@@ -2128,7 +2138,6 @@ ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id,
if
(
nread
==
0
)
{
*
data_flags
|=
NGHTTP2_DATA_FLAG_EOF
;
if
(
!
config
.
trailer
.
empty
())
{
*
data_flags
|=
NGHTTP2_DATA_FLAG_NO_END_STREAM
;
std
::
vector
<
nghttp2_nv
>
nva
;
nva
.
reserve
(
config
.
trailer
.
size
());
for
(
auto
&
kv
:
config
.
trailer
)
{
...
...
@@ -2136,7 +2145,11 @@ ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id,
}
rv
=
nghttp2_submit_trailer
(
session
,
stream_id
,
nva
.
data
(),
nva
.
size
());
if
(
rv
!=
0
)
{
*
data_flags
&=
~
NGHTTP2_DATA_FLAG_NO_END_STREAM
;
if
(
nghttp2_is_fatal
(
rv
))
{
return
NGHTTP2_ERR_CALLBACK_FAILURE
;
}
}
else
{
*
data_flags
|=
NGHTTP2_DATA_FLAG_NO_END_STREAM
;
}
}
}
else
{
...
...
src/shrpx_downstream.cc
View file @
bff5a28d
...
...
@@ -120,8 +120,9 @@ Downstream::Downstream(Upstream *upstream, int32_t stream_id, int32_t priority)
response_minor_
(
1
),
upgrade_request_
(
false
),
upgraded_
(
false
),
http2_upgrade_seen_
(
false
),
chunked_request_
(
false
),
request_connection_close_
(
false
),
request_header_key_prev_
(
false
),
request_http2_expect_body_
(
false
),
chunked_response_
(
false
),
response_connection_close_
(
false
),
response_header_key_prev_
(
false
),
request_trailer_key_prev_
(
false
),
request_http2_expect_body_
(
false
),
chunked_response_
(
false
),
response_connection_close_
(
false
),
response_header_key_prev_
(
false
),
response_trailer_key_prev_
(
false
),
expect_final_response_
(
false
),
request_pending_
(
false
)
{
ev_timer_init
(
&
upstream_rtimer_
,
&
upstream_rtimeoutcb
,
0.
,
...
...
@@ -287,6 +288,45 @@ const std::string &Downstream::get_assembled_request_cookie() const {
return
assembled_request_cookie_
;
}
namespace
{
void
add_header
(
bool
&
key_prev
,
size_t
&
sum
,
Headers
&
headers
,
std
::
string
name
,
std
::
string
value
)
{
key_prev
=
true
;
sum
+=
name
.
size
()
+
value
.
size
();
headers
.
emplace_back
(
std
::
move
(
name
),
std
::
move
(
value
));
}
}
// namespace
namespace
{
void
append_last_header_key
(
bool
key_prev
,
size_t
&
sum
,
Headers
&
headers
,
const
char
*
data
,
size_t
len
)
{
assert
(
key_prev
);
sum
+=
len
;
auto
&
item
=
headers
.
back
();
item
.
name
.
append
(
data
,
len
);
}
}
// namespace
namespace
{
void
append_last_header_value
(
bool
key_prev
,
size_t
&
sum
,
Headers
&
headers
,
const
char
*
data
,
size_t
len
)
{
assert
(
!
key_prev
);
sum
+=
len
;
auto
&
item
=
headers
.
back
();
item
.
value
.
append
(
data
,
len
);
}
}
// namespace
namespace
{
void
set_last_header_value
(
bool
&
key_prev
,
size_t
&
sum
,
Headers
&
headers
,
const
char
*
data
,
size_t
len
)
{
key_prev
=
false
;
sum
+=
len
;
auto
&
item
=
headers
.
back
();
item
.
value
.
assign
(
data
,
len
);
}
}
// namespace
namespace
{
int
index_headers
(
http2
::
HeaderIndex
&
hdidx
,
Headers
&
headers
,
int64_t
&
content_length
)
{
...
...
@@ -333,16 +373,13 @@ Downstream::get_request_header(const std::string &name) const {
}
void
Downstream
::
add_request_header
(
std
::
string
name
,
std
::
string
value
)
{
request_header_key_prev_
=
true
;
request_headers_sum_
+=
name
.
size
()
+
value
.
size
();
request_headers_
.
emplace_back
(
std
::
move
(
name
),
std
::
move
(
value
));
add_header
(
request_header_key_prev_
,
request_headers_sum_
,
request_headers_
,
std
::
move
(
name
),
std
::
move
(
value
));
}
void
Downstream
::
set_last_request_header_value
(
std
::
string
value
)
{
request_header_key_prev_
=
false
;
request_headers_sum_
+=
value
.
size
();
Headers
::
value_type
&
item
=
request_headers_
.
back
();
item
.
value
=
std
::
move
(
value
);
void
Downstream
::
set_last_request_header_value
(
const
char
*
data
,
size_t
len
)
{
set_last_header_value
(
request_header_key_prev_
,
request_headers_sum_
,
request_headers_
,
data
,
len
);
}
void
Downstream
::
add_request_header
(
const
uint8_t
*
name
,
size_t
namelen
,
...
...
@@ -359,18 +396,14 @@ bool Downstream::get_request_header_key_prev() const {
}
void
Downstream
::
append_last_request_header_key
(
const
char
*
data
,
size_t
len
)
{
assert
(
request_header_key_prev_
);
request_headers_sum_
+=
len
;
auto
&
item
=
request_headers_
.
back
();
item
.
name
.
append
(
data
,
len
);
append_last_header_key
(
request_header_key_prev_
,
request_headers_sum_
,
request_headers_
,
data
,
len
);
}
void
Downstream
::
append_last_request_header_value
(
const
char
*
data
,
size_t
len
)
{
assert
(
!
request_header_key_prev_
);
request_headers_sum_
+=
len
;
auto
&
item
=
request_headers_
.
back
();
item
.
value
.
append
(
data
,
len
);
append_last_header_value
(
request_header_key_prev_
,
request_headers_sum_
,
request_headers_
,
data
,
len
);
}
void
Downstream
::
clear_request_headers
()
{
...
...
@@ -382,6 +415,45 @@ size_t Downstream::get_request_headers_sum() const {
return
request_headers_sum_
;
}
void
Downstream
::
add_request_trailer
(
const
uint8_t
*
name
,
size_t
namelen
,
const
uint8_t
*
value
,
size_t
valuelen
,
bool
no_index
,
int16_t
token
)
{
// we never index trailer part. Header size limit should be applied
// to all request header fields combined.
request_headers_sum_
+=
namelen
+
valuelen
;
http2
::
add_header
(
request_trailers_
,
name
,
namelen
,
value
,
valuelen
,
no_index
,
-
1
);
}
const
Headers
&
Downstream
::
get_request_trailers
()
const
{
return
request_trailers_
;
}
void
Downstream
::
add_request_trailer
(
std
::
string
name
,
std
::
string
value
)
{
add_header
(
request_trailer_key_prev_
,
request_headers_sum_
,
request_trailers_
,
std
::
move
(
name
),
std
::
move
(
value
));
}
void
Downstream
::
set_last_request_trailer_value
(
const
char
*
data
,
size_t
len
)
{
set_last_header_value
(
request_trailer_key_prev_
,
request_headers_sum_
,
request_trailers_
,
data
,
len
);
}
bool
Downstream
::
get_request_trailer_key_prev
()
const
{
return
request_trailer_key_prev_
;
}
void
Downstream
::
append_last_request_trailer_key
(
const
char
*
data
,
size_t
len
)
{
append_last_header_key
(
request_trailer_key_prev_
,
request_headers_sum_
,
request_trailers_
,
data
,
len
);
}
void
Downstream
::
append_last_request_trailer_value
(
const
char
*
data
,
size_t
len
)
{
append_last_header_value
(
request_trailer_key_prev_
,
request_headers_sum_
,
request_trailers_
,
data
,
len
);
}
void
Downstream
::
set_request_method
(
std
::
string
method
)
{
request_method_
=
std
::
move
(
method
);
}
...
...
@@ -592,16 +664,13 @@ void Downstream::rewrite_location_response_header(
}
void
Downstream
::
add_response_header
(
std
::
string
name
,
std
::
string
value
)
{
response_header_key_prev_
=
true
;
response_headers_sum_
+=
name
.
size
()
+
value
.
size
();
response_headers_
.
emplace_back
(
std
::
move
(
name
),
std
::
move
(
value
));
add_header
(
response_header_key_prev_
,
response_headers_sum_
,
response_headers_
,
std
::
move
(
name
),
std
::
move
(
value
));
}
void
Downstream
::
set_last_response_header_value
(
std
::
string
value
)
{
response_header_key_prev_
=
false
;
response_headers_sum_
+=
value
.
size
();
auto
&
item
=
response_headers_
.
back
();
item
.
value
=
std
::
move
(
value
);
void
Downstream
::
set_last_response_header_value
(
const
char
*
data
,
size_t
len
)
{
set_last_header_value
(
response_header_key_prev_
,
response_headers_sum_
,
response_headers_
,
data
,
len
);
}
void
Downstream
::
add_response_header
(
std
::
string
name
,
std
::
string
value
,
...
...
@@ -626,18 +695,14 @@ bool Downstream::get_response_header_key_prev() const {
}
void
Downstream
::
append_last_response_header_key
(
const
char
*
data
,
size_t
len
)
{
assert
(
response_header_key_prev_
);
response_headers_sum_
+=
len
;
auto
&
item
=
response_headers_
.
back
();
item
.
name
.
append
(
data
,
len
);
append_last_header_key
(
response_header_key_prev_
,
response_headers_sum_
,
response_headers_
,
data
,
len
);
}
void
Downstream
::
append_last_response_header_value
(
const
char
*
data
,
size_t
len
)
{
assert
(
!
response_header_key_prev_
);
response_headers_sum_
+=
len
;
auto
&
item
=
response_headers_
.
back
();
item
.
value
.
append
(
data
,
len
);
append_last_header_value
(
response_header_key_prev_
,
response_headers_sum_
,
response_headers_
,
data
,
len
);
}
void
Downstream
::
clear_response_headers
()
{
...
...
@@ -649,10 +714,48 @@ size_t Downstream::get_response_headers_sum() const {
return
response_headers_sum_
;
}
const
Headers
&
Downstream
::
get_response_trailers
()
const
{
return
response_trailers_
;
}
void
Downstream
::
add_response_trailer
(
const
uint8_t
*
name
,
size_t
namelen
,
const
uint8_t
*
value
,
size_t
valuelen
,
bool
no_index
,
int16_t
token
)
{
response_headers_sum_
+=
namelen
+
valuelen
;
http2
::
add_header
(
response_trailers_
,
name
,
namelen
,
value
,
valuelen
,
no_index
,
-
1
);
}
unsigned
int
Downstream
::
get_response_http_status
()
const
{
return
response_http_status_
;
}
void
Downstream
::
add_response_trailer
(
std
::
string
name
,
std
::
string
value
)
{
add_header
(
response_trailer_key_prev_
,
response_headers_sum_
,
response_trailers_
,
std
::
move
(
name
),
std
::
move
(
value
));
}
void
Downstream
::
set_last_response_trailer_value
(
const
char
*
data
,
size_t
len
)
{
set_last_header_value
(
response_trailer_key_prev_
,
response_headers_sum_
,
response_trailers_
,
data
,
len
);
}
bool
Downstream
::
get_response_trailer_key_prev
()
const
{
return
response_trailer_key_prev_
;
}
void
Downstream
::
append_last_response_trailer_key
(
const
char
*
data
,
size_t
len
)
{
append_last_header_key
(
response_trailer_key_prev_
,
response_headers_sum_
,
response_trailers_
,
data
,
len
);
}
void
Downstream
::
append_last_response_trailer_value
(
const
char
*
data
,
size_t
len
)
{
append_last_header_value
(
response_trailer_key_prev_
,
response_headers_sum_
,
response_trailers_
,
data
,
len
);
}
void
Downstream
::
set_response_http_status
(
unsigned
int
status
)
{
response_http_status_
=
status
;
}
...
...
src/shrpx_downstream.h
View file @
bff5a28d
...
...
@@ -113,7 +113,7 @@ public:
// 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
set_last_request_header_value
(
const
char
*
data
,
size_t
len
);
void
add_request_header
(
const
uint8_t
*
name
,
size_t
namelen
,
const
uint8_t
*
value
,
size_t
valuelen
,
bool
no_index
,
...
...
@@ -127,6 +127,16 @@ public:
size_t
get_request_headers_sum
()
const
;
const
Headers
&
get_request_trailers
()
const
;
void
add_request_trailer
(
const
uint8_t
*
name
,
size_t
namelen
,
const
uint8_t
*
value
,
size_t
valuelen
,
bool
no_index
,
int16_t
token
);
void
add_request_trailer
(
std
::
string
name
,
std
::
string
value
);
void
set_last_request_trailer_value
(
const
char
*
data
,
size_t
len
);
bool
get_request_trailer_key_prev
()
const
;
void
append_last_request_trailer_key
(
const
char
*
data
,
size_t
len
);
void
append_last_request_trailer_value
(
const
char
*
data
,
size_t
len
);
void
set_request_method
(
std
::
string
method
);
const
std
::
string
&
get_request_method
()
const
;
void
set_request_path
(
std
::
string
path
);
...
...
@@ -201,7 +211,7 @@ public:
// Rewrites the location response header field.
void
rewrite_location_response_header
(
const
std
::
string
&
upstream_scheme
);
void
add_response_header
(
std
::
string
name
,
std
::
string
value
);
void
set_last_response_header_value
(
std
::
string
value
);
void
set_last_response_header_value
(
const
char
*
data
,
size_t
len
);
void
add_response_header
(
std
::
string
name
,
std
::
string
value
,
int16_t
token
);
void
add_response_header
(
const
uint8_t
*
name
,
size_t
namelen
,
...
...
@@ -216,6 +226,16 @@ public:
size_t
get_response_headers_sum
()
const
;
const
Headers
&
get_response_trailers
()
const
;
void
add_response_trailer
(
const
uint8_t
*
name
,
size_t
namelen
,
const
uint8_t
*
value
,
size_t
valuelen
,
bool
no_index
,
int16_t
token
);
void
add_response_trailer
(
std
::
string
name
,
std
::
string
value
);
void
set_last_response_trailer_value
(
const
char
*
data
,
size_t
len
);
bool
get_response_trailer_key_prev
()
const
;
void
append_last_response_trailer_key
(
const
char
*
data
,
size_t
len
);
void
append_last_response_trailer_value
(
const
char
*
data
,
size_t
len
);
unsigned
int
get_response_http_status
()
const
;
void
set_response_http_status
(
unsigned
int
status
);
void
set_response_major
(
int
major
);
...
...
@@ -308,6 +328,11 @@ private:
Headers
request_headers_
;
Headers
response_headers_
;
// trailer part. For HTTP/1.1, trailer part is only included with
// chunked encoding. For HTTP/2, there is no such limit.
Headers
request_trailers_
;
Headers
response_trailers_
;
std
::
chrono
::
high_resolution_clock
::
time_point
request_start_time_
;
std
::
string
request_method_
;
...
...
@@ -385,11 +410,13 @@ private:
bool
chunked_request_
;
bool
request_connection_close_
;
bool
request_header_key_prev_
;
bool
request_trailer_key_prev_
;
bool
request_http2_expect_body_
;
bool
chunked_response_
;
bool
response_connection_close_
;
bool
response_header_key_prev_
;
bool
response_trailer_key_prev_
;
bool
expect_final_response_
;
// true if downstream request is pending because backend connection
// has not been established or should be checked before use;
...
...
src/shrpx_http2_downstream_connection.cc
View file @
bff5a28d
...
...
@@ -159,6 +159,7 @@ ssize_t http2_data_read_callback(nghttp2_session *session, int32_t stream_id,
uint8_t
*
buf
,
size_t
length
,
uint32_t
*
data_flags
,
nghttp2_data_source
*
source
,
void
*
user_data
)
{
int
rv
;
auto
sd
=
static_cast
<
StreamData
*>
(
nghttp2_session_get_stream_user_data
(
session
,
stream_id
));
if
(
!
sd
||
!
sd
->
dconn
)
{
...
...
@@ -201,6 +202,23 @@ ssize_t http2_data_read_callback(nghttp2_session *session, int32_t stream_id,
!
downstream
->
get_upgraded
())))
{
*
data_flags
|=
NGHTTP2_DATA_FLAG_EOF
;
auto
&
trailers
=
downstream
->
get_request_trailers
();
if
(
!
trailers
.
empty
())
{
std
::
vector
<
nghttp2_nv
>
nva
;
nva
.
reserve
(
trailers
.
size
());
http2
::
copy_headers_to_nva
(
nva
,
trailers
);
if
(
!
nva
.
empty
())
{
rv
=
nghttp2_submit_trailer
(
session
,
stream_id
,
nva
.
data
(),
nva
.
size
());
if
(
rv
!=
0
)
{
if
(
nghttp2_is_fatal
(
rv
))
{
return
NGHTTP2_ERR_CALLBACK_FAILURE
;
}
}
else
{
*
data_flags
|=
NGHTTP2_DATA_FLAG_NO_END_STREAM
;
}
}
}
}
if
(
!
input_empty
)
{
...
...
@@ -275,7 +293,7 @@ int Http2DownstreamConnection::push_request_headers() {
cookies
=
downstream_
->
crumble_request_cookie
();
}
//
8
means:
//
9
means:
// 1. :method
// 2. :scheme
// 3. :path
...
...
@@ -284,8 +302,9 @@ int Http2DownstreamConnection::push_request_headers() {
// 6. via (optional)
// 7. x-forwarded-for (optional)
// 8. x-forwarded-proto (optional)
// 9. te (optional)
auto
nva
=
std
::
vector
<
nghttp2_nv
>
();
nva
.
reserve
(
nheader
+
8
+
cookies
.
size
());
nva
.
reserve
(
nheader
+
9
+
cookies
.
size
());
std
::
string
via_value
;
std
::
string
xff_value
;
...
...
@@ -432,6 +451,11 @@ int Http2DownstreamConnection::push_request_headers() {
nva
.
push_back
(
http2
::
make_nv_ls
(
"via"
,
via_value
));
}
auto
te
=
downstream_
->
get_request_header
(
http2
::
HD_TE
);
if
(
te
)
{
nva
.
push_back
(
http2
::
make_nv_ls
(
"te"
,
te
->
value
));
}
if
(
LOG_ENABLED
(
INFO
))
{
std
::
stringstream
ss
;
for
(
auto
&
nv
:
nva
)
{
...
...
src/shrpx_http2_session.cc
View file @
bff5a28d
...
...
@@ -668,20 +668,35 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
return
0
;
}
if
(
frame
->
hd
.
type
!=
NGHTTP2_HEADERS
||
(
frame
->
headers
.
cat
!=
NGHTTP2_HCAT_RESPONSE
&&
!
downstream
->
get_expect_final_response
()))
{
if
(
frame
->
hd
.
type
!=
NGHTTP2_HEADERS
)
{
return
0
;
}
auto
trailer
=
frame
->
headers
.
cat
!=
NGHTTP2_HCAT_RESPONSE
&&
!
downstream
->
get_expect_final_response
();
if
(
downstream
->
get_response_headers_sum
()
>
Downstream
::
MAX_HEADERS_SUM
)
{
if
(
LOG_ENABLED
(
INFO
))
{
DLOG
(
INFO
,
downstream
)
<<
"Too large header block size="
<<
downstream
->
get_response_headers_sum
();
}
if
(
trailer
)
{
// we don't care trailer part exceeds header size limit; just
// discard it.
return
0
;
}
return
NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE
;
}
if
(
trailer
)
{
// just store header fields for trailer part
downstream
->
add_response_trailer
(
name
,
namelen
,
value
,
valuelen
,
flags
&
NGHTTP2_NV_FLAG_NO_INDEX
,
-
1
);
return
0
;
}
auto
token
=
http2
::
lookup_token
(
name
,
namelen
);
if
(
token
==
http2
::
HD_CONTENT_LENGTH
)
{
...
...
@@ -891,10 +906,6 @@ int on_frame_recv_callback(nghttp2_session *session, const nghttp2_frame *frame,
if
(
rv
!=
0
)
{
return
0
;
}
}
else
if
((
frame
->
hd
.
flags
&
NGHTTP2_FLAG_END_STREAM
)
==
0
)
{
http2session
->
submit_rst_stream
(
frame
->
hd
.
stream_id
,
NGHTTP2_PROTOCOL_ERROR
);
return
0
;
}
}
...
...
src/shrpx_http2_upstream.cc
View file @
bff5a28d
...
...
@@ -187,8 +187,7 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
verbose_on_header_callback
(
session
,
frame
,
name
,
namelen
,
value
,
valuelen
,
flags
,
user_data
);
}
if
(
frame
->
hd
.
type
!=
NGHTTP2_HEADERS
||
frame
->
headers
.
cat
!=
NGHTTP2_HCAT_REQUEST
)
{
if
(
frame
->
hd
.
type
!=
NGHTTP2_HEADERS
)
{
return
0
;
}
auto
upstream
=
static_cast
<
Http2Upstream
*>
(
user_data
);
...
...
@@ -207,12 +206,25 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
<<
downstream
->
get_request_headers_sum
();
}
// just ignore header fields if this is trailer part.
if
(
frame
->
headers
.
cat
==
NGHTTP2_HCAT_HEADERS
)
{
return
0
;
}
if
(
upstream
->
error_reply
(
downstream
,
431
)
!=
0
)
{
return
NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE
;
}
return
0
;
}
if
(
frame
->
headers
.
cat
==
NGHTTP2_HCAT_HEADERS
)
{
// just store header fields for trailer part
downstream
->
add_request_trailer
(
name
,
namelen
,
value
,
valuelen
,
flags
&
NGHTTP2_NV_FLAG_NO_INDEX
,
-
1
);
return
0
;
}
auto
token
=
http2
::
lookup_token
(
name
,
namelen
);
if
(
token
==
http2
::
HD_CONTENT_LENGTH
)
{
...
...
@@ -1056,6 +1068,7 @@ ssize_t downstream_data_read_callback(nghttp2_session *session,
size_t
length
,
uint32_t
*
data_flags
,
nghttp2_data_source
*
source
,
void
*
user_data
)
{
int
rv
;
auto
downstream
=
static_cast
<
Downstream
*>
(
source
->
ptr
);
auto
upstream
=
static_cast
<
Http2Upstream
*>
(
downstream
->
get_upstream
());
auto
body
=
downstream
->
get_response_buf
();
...
...
@@ -1081,7 +1094,23 @@ ssize_t downstream_data_read_callback(nghttp2_session *session,
*
data_flags
|=
NGHTTP2_DATA_FLAG_EOF
;
if
(
!
downstream
->
get_upgraded
())
{
auto
&
trailers
=
downstream
->
get_response_trailers
();
if
(
!
trailers
.
empty
())
{
std
::
vector
<
nghttp2_nv
>
nva
;
nva
.
reserve
(
trailers
.
size
());
http2
::
copy_headers_to_nva
(
nva
,
trailers
);
if
(
!
nva
.
empty
())
{
rv
=
nghttp2_submit_trailer
(
session
,
stream_id
,
nva
.
data
(),
nva
.
size
());
if
(
rv
!=
0
)
{
if
(
nghttp2_is_fatal
(
rv
))
{
return
NGHTTP2_ERR_CALLBACK_FAILURE
;
}
}
else
{
*
data_flags
|=
NGHTTP2_DATA_FLAG_NO_END_STREAM
;
}
}
}
if
(
nghttp2_session_get_stream_remote_close
(
session
,
stream_id
)
==
0
)
{
upstream
->
rst_stream
(
downstream
,
NGHTTP2_NO_ERROR
);
}
...
...
src/shrpx_http_downstream_connection.cc
View file @
bff5a28d
...
...
@@ -403,7 +403,16 @@ int HttpDownstreamConnection::end_upload_data() {
}
auto
output
=
downstream_
->
get_request_buf
();
output
->
append
(
"0
\r\n\r\n
"
);
auto
&
trailers
=
downstream_
->
get_request_trailers
();
if
(
trailers
.
empty
())
{
output
->
append
(
"0
\r\n\r\n
"
);
}
else
{
output
->
append
(
"0
\r\n
"
);
std
::
string
trailer_part
;
http2
::
build_http1_headers_from_headers
(
trailer_part
,
trailers
);
output
->
append
(
trailer_part
.
c_str
(),
trailer_part
.
size
());
output
->
append
(
"
\r\n
"
);
}
signal_write
();
...
...
@@ -555,14 +564,19 @@ int htp_hdrs_completecb(http_parser *htp) {
namespace
{
int
htp_hdr_keycb
(
http_parser
*
htp
,
const
char
*
data
,
size_t
len
)
{
auto
downstream
=
static_cast
<
Downstream
*>
(
htp
->
data
);
if
(
downstream
->
get_response_state
()
!
=
Downstream
::
INITIAL
)
{
// ignore trailers
return
0
;
}
if
(
downstream
->
get_response_header_key_prev
())
{
downstream
->
append_last_response_header_key
(
data
,
len
);
if
(
downstream
->
get_response_state
()
=
=
Downstream
::
INITIAL
)
{
if
(
downstream
->
get_response_header_key_prev
())
{
downstream
->
append_last_response_header_key
(
data
,
len
)
;
}
else
{
downstream
->
add_response_header
(
std
::
string
(
data
,
len
),
""
);
}
}
else
{
downstream
->
add_response_header
(
std
::
string
(
data
,
len
),
""
);
// trailer part
if
(
downstream
->
get_response_trailer_key_prev
())
{
downstream
->
append_last_response_trailer_key
(
data
,
len
);
}
else
{
downstream
->
add_response_trailer
(
std
::
string
(
data
,
len
),
""
);
}
}
if
(
downstream
->
get_response_headers_sum
()
>
Downstream
::
MAX_HEADERS_SUM
)
{
if
(
LOG_ENABLED
(
INFO
))
{
...
...
@@ -578,14 +592,18 @@ int htp_hdr_keycb(http_parser *htp, const char *data, size_t len) {
namespace
{
int
htp_hdr_valcb
(
http_parser
*
htp
,
const
char
*
data
,
size_t
len
)
{
auto
downstream
=
static_cast
<
Downstream
*>
(
htp
->
data
);
if
(
downstream
->
get_response_state
()
!
=
Downstream
::
INITIAL
)
{
// ignore trailers
return
0
;
}
if
(
downstream
->
get_response_header_key_prev
())
{
downstream
->
set_last_response_header_value
(
std
::
string
(
data
,
len
));
if
(
downstream
->
get_response_state
()
=
=
Downstream
::
INITIAL
)
{
if
(
downstream
->
get_response_header_key_prev
())
{
downstream
->
set_last_response_header_value
(
data
,
len
)
;
}
else
{
downstream
->
append_last_response_header_value
(
data
,
len
);
}
}
else
{
downstream
->
append_last_response_header_value
(
data
,
len
);
if
(
downstream
->
get_response_trailer_key_prev
())
{
downstream
->
set_last_response_trailer_value
(
data
,
len
);
}
else
{
downstream
->
append_last_response_trailer_value
(
data
,
len
);
}
}
if
(
downstream
->
get_response_headers_sum
()
>
Downstream
::
MAX_HEADERS_SUM
)
{
if
(
LOG_ENABLED
(
INFO
))
{
...
...
src/shrpx_https_upstream.cc
View file @
bff5a28d
...
...
@@ -83,14 +83,19 @@ namespace {
int
htp_hdr_keycb
(
http_parser
*
htp
,
const
char
*
data
,
size_t
len
)
{
auto
upstream
=
static_cast
<
HttpsUpstream
*>
(
htp
->
data
);
auto
downstream
=
upstream
->
get_downstream
();
if
(
downstream
->
get_request_state
()
!
=
Downstream
::
INITIAL
)
{
// ignore trailers
return
0
;
}
if
(
downstream
->
get_request_header_key_prev
())
{
downstream
->
append_last_request_header_key
(
data
,
len
);
if
(
downstream
->
get_request_state
()
=
=
Downstream
::
INITIAL
)
{
if
(
downstream
->
get_request_header_key_prev
())
{
downstream
->
append_last_request_header_key
(
data
,
len
)
;
}
else
{
downstream
->
add_request_header
(
std
::
string
(
data
,
len
),
""
);
}
}
else
{
downstream
->
add_request_header
(
std
::
string
(
data
,
len
),
""
);
// trailer part
if
(
downstream
->
get_request_trailer_key_prev
())
{
downstream
->
append_last_request_trailer_key
(
data
,
len
);
}
else
{
downstream
->
add_request_trailer
(
std
::
string
(
data
,
len
),
""
);
}
}
if
(
downstream
->
get_request_headers_sum
()
>
Downstream
::
MAX_HEADERS_SUM
)
{
if
(
LOG_ENABLED
(
INFO
))
{
...
...
@@ -107,14 +112,18 @@ namespace {
int
htp_hdr_valcb
(
http_parser
*
htp
,
const
char
*
data
,
size_t
len
)
{
auto
upstream
=
static_cast
<
HttpsUpstream
*>
(
htp
->
data
);
auto
downstream
=
upstream
->
get_downstream
();
if
(
downstream
->
get_request_state
()
!
=
Downstream
::
INITIAL
)
{
// ignore trailers
return
0
;
}
if
(
downstream
->
get_request_header_key_prev
())
{
downstream
->
set_last_request_header_value
(
std
::
string
(
data
,
len
));
if
(
downstream
->
get_request_state
()
=
=
Downstream
::
INITIAL
)
{
if
(
downstream
->
get_request_header_key_prev
())
{
downstream
->
set_last_request_header_value
(
data
,
len
)
;
}
else
{
downstream
->
append_last_request_header_value
(
data
,
len
);
}
}
else
{
downstream
->
append_last_request_header_value
(
data
,
len
);
if
(
downstream
->
get_request_trailer_key_prev
())
{
downstream
->
set_last_request_trailer_value
(
data
,
len
);
}
else
{
downstream
->
append_last_request_trailer_value
(
data
,
len
);
}
}
if
(
downstream
->
get_request_headers_sum
()
>
Downstream
::
MAX_HEADERS_SUM
)
{
if
(
LOG_ENABLED
(
INFO
))
{
...
...
@@ -780,7 +789,16 @@ int HttpsUpstream::on_downstream_body(Downstream *downstream,
int
HttpsUpstream
::
on_downstream_body_complete
(
Downstream
*
downstream
)
{
if
(
downstream
->
get_chunked_response
())
{
auto
output
=
downstream
->
get_response_buf
();
output
->
append
(
"0
\r\n\r\n
"
);
auto
&
trailers
=
downstream
->
get_response_trailers
();
if
(
trailers
.
empty
())
{
output
->
append
(
"0
\r\n\r\n
"
);
}
else
{
output
->
append
(
"0
\r\n
"
);
std
::
string
trailer_part
;
http2
::
build_http1_headers_from_headers
(
trailer_part
,
trailers
);
output
->
append
(
trailer_part
.
c_str
(),
trailer_part
.
size
());
output
->
append
(
"
\r\n
"
);
}
}
if
(
LOG_ENABLED
(
INFO
))
{
DLOG
(
INFO
,
downstream
)
<<
"HTTP response completed"
;
...
...
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