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
7e217511
Commit
7e217511
authored
Jun 01, 2014
by
Tatsuhiro Tsujikawa
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
nghttpx: Code cleanup
Mainly make nested code block to rather flat style.
parent
8c67bbe3
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
436 additions
and
321 deletions
+436
-321
src/shrpx_http2_session.cc
src/shrpx_http2_session.cc
+36
-14
src/shrpx_http2_upstream.cc
src/shrpx_http2_upstream.cc
+132
-100
src/shrpx_https_upstream.cc
src/shrpx_https_upstream.cc
+118
-79
src/shrpx_spdy_upstream.cc
src/shrpx_spdy_upstream.cc
+150
-128
No files found.
src/shrpx_http2_session.cc
View file @
7e217511
...
...
@@ -272,19 +272,25 @@ void eventcb(bufferevent *bev, short events, void *ptr)
return
;
}
int
fd
=
bufferevent_getfd
(
bev
);
auto
fd
=
bufferevent_getfd
(
bev
);
int
val
=
1
;
if
(
setsockopt
(
fd
,
IPPROTO_TCP
,
TCP_NODELAY
,
reinterpret_cast
<
char
*>
(
&
val
),
sizeof
(
val
))
==
-
1
)
{
reinterpret_cast
<
char
*>
(
&
val
),
sizeof
(
val
))
==
-
1
)
{
SSLOG
(
WARNING
,
http2session
)
<<
"Setting option TCP_NODELAY failed: errno="
<<
errno
;
}
}
else
if
(
events
&
BEV_EVENT_EOF
)
{
return
;
}
if
(
events
&
BEV_EVENT_EOF
)
{
if
(
LOG_ENABLED
(
INFO
))
{
SSLOG
(
INFO
,
http2session
)
<<
"EOF"
;
}
http2session
->
disconnect
();
}
else
if
(
events
&
(
BEV_EVENT_ERROR
|
BEV_EVENT_TIMEOUT
))
{
return
;
}
if
(
events
&
(
BEV_EVENT_ERROR
|
BEV_EVENT_TIMEOUT
))
{
if
(
LOG_ENABLED
(
INFO
))
{
if
(
events
&
BEV_EVENT_ERROR
)
{
SSLOG
(
INFO
,
http2session
)
<<
"Network error"
;
...
...
@@ -293,6 +299,7 @@ void eventcb(bufferevent *bev, short events, void *ptr)
}
}
http2session
->
disconnect
();
return
;
}
}
}
// namespace
...
...
@@ -350,12 +357,18 @@ void proxy_eventcb(bufferevent *bev, short events, void *ptr)
SSLOG
(
ERROR
,
http2session
)
<<
"bufferevent_write() failed"
;
http2session
->
disconnect
();
}
}
else
if
(
events
&
BEV_EVENT_EOF
)
{
return
;
}
if
(
events
&
BEV_EVENT_EOF
)
{
if
(
LOG_ENABLED
(
INFO
))
{
SSLOG
(
INFO
,
http2session
)
<<
"Proxy EOF"
;
}
http2session
->
disconnect
();
}
else
if
(
events
&
(
BEV_EVENT_ERROR
|
BEV_EVENT_TIMEOUT
))
{
return
;
}
if
(
events
&
(
BEV_EVENT_ERROR
|
BEV_EVENT_TIMEOUT
))
{
if
(
LOG_ENABLED
(
INFO
))
{
if
(
events
&
BEV_EVENT_ERROR
)
{
SSLOG
(
INFO
,
http2session
)
<<
"Network error"
;
...
...
@@ -364,6 +377,7 @@ void proxy_eventcb(bufferevent *bev, short events, void *ptr)
}
}
http2session
->
disconnect
();
return
;
}
}
}
// namespace
...
...
@@ -409,7 +423,11 @@ int Http2Session::initiate_connection()
proxy_htp_
->
data
=
this
;
state_
=
PROXY_CONNECTING
;
}
else
if
(
state_
==
DISCONNECTED
||
state_
==
PROXY_CONNECTED
)
{
return
0
;
}
if
(
state_
==
DISCONNECTED
||
state_
==
PROXY_CONNECTED
)
{
if
(
LOG_ENABLED
(
INFO
))
{
SSLOG
(
INFO
,
this
)
<<
"Connecting to downstream server"
;
}
...
...
@@ -492,11 +510,12 @@ int Http2Session::initiate_connection()
if
(
state_
!=
CONNECTED
)
{
state_
=
CONNECTING
;
}
}
else
{
// Unreachable
DIE
();
return
0
;
}
return
0
;
// Unreachable
DIE
();
}
void
Http2Session
::
unwrap_free_bev
()
...
...
@@ -517,10 +536,13 @@ int htp_hdrs_completecb(http_parser *htp)
SSLOG
(
INFO
,
http2session
)
<<
"Tunneling success"
;
}
http2session
->
set_state
(
Http2Session
::
PROXY_CONNECTED
);
}
else
{
SSLOG
(
WARNING
,
http2session
)
<<
"Tunneling failed"
;
http2session
->
set_state
(
Http2Session
::
PROXY_FAILED
);
return
0
;
}
SSLOG
(
WARNING
,
http2session
)
<<
"Tunneling failed"
;
http2session
->
set_state
(
Http2Session
::
PROXY_FAILED
);
return
0
;
}
}
// namespace
...
...
src/shrpx_http2_upstream.cc
View file @
7e217511
...
...
@@ -61,37 +61,50 @@ int on_stream_close_callback
<<
" is being closed"
;
}
auto
downstream
=
upstream
->
find_downstream
(
stream_id
);
if
(
downstream
)
{
if
(
downstream
->
get_request_state
()
==
Downstream
::
CONNECT_FAIL
)
{
upstream
->
remove_downstream
(
downstream
);
delete
downstream
;
}
else
{
downstream
->
set_request_state
(
Downstream
::
STREAM_CLOSED
);
if
(
downstream
->
get_response_state
()
==
Downstream
::
MSG_COMPLETE
)
{
// At this point, downstream response was read
if
(
!
downstream
->
get_upgraded
()
&&
!
downstream
->
get_response_connection_close
())
{
// Keep-alive
auto
dconn
=
downstream
->
get_downstream_connection
();
if
(
dconn
)
{
dconn
->
detach_downstream
(
downstream
);
}
}
upstream
->
remove_downstream
(
downstream
);
delete
downstream
;
}
else
{
// At this point, downstream read may be paused.
// If shrpx_downstream::push_request_headers() failed, the
// error is handled here.
upstream
->
remove_downstream
(
downstream
);
delete
downstream
;
// How to test this case? Request sufficient large download
// and make client send RST_STREAM after it gets first DATA
// frame chunk.
if
(
!
downstream
)
{
return
0
;
}
if
(
downstream
->
get_request_state
()
==
Downstream
::
CONNECT_FAIL
)
{
upstream
->
remove_downstream
(
downstream
);
delete
downstream
;
return
0
;
}
downstream
->
set_request_state
(
Downstream
::
STREAM_CLOSED
);
if
(
downstream
->
get_response_state
()
==
Downstream
::
MSG_COMPLETE
)
{
// At this point, downstream response was read
if
(
!
downstream
->
get_upgraded
()
&&
!
downstream
->
get_response_connection_close
())
{
// Keep-alive
auto
dconn
=
downstream
->
get_downstream_connection
();
if
(
dconn
)
{
dconn
->
detach_downstream
(
downstream
);
}
}
upstream
->
remove_downstream
(
downstream
);
delete
downstream
;
return
0
;
}
// At this point, downstream read may be paused.
// If shrpx_downstream::push_request_headers() failed, the
// error is handled here.
upstream
->
remove_downstream
(
downstream
);
delete
downstream
;
// How to test this case? Request sufficient large download
// and make client send RST_STREAM after it gets first DATA
// frame chunk.
return
0
;
}
}
// namespace
...
...
@@ -423,12 +436,16 @@ int on_data_chunk_recv_callback(nghttp2_session *session,
{
auto
upstream
=
static_cast
<
Http2Upstream
*>
(
user_data
);
auto
downstream
=
upstream
->
find_downstream
(
stream_id
);
if
(
downstream
)
{
if
(
downstream
->
push_upload_data_chunk
(
data
,
len
)
!=
0
)
{
upstream
->
rst_stream
(
downstream
,
NGHTTP2_INTERNAL_ERROR
);
return
0
;
}
if
(
!
downstream
)
{
return
0
;
}
if
(
downstream
->
push_upload_data_chunk
(
data
,
len
)
!=
0
)
{
upstream
->
rst_stream
(
downstream
,
NGHTTP2_INTERNAL_ERROR
);
return
0
;
}
return
0
;
}
}
// namespace
...
...
@@ -691,6 +708,7 @@ void downstream_readcb(bufferevent *bev, void *ptr)
auto
dconn
=
static_cast
<
DownstreamConnection
*>
(
ptr
);
auto
downstream
=
dconn
->
get_downstream
();
auto
upstream
=
static_cast
<
Http2Upstream
*>
(
downstream
->
get_upstream
());
if
(
downstream
->
get_request_state
()
==
Downstream
::
STREAM_CLOSED
)
{
// If upstream HTTP2 stream was closed, we just close downstream,
// because there is no consumer now. Downstream connection is also
...
...
@@ -707,11 +725,11 @@ void downstream_readcb(bufferevent *bev, void *ptr)
// on_stream_close_callback.
upstream
->
rst_stream
(
downstream
,
infer_upstream_rst_stream_error_code
(
downstream
->
get_response_rst_stream_error_code
()));
downstream
->
set_downstream_connection
(
0
);
downstream
->
set_downstream_connection
(
nullptr
);
delete
dconn
;
dconn
=
0
;
dconn
=
nullptr
;
}
else
{
int
rv
=
downstream
->
on_read
();
auto
rv
=
downstream
->
on_read
();
if
(
rv
!=
0
)
{
if
(
LOG_ENABLED
(
INFO
))
{
DCLOG
(
INFO
,
dconn
)
<<
"HTTP parser failure"
;
...
...
@@ -728,9 +746,9 @@ void downstream_readcb(bufferevent *bev, void *ptr)
downstream
->
set_response_state
(
Downstream
::
MSG_COMPLETE
);
// Clearly, we have to close downstream connection on http parser
// failure.
downstream
->
set_downstream_connection
(
0
);
downstream
->
set_downstream_connection
(
nullptr
);
delete
dconn
;
dconn
=
0
;
dconn
=
nullptr
;
}
}
if
(
upstream
->
send
()
!=
0
)
{
...
...
@@ -765,14 +783,18 @@ void downstream_eventcb(bufferevent *bev, short events, void *ptr)
DCLOG
(
INFO
,
dconn
)
<<
"Connection established. stream_id="
<<
downstream
->
get_stream_id
();
}
int
fd
=
bufferevent_getfd
(
bev
);
auto
fd
=
bufferevent_getfd
(
bev
);
int
val
=
1
;
if
(
setsockopt
(
fd
,
IPPROTO_TCP
,
TCP_NODELAY
,
reinterpret_cast
<
char
*>
(
&
val
),
sizeof
(
val
))
==
-
1
)
{
reinterpret_cast
<
char
*>
(
&
val
),
sizeof
(
val
))
==
-
1
)
{
DCLOG
(
WARNING
,
dconn
)
<<
"Setting option TCP_NODELAY failed: errno="
<<
errno
;
}
}
else
if
(
events
&
BEV_EVENT_EOF
)
{
return
;
}
if
(
events
&
BEV_EVENT_EOF
)
{
if
(
LOG_ENABLED
(
INFO
))
{
DCLOG
(
INFO
,
dconn
)
<<
"EOF. stream_id="
<<
downstream
->
get_stream_id
();
}
...
...
@@ -781,41 +803,46 @@ void downstream_eventcb(bufferevent *bev, short events, void *ptr)
// the first place. We can delete downstream.
upstream
->
remove_downstream
(
downstream
);
delete
downstream
;
}
else
{
// Delete downstream connection. If we don't delete it here, it
// will be pooled in on_stream_close_callback.
downstream
->
set_downstream_connection
(
0
);
delete
dconn
;
dconn
=
0
;
// downstream wil be deleted in on_stream_close_callback.
if
(
downstream
->
get_response_state
()
==
Downstream
::
HEADER_COMPLETE
)
{
// Server may indicate the end of the request by EOF
if
(
LOG_ENABLED
(
INFO
))
{
ULOG
(
INFO
,
upstream
)
<<
"Downstream body was ended by EOF"
;
}
downstream
->
set_response_state
(
Downstream
::
MSG_COMPLETE
);
// For tunneled connection, MSG_COMPLETE signals
// downstream_data_read_callback to send RST_STREAM after
// pending response body is sent. This is needed to ensure
// that RST_STREAM is sent after all pending data are sent.
upstream
->
on_downstream_body_complete
(
downstream
);
}
else
if
(
downstream
->
get_response_state
()
!=
Downstream
::
MSG_COMPLETE
)
{
// If stream was not closed, then we set MSG_COMPLETE and let
// on_stream_close_callback delete downstream.
if
(
upstream
->
error_reply
(
downstream
,
502
)
!=
0
)
{
delete
upstream
->
get_client_handler
();
return
;
}
downstream
->
set_response_state
(
Downstream
::
MSG_COMPLETE
)
;
return
;
}
// Delete downstream connection. If we don't delete it here, it
// will be pooled in on_stream_close_callback.
downstream
->
set_downstream_connection
(
nullptr
);
delete
dconn
;
dconn
=
nullptr
;
// downstream wil be deleted in on_stream_close_callback.
if
(
downstream
->
get_response_state
()
==
Downstream
::
HEADER_COMPLETE
)
{
// Server may indicate the end of the request by EOF
if
(
LOG_ENABLED
(
INFO
))
{
ULOG
(
INFO
,
upstream
)
<<
"Downstream body was ended by EOF"
;
}
if
(
upstream
->
send
()
!=
0
)
{
downstream
->
set_response_state
(
Downstream
::
MSG_COMPLETE
);
// For tunneled connection, MSG_COMPLETE signals
// downstream_data_read_callback to send RST_STREAM after
// pending response body is sent. This is needed to ensure
// that RST_STREAM is sent after all pending data are sent.
upstream
->
on_downstream_body_complete
(
downstream
);
}
else
if
(
downstream
->
get_response_state
()
!=
Downstream
::
MSG_COMPLETE
)
{
// If stream was not closed, then we set MSG_COMPLETE and let
// on_stream_close_callback delete downstream.
if
(
upstream
->
error_reply
(
downstream
,
502
)
!=
0
)
{
delete
upstream
->
get_client_handler
();
return
;
}
// At this point, downstream may be deleted.
downstream
->
set_response_state
(
Downstream
::
MSG_COMPLETE
);
}
}
else
if
(
events
&
(
BEV_EVENT_ERROR
|
BEV_EVENT_TIMEOUT
))
{
if
(
upstream
->
send
()
!=
0
)
{
delete
upstream
->
get_client_handler
();
return
;
}
// At this point, downstream may be deleted.
return
;
}
if
(
events
&
(
BEV_EVENT_ERROR
|
BEV_EVENT_TIMEOUT
))
{
if
(
LOG_ENABLED
(
INFO
))
{
if
(
events
&
BEV_EVENT_ERROR
)
{
DCLOG
(
INFO
,
dconn
)
<<
"Downstream network error: "
...
...
@@ -828,45 +855,50 @@ void downstream_eventcb(bufferevent *bev, short events, void *ptr)
DCLOG
(
INFO
,
dconn
)
<<
"Note: this is tunnel connection"
;
}
}
if
(
downstream
->
get_request_state
()
==
Downstream
::
STREAM_CLOSED
)
{
upstream
->
remove_downstream
(
downstream
);
delete
downstream
;
return
;
}
// Delete downstream connection. If we don't delete it here, it
// will be pooled in on_stream_close_callback.
downstream
->
set_downstream_connection
(
nullptr
);
delete
dconn
;
dconn
=
nullptr
;
if
(
downstream
->
get_response_state
()
==
Downstream
::
MSG_COMPLETE
)
{
// For SSL tunneling, we issue RST_STREAM. For other types of
// stream, we don't have to do anything since response was
// complete.
if
(
downstream
->
get_upgraded
())
{
upstream
->
rst_stream
(
downstream
,
NGHTTP2_INTERNAL_ERROR
);
}
}
else
{
// Delete downstream connection. If we don't delete it here, it
// will be pooled in on_stream_close_callback.
downstream
->
set_downstream_connection
(
0
);
delete
dconn
;
dconn
=
0
;
if
(
downstream
->
get_response_state
()
==
Downstream
::
MSG_COMPLETE
)
{
// For SSL tunneling, we issue RST_STREAM. For other types of
// stream, we don't have to do anything since response was
// complete.
if
(
downstream
->
get_upgraded
())
{
upstream
->
rst_stream
(
downstream
,
NGHTTP2_INTERNAL_ERROR
);
}
if
(
downstream
->
get_response_state
()
==
Downstream
::
HEADER_COMPLETE
)
{
upstream
->
rst_stream
(
downstream
,
NGHTTP2_INTERNAL_ERROR
);
}
else
{
if
(
downstream
->
get_response_state
()
==
Downstream
::
HEADER_COMPLETE
)
{
upstream
->
rst_stream
(
downstream
,
NGHTTP2_INTERNAL_ERROR
);
unsigned
int
status
;
if
(
events
&
BEV_EVENT_TIMEOUT
)
{
status
=
504
;
}
else
{
unsigned
int
status
;
if
(
events
&
BEV_EVENT_TIMEOUT
)
{
status
=
504
;
}
else
{
status
=
502
;
}
if
(
upstream
->
error_reply
(
downstream
,
status
)
!=
0
)
{
delete
upstream
->
get_client_handler
();
return
;
}
status
=
502
;
}
if
(
upstream
->
error_reply
(
downstream
,
status
)
!=
0
)
{
delete
upstream
->
get_client_handler
();
return
;
}
downstream
->
set_response_state
(
Downstream
::
MSG_COMPLETE
);
}
if
(
upstream
->
send
()
!=
0
)
{
delete
upstream
->
get_client_handler
();
return
;
}
// At this point, downstream may be deleted.
downstream
->
set_response_state
(
Downstream
::
MSG_COMPLETE
);
}
if
(
upstream
->
send
()
!=
0
)
{
delete
upstream
->
get_client_handler
();
return
;
}
// At this point, downstream may be deleted.
return
;
}
}
}
// namespace
...
...
src/shrpx_https_upstream.cc
View file @
7e217511
...
...
@@ -193,19 +193,23 @@ int htp_hdrs_completecb(http_parser *htp)
}
rv
=
dconn
->
attach_downstream
(
downstream
);
if
(
rv
!=
0
)
{
downstream
->
set_request_state
(
Downstream
::
CONNECT_FAIL
);
downstream
->
set_downstream_connection
(
0
);
downstream
->
set_downstream_connection
(
nullptr
);
delete
dconn
;
return
-
1
;
}
else
{
rv
=
downstream
->
push_request_headers
();
if
(
rv
!=
0
)
{
return
-
1
;
}
downstream
->
set_request_state
(
Downstream
::
HEADER_COMPLETE
);
return
0
;
}
rv
=
downstream
->
push_request_headers
();
if
(
rv
!=
0
)
{
return
-
1
;
}
downstream
->
set_request_state
(
Downstream
::
HEADER_COMPLETE
);
return
0
;
}
}
// namespace
...
...
@@ -431,9 +435,9 @@ int HttpsUpstream::resume_read(IOCtrlReason reason, Downstream *downstream)
// are not notified by readcb until new data arrive.
http_parser_pause
(
&
htp_
,
0
);
return
on_read
();
}
else
{
return
0
;
}
return
0
;
}
namespace
{
...
...
@@ -443,80 +447,109 @@ void https_downstream_readcb(bufferevent *bev, void *ptr)
auto
downstream
=
dconn
->
get_downstream
();
auto
upstream
=
static_cast
<
HttpsUpstream
*>
(
downstream
->
get_upstream
());
int
rv
;
rv
=
downstream
->
on_read
();
if
(
downstream
->
get_response_state
()
==
Downstream
::
MSG_RESET
)
{
delete
upstream
->
get_client_handler
();
}
else
if
(
rv
==
0
)
{
auto
handler
=
upstream
->
get_client_handler
();
if
(
downstream
->
get_response_state
()
==
Downstream
::
MSG_COMPLETE
)
{
if
(
downstream
->
get_response_connection_close
())
{
// Connection close
downstream
->
set_downstream_connection
(
0
);
delete
dconn
;
dconn
=
0
;
}
else
{
// Keep-alive
dconn
->
detach_downstream
(
downstream
);
}
if
(
downstream
->
get_request_state
()
==
Downstream
::
MSG_COMPLETE
)
{
if
(
handler
->
get_should_close_after_write
()
&&
handler
->
get_outbuf_length
()
==
0
)
{
// If all upstream response body has already written out to
// the peer, we cannot use writecb for ClientHandler. In
// this case, we just delete handler here.
delete
handler
;
return
;
}
else
{
upstream
->
delete_downstream
();
// Process next HTTP request
if
(
upstream
->
resume_read
(
SHRPX_MSG_BLOCK
,
0
)
==
-
1
)
{
return
;
}
}
}
else
if
(
downstream
->
get_upgraded
())
{
// This path is effectively only taken for HTTP2 downstream
// because only HTTP2 downstream sets response_state to
// MSG_COMPLETE and this function. For HTTP downstream, EOF
// from tunnel connection is handled on
// https_downstream_eventcb.
//
// Tunneled connection always indicates connection close.
if
(
handler
->
get_outbuf_length
()
==
0
)
{
// For tunneled connection, if there is no pending data,
// delete handler because on_write will not be called.
delete
handler
;
}
else
{
if
(
LOG_ENABLED
(
INFO
))
{
DLOG
(
INFO
,
downstream
)
<<
"Tunneled connection has pending data"
;
}
}
}
}
else
{
if
(
handler
->
get_outbuf_length
()
>=
OUTBUF_MAX_THRES
)
{
downstream
->
pause_read
(
SHRPX_NO_BUFFER
);
}
}
}
else
{
return
;
}
if
(
rv
!=
0
)
{
if
(
downstream
->
get_response_state
()
==
Downstream
::
HEADER_COMPLETE
)
{
// We already sent HTTP response headers to upstream
// client. Just close the upstream connection.
delete
upstream
->
get_client_handler
();
}
else
{
// We did not sent any HTTP response, so sent error
// response. Cannot reuse downstream connection in this case.
if
(
upstream
->
error_reply
(
502
)
!=
0
)
{
delete
upstream
->
get_client_handler
();
return
;
}
// We did not sent any HTTP response, so sent error
// response. Cannot reuse downstream connection in this case.
if
(
upstream
->
error_reply
(
502
)
!=
0
)
{
delete
upstream
->
get_client_handler
();
return
;
}
if
(
downstream
->
get_request_state
()
==
Downstream
::
MSG_COMPLETE
)
{
upstream
->
delete_downstream
();
// Process next HTTP request
if
(
upstream
->
resume_read
(
SHRPX_MSG_BLOCK
,
0
)
==
-
1
)
{
return
;
}
if
(
downstream
->
get_request_state
()
==
Downstream
::
MSG_COMPLETE
)
{
upstream
->
delete_downstream
();
// Process next HTTP request
if
(
upstream
->
resume_read
(
SHRPX_MSG_BLOCK
,
0
)
==
-
1
)
{
return
;
}
}
}
return
;
}
auto
handler
=
upstream
->
get_client_handler
();
if
(
downstream
->
get_response_state
()
!=
Downstream
::
MSG_COMPLETE
)
{
if
(
handler
->
get_outbuf_length
()
>=
OUTBUF_MAX_THRES
)
{
downstream
->
pause_read
(
SHRPX_NO_BUFFER
);
}
return
;
}
if
(
downstream
->
get_response_connection_close
())
{
// Connection close
downstream
->
set_downstream_connection
(
nullptr
);
delete
dconn
;
dconn
=
nullptr
;
}
else
{
// Keep-alive
dconn
->
detach_downstream
(
downstream
);
}
if
(
downstream
->
get_request_state
()
==
Downstream
::
MSG_COMPLETE
)
{
if
(
handler
->
get_should_close_after_write
()
&&
handler
->
get_outbuf_length
()
==
0
)
{
// If all upstream response body has already written out to
// the peer, we cannot use writecb for ClientHandler. In
// this case, we just delete handler here.
delete
handler
;
return
;
}
upstream
->
delete_downstream
();
// Process next HTTP request
if
(
upstream
->
resume_read
(
SHRPX_MSG_BLOCK
,
0
)
==
-
1
)
{
return
;
}
return
;
}
if
(
downstream
->
get_upgraded
())
{
// This path is effectively only taken for HTTP2 downstream
// because only HTTP2 downstream sets response_state to
// MSG_COMPLETE and this function. For HTTP downstream, EOF
// from tunnel connection is handled on
// https_downstream_eventcb.
//
// Tunneled connection always indicates connection close.
if
(
handler
->
get_outbuf_length
()
==
0
)
{
// For tunneled connection, if there is no pending data,
// delete handler because on_write will not be called.
delete
handler
;
return
;
}
if
(
LOG_ENABLED
(
INFO
))
{
DLOG
(
INFO
,
downstream
)
<<
"Tunneled connection has pending data"
;
}
return
;
}
}
}
// namespace
...
...
@@ -545,7 +578,11 @@ void https_downstream_eventcb(bufferevent *bev, short events, void *ptr)
if
(
LOG_ENABLED
(
INFO
))
{
DCLOG
(
INFO
,
dconn
)
<<
"Connection established"
;
}
}
else
if
(
events
&
BEV_EVENT_EOF
)
{
return
;
}
if
(
events
&
BEV_EVENT_EOF
)
{
if
(
LOG_ENABLED
(
INFO
))
{
DCLOG
(
INFO
,
dconn
)
<<
"EOF"
;
}
...
...
@@ -567,9 +604,7 @@ void https_downstream_eventcb(bufferevent *bev, short events, void *ptr)
delete
handler
;
return
;
}
}
else
if
(
downstream
->
get_response_state
()
==
Downstream
::
MSG_COMPLETE
)
{
// Nothing to do
}
else
{
}
else
if
(
downstream
->
get_response_state
()
!=
Downstream
::
MSG_COMPLETE
)
{
// error
if
(
LOG_ENABLED
(
INFO
))
{
DCLOG
(
INFO
,
dconn
)
<<
"Treated as error"
;
...
...
@@ -585,7 +620,11 @@ void https_downstream_eventcb(bufferevent *bev, short events, void *ptr)
return
;
}
}
}
else
if
(
events
&
(
BEV_EVENT_ERROR
|
BEV_EVENT_TIMEOUT
))
{
return
;
}
if
(
events
&
(
BEV_EVENT_ERROR
|
BEV_EVENT_TIMEOUT
))
{
if
(
LOG_ENABLED
(
INFO
))
{
if
(
events
&
BEV_EVENT_ERROR
)
{
DCLOG
(
INFO
,
dconn
)
<<
"Network error"
;
...
...
src/shrpx_spdy_upstream.cc
View file @
7e217511
...
...
@@ -103,37 +103,41 @@ void on_stream_close_callback
<<
" is being closed"
;
}
auto
downstream
=
upstream
->
find_downstream
(
stream_id
);
if
(
downstream
)
{
if
(
downstream
->
get_request_state
()
==
Downstream
::
CONNECT_FAIL
)
{
upstream
->
remove_downstream
(
downstream
);
delete
downstream
;
}
else
{
downstream
->
set_request_state
(
Downstream
::
STREAM_CLOSED
);
if
(
downstream
->
get_response_state
()
==
Downstream
::
MSG_COMPLETE
)
{
// At this point, downstream response was read
if
(
!
downstream
->
get_upgraded
()
&&
!
downstream
->
get_response_connection_close
())
{
// Keep-alive
auto
dconn
=
downstream
->
get_downstream_connection
();
if
(
dconn
)
{
dconn
->
detach_downstream
(
downstream
);
}
}
upstream
->
remove_downstream
(
downstream
);
delete
downstream
;
}
else
{
// At this point, downstream read may be paused.
// If shrpx_downstream::push_request_headers() failed, the
// error is handled here.
upstream
->
remove_downstream
(
downstream
);
delete
downstream
;
// How to test this case? Request sufficient large download
// and make client send RST_STREAM after it gets first DATA
// frame chunk.
if
(
!
downstream
)
{
return
;
}
if
(
downstream
->
get_request_state
()
==
Downstream
::
CONNECT_FAIL
)
{
upstream
->
remove_downstream
(
downstream
);
delete
downstream
;
return
;
}
downstream
->
set_request_state
(
Downstream
::
STREAM_CLOSED
);
if
(
downstream
->
get_response_state
()
==
Downstream
::
MSG_COMPLETE
)
{
// At this point, downstream response was read
if
(
!
downstream
->
get_upgraded
()
&&
!
downstream
->
get_response_connection_close
())
{
// Keep-alive
auto
dconn
=
downstream
->
get_downstream_connection
();
if
(
dconn
)
{
dconn
->
detach_downstream
(
downstream
);
}
}
upstream
->
remove_downstream
(
downstream
);
delete
downstream
;
return
;
}
// At this point, downstream read may be paused.
// If shrpx_downstream::push_request_headers() failed, the
// error is handled here.
upstream
->
remove_downstream
(
downstream
);
delete
downstream
;
// How to test this case? Request sufficient large download
// and make client send RST_STREAM after it gets first DATA
// frame chunk.
}
}
// namespace
...
...
@@ -245,43 +249,49 @@ void on_data_chunk_recv_callback(spdylay_session *session,
{
auto
upstream
=
static_cast
<
SpdyUpstream
*>
(
user_data
);
auto
downstream
=
upstream
->
find_downstream
(
stream_id
);
if
(
downstream
)
{
if
(
downstream
->
push_upload_data_chunk
(
data
,
len
)
!=
0
)
{
upstream
->
rst_stream
(
downstream
,
SPDYLAY_INTERNAL_ERROR
);
return
;
if
(
!
downstream
)
{
return
;
}
if
(
downstream
->
push_upload_data_chunk
(
data
,
len
)
!=
0
)
{
upstream
->
rst_stream
(
downstream
,
SPDYLAY_INTERNAL_ERROR
);
return
;
}
if
(
!
upstream
->
get_flow_control
())
{
return
;
}
// If connection-level window control is not enabled (e.g,
// spdy/3), spdylay_session_get_recv_data_length() is always
// returns 0.
if
(
spdylay_session_get_recv_data_length
(
session
)
>
std
::
max
(
SPDYLAY_INITIAL_WINDOW_SIZE
,
1
<<
get_config
()
->
http2_upstream_connection_window_bits
))
{
if
(
LOG_ENABLED
(
INFO
))
{
ULOG
(
INFO
,
upstream
)
<<
"Flow control error on connection: "
<<
"recv_window_size="
<<
spdylay_session_get_recv_data_length
(
session
)
<<
", window_size="
<<
(
1
<<
get_config
()
->
http2_upstream_connection_window_bits
);
}
if
(
upstream
->
get_flow_control
())
{
// If connection-level window control is not enabled (e.g,
// spdy/3), spdylay_session_get_recv_data_length() is always
// returns 0.
if
(
spdylay_session_get_recv_data_length
(
session
)
>
std
::
max
(
SPDYLAY_INITIAL_WINDOW_SIZE
,
1
<<
get_config
()
->
http2_upstream_connection_window_bits
))
{
if
(
LOG_ENABLED
(
INFO
))
{
ULOG
(
INFO
,
upstream
)
<<
"Flow control error on connection: "
<<
"recv_window_size="
<<
spdylay_session_get_recv_data_length
(
session
)
<<
", window_size="
<<
(
1
<<
get_config
()
->
http2_upstream_connection_window_bits
);
}
spdylay_session_fail_session
(
session
,
SPDYLAY_GOAWAY_PROTOCOL_ERROR
);
return
;
}
if
(
spdylay_session_get_stream_recv_data_length
(
session
,
stream_id
)
>
std
::
max
(
SPDYLAY_INITIAL_WINDOW_SIZE
,
1
<<
get_config
()
->
http2_upstream_window_bits
))
{
if
(
LOG_ENABLED
(
INFO
))
{
ULOG
(
INFO
,
upstream
)
<<
"Flow control error: recv_window_size="
<<
spdylay_session_get_stream_recv_data_length
(
session
,
stream_id
)
<<
", initial_window_size="
<<
(
1
<<
get_config
()
->
http2_upstream_window_bits
);
}
upstream
->
rst_stream
(
downstream
,
SPDYLAY_FLOW_CONTROL_ERROR
);
return
;
}
spdylay_session_fail_session
(
session
,
SPDYLAY_GOAWAY_PROTOCOL_ERROR
);
return
;
}
if
(
spdylay_session_get_stream_recv_data_length
(
session
,
stream_id
)
>
std
::
max
(
SPDYLAY_INITIAL_WINDOW_SIZE
,
1
<<
get_config
()
->
http2_upstream_window_bits
))
{
if
(
LOG_ENABLED
(
INFO
))
{
ULOG
(
INFO
,
upstream
)
<<
"Flow control error: recv_window_size="
<<
spdylay_session_get_stream_recv_data_length
(
session
,
stream_id
)
<<
", initial_window_size="
<<
(
1
<<
get_config
()
->
http2_upstream_window_bits
);
}
upstream
->
rst_stream
(
downstream
,
SPDYLAY_FLOW_CONTROL_ERROR
);
return
;
}
}
}
// namespace
...
...
@@ -520,11 +530,11 @@ void spdy_downstream_readcb(bufferevent *bev, void *ptr)
// on_stream_close_callback.
upstream
->
rst_stream
(
downstream
,
infer_upstream_rst_stream_status_code
(
downstream
->
get_response_rst_stream_error_code
()));
downstream
->
set_downstream_connection
(
0
);
downstream
->
set_downstream_connection
(
nullptr
);
delete
dconn
;
dconn
=
0
;
dconn
=
nullptr
;
}
else
{
int
rv
=
downstream
->
on_read
();
auto
rv
=
downstream
->
on_read
();
if
(
rv
!=
0
)
{
if
(
LOG_ENABLED
(
INFO
))
{
DCLOG
(
INFO
,
dconn
)
<<
"HTTP parser failure"
;
...
...
@@ -541,9 +551,9 @@ void spdy_downstream_readcb(bufferevent *bev, void *ptr)
downstream
->
set_response_state
(
Downstream
::
MSG_COMPLETE
);
// Clearly, we have to close downstream connection on http parser
// failure.
downstream
->
set_downstream_connection
(
0
);
downstream
->
set_downstream_connection
(
nullptr
);
delete
dconn
;
dconn
=
0
;
dconn
=
nullptr
;
}
}
if
(
upstream
->
send
()
!=
0
)
{
...
...
@@ -573,6 +583,7 @@ void spdy_downstream_eventcb(bufferevent *bev, short events, void *ptr)
auto
dconn
=
static_cast
<
DownstreamConnection
*>
(
ptr
);
auto
downstream
=
dconn
->
get_downstream
();
auto
upstream
=
static_cast
<
SpdyUpstream
*>
(
downstream
->
get_upstream
());
if
(
events
&
BEV_EVENT_CONNECTED
)
{
if
(
LOG_ENABLED
(
INFO
))
{
DCLOG
(
INFO
,
dconn
)
<<
"Connection established. stream_id="
...
...
@@ -585,7 +596,10 @@ void spdy_downstream_eventcb(bufferevent *bev, short events, void *ptr)
DCLOG
(
WARNING
,
dconn
)
<<
"Setting option TCP_NODELAY failed: errno="
<<
errno
;
}
}
else
if
(
events
&
BEV_EVENT_EOF
)
{
return
;
}
if
(
events
&
BEV_EVENT_EOF
)
{
if
(
LOG_ENABLED
(
INFO
))
{
DCLOG
(
INFO
,
dconn
)
<<
"EOF. stream_id="
<<
downstream
->
get_stream_id
();
}
...
...
@@ -594,41 +608,46 @@ void spdy_downstream_eventcb(bufferevent *bev, short events, void *ptr)
// the first place. We can delete downstream.
upstream
->
remove_downstream
(
downstream
);
delete
downstream
;
}
else
{
// Delete downstream connection. If we don't delete it here, it
// will be pooled in on_stream_close_callback.
downstream
->
set_downstream_connection
(
0
);
delete
dconn
;
dconn
=
0
;
// downstream wil be deleted in on_stream_close_callback.
if
(
downstream
->
get_response_state
()
==
Downstream
::
HEADER_COMPLETE
)
{
// Server may indicate the end of the request by EOF
if
(
LOG_ENABLED
(
INFO
))
{
ULOG
(
INFO
,
upstream
)
<<
"Downstream body was ended by EOF"
;
}
downstream
->
set_response_state
(
Downstream
::
MSG_COMPLETE
);
return
;
}
// For tunneled connection, MSG_COMPLETE signals
// spdy_data_read_callback to send RST_STREAM after pending
// response body is sent. This is needed to ensure that
// RST_STREAM is sent after all pending data are sent.
upstream
->
on_downstream_body_complete
(
downstream
);
}
else
if
(
downstream
->
get_response_state
()
!=
Downstream
::
MSG_COMPLETE
)
{
// If stream was not closed, then we set MSG_COMPLETE and let
// on_stream_close_callback delete downstream.
if
(
upstream
->
error_reply
(
downstream
,
502
)
!=
0
)
{
delete
upstream
->
get_client_handler
();
return
;
}
downstream
->
set_response_state
(
Downstream
::
MSG_COMPLETE
);
// Delete downstream connection. If we don't delete it here, it
// will be pooled in on_stream_close_callback.
downstream
->
set_downstream_connection
(
nullptr
);
delete
dconn
;
dconn
=
nullptr
;
// downstream wil be deleted in on_stream_close_callback.
if
(
downstream
->
get_response_state
()
==
Downstream
::
HEADER_COMPLETE
)
{
// Server may indicate the end of the request by EOF
if
(
LOG_ENABLED
(
INFO
))
{
ULOG
(
INFO
,
upstream
)
<<
"Downstream body was ended by EOF"
;
}
if
(
upstream
->
send
()
!=
0
)
{
downstream
->
set_response_state
(
Downstream
::
MSG_COMPLETE
);
// For tunneled connection, MSG_COMPLETE signals
// spdy_data_read_callback to send RST_STREAM after pending
// response body is sent. This is needed to ensure that
// RST_STREAM is sent after all pending data are sent.
upstream
->
on_downstream_body_complete
(
downstream
);
}
else
if
(
downstream
->
get_response_state
()
!=
Downstream
::
MSG_COMPLETE
)
{
// If stream was not closed, then we set MSG_COMPLETE and let
// on_stream_close_callback delete downstream.
if
(
upstream
->
error_reply
(
downstream
,
502
)
!=
0
)
{
delete
upstream
->
get_client_handler
();
return
;
}
// At this point, downstream may be deleted.
downstream
->
set_response_state
(
Downstream
::
MSG_COMPLETE
);
}
}
else
if
(
events
&
(
BEV_EVENT_ERROR
|
BEV_EVENT_TIMEOUT
))
{
if
(
upstream
->
send
()
!=
0
)
{
delete
upstream
->
get_client_handler
();
return
;
}
// At this point, downstream may be deleted.
return
;
}
if
(
events
&
(
BEV_EVENT_ERROR
|
BEV_EVENT_TIMEOUT
))
{
if
(
LOG_ENABLED
(
INFO
))
{
if
(
events
&
BEV_EVENT_ERROR
)
{
DCLOG
(
INFO
,
dconn
)
<<
"Downstream network error: "
...
...
@@ -644,42 +663,45 @@ void spdy_downstream_eventcb(bufferevent *bev, short events, void *ptr)
if
(
downstream
->
get_request_state
()
==
Downstream
::
STREAM_CLOSED
)
{
upstream
->
remove_downstream
(
downstream
);
delete
downstream
;
return
;
}
// Delete downstream connection. If we don't delete it here, it
// will be pooled in on_stream_close_callback.
downstream
->
set_downstream_connection
(
nullptr
);
delete
dconn
;
dconn
=
nullptr
;
if
(
downstream
->
get_response_state
()
==
Downstream
::
MSG_COMPLETE
)
{
// For SSL tunneling, we issue RST_STREAM. For other types of
// stream, we don't have to do anything since response was
// complete.
if
(
downstream
->
get_upgraded
())
{
upstream
->
rst_stream
(
downstream
,
SPDYLAY_INTERNAL_ERROR
);
}
}
else
{
// Delete downstream connection. If we don't delete it here, it
// will be pooled in on_stream_close_callback.
downstream
->
set_downstream_connection
(
0
);
delete
dconn
;
dconn
=
0
;
if
(
downstream
->
get_response_state
()
==
Downstream
::
MSG_COMPLETE
)
{
// For SSL tunneling, we issue RST_STREAM. For other types of
// stream, we don't have to do anything since response was
// complete.
if
(
downstream
->
get_upgraded
())
{
upstream
->
rst_stream
(
downstream
,
SPDYLAY_INTERNAL_ERROR
);
}
if
(
downstream
->
get_response_state
()
==
Downstream
::
HEADER_COMPLETE
)
{
upstream
->
rst_stream
(
downstream
,
SPDYLAY_INTERNAL_ERROR
);
}
else
{
if
(
downstream
->
get_response_state
()
==
Downstream
::
HEADER_COMPLETE
)
{
upstream
->
rst_stream
(
downstream
,
SPDYLAY_INTERNAL_ERROR
);
unsigned
int
status
;
if
(
events
&
BEV_EVENT_TIMEOUT
)
{
status
=
504
;
}
else
{
unsigned
int
status
;
if
(
events
&
BEV_EVENT_TIMEOUT
)
{
status
=
504
;
}
else
{
status
=
502
;
}
if
(
upstream
->
error_reply
(
downstream
,
status
)
!=
0
)
{
delete
upstream
->
get_client_handler
();
return
;
}
status
=
502
;
}
if
(
upstream
->
error_reply
(
downstream
,
status
)
!=
0
)
{
delete
upstream
->
get_client_handler
();
return
;
}
downstream
->
set_response_state
(
Downstream
::
MSG_COMPLETE
);
}
if
(
upstream
->
send
()
!=
0
)
{
delete
upstream
->
get_client_handler
();
return
;
}
// At this point, downstream may be deleted.
downstream
->
set_response_state
(
Downstream
::
MSG_COMPLETE
);
}
if
(
upstream
->
send
()
!=
0
)
{
delete
upstream
->
get_client_handler
();
return
;
}
// At this point, downstream may be deleted.
return
;
}
}
}
// namespace
...
...
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