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
a9b74261
Commit
a9b74261
authored
Sep 19, 2014
by
Tatsuhiro Tsujikawa
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
nghttpd: Rewrite using bufferevent (again) for simplicity
parent
89c3c085
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
85 additions
and
278 deletions
+85
-278
src/HttpServer.cc
src/HttpServer.cc
+81
-264
src/HttpServer.h
src/HttpServer.h
+4
-14
No files found.
src/HttpServer.cc
View file @
a9b74261
...
...
@@ -43,7 +43,7 @@
#include <event.h>
#include <event2/listener.h>
#include <event2/bufferevent.h>
#include <event2/bufferevent
_ssl
.h>
#ifdef __cplusplus
extern
"C"
{
...
...
@@ -336,25 +336,14 @@ Http2Handler::Http2Handler(Sessions *sessions,
session_
(
nullptr
),
sessions_
(
sessions
),
ssl_
(
ssl
),
rev_
(
nullptr
),
wev_
(
nullptr
),
bev_
(
nullptr
),
settings_timerev_
(
nullptr
),
pending_data_
(
nullptr
),
pending_datalen_
(
0
),
fd_
(
fd
)
{
nghttp2_buf_wrap_init
(
&
sendbuf_
,
sendbufarray_
,
sizeof
(
sendbufarray_
));
}
{}
Http2Handler
::~
Http2Handler
()
{
on_session_closed
(
this
,
session_id_
);
if
(
rev_
)
{
event_free
(
rev_
);
}
if
(
wev_
)
{
event_free
(
wev_
);
}
if
(
settings_timerev_
)
{
event_free
(
settings_timerev_
);
}
...
...
@@ -363,6 +352,10 @@ Http2Handler::~Http2Handler()
SSL_set_shutdown
(
ssl_
,
SSL_RECEIVED_SHUTDOWN
);
SSL_shutdown
(
ssl_
);
}
if
(
bev_
)
{
bufferevent_disable
(
bev_
,
EV_READ
|
EV_WRITE
);
bufferevent_free
(
bev_
);
}
if
(
ssl_
)
{
SSL_free
(
ssl_
);
}
...
...
@@ -376,333 +369,157 @@ void Http2Handler::remove_self()
}
namespace
{
void
re
v_cb
(
evutil_socket_t
fd
,
short
what
,
void
*
arg
)
void
re
adcb
(
bufferevent
*
bev
,
void
*
arg
)
{
int
rv
;
auto
handler
=
static_cast
<
Http2Handler
*>
(
arg
);
if
(
what
&
EV_READ
)
{
rv
=
handler
->
on_read
();
if
(
rv
==
-
1
)
{
delete_handler
(
handler
);
}
}
}
}
// namespace
namespace
{
void
w
ev_cb
(
evutil_socket_t
fd
,
short
what
,
void
*
arg
)
void
w
ritecb
(
bufferevent
*
bev
,
void
*
arg
)
{
int
rv
;
auto
handler
=
static_cast
<
Http2Handler
*>
(
arg
);
if
(
what
&
EV_WRITE
)
{
rv
=
handler
->
on_write
();
if
(
rv
==
-
1
)
{
delete_handler
(
handler
);
}
}
}
}
// namespace
int
Http2Handler
::
handle_ssl_temporal_error
(
int
err
)
namespace
{
void
eventcb
(
bufferevent
*
bev
,
short
events
,
void
*
arg
)
{
auto
sslerr
=
SSL_get_error
(
ssl_
,
err
);
switch
(
sslerr
)
{
case
SSL_ERROR_WANT_READ
:
event_add
(
rev_
,
nullptr
);
return
1
;
case
SSL_ERROR_WANT_WRITE
:
event_add
(
wev_
,
nullptr
);
return
1
;
}
auto
handler
=
static_cast
<
Http2Handler
*>
(
arg
);
return
-
1
;
}
if
(
events
&
(
BEV_EVENT_EOF
|
BEV_EVENT_ERROR
|
BEV_EVENT_TIMEOUT
))
{
delete_handler
(
handler
);
int
Http2Handler
::
tls_write
(
const
uint8_t
*
data
,
size_t
datalen
)
{
int
rv
;
size_t
max_avail
;
return
;
}
// OpenSSL sends at most 16K bytes
max_avail
=
ssl_
?
std
::
min
((
ssize_t
)
16384
,
nghttp2_buf_avail
(
&
sendbuf_
))
:
nghttp2_buf_avail
(
&
sendbuf_
);
if
(
events
&
BEV_EVENT_CONNECTED
)
{
if
(
handler
->
get_sessions
()
->
get_config
()
->
verbose
)
{
std
::
cerr
<<
"SSL/TLS handshake completed"
<<
std
::
endl
;
}
if
(
max_avail
<
datalen
)
{
if
(
nghttp2_buf_len
(
&
sendbuf_
)
>
0
)
{
rv
=
tls_write_pending
();
if
(
handler
->
verify_npn_result
()
!=
0
)
{
delete_handler
(
handler
);
if
(
rv
==
-
1
)
{
return
-
1
;
return
;
}
if
(
rv
==
1
)
{
pending_data_
=
data
;
pending_datalen_
=
datalen
;
if
(
handler
->
on_connect
()
!=
0
)
{
delete_handler
(
handler
);
return
1
;
}
return
;
}
assert
(
nghttp2_buf_avail
(
&
sendbuf_
)
>=
(
ssize_t
)
datalen
);
}
//std::cerr << "DBG: copy " << datalen << " bytes" << std::endl;
sendbuf_
.
last
=
nghttp2_cpymem
(
sendbuf_
.
last
,
data
,
datalen
);
return
0
;
}
}
// namespace
int
Http2Handler
::
tls_write_pending
()
int
Http2Handler
::
setup_bev
()
{
int
rv
;
auto
evbase
=
sessions_
->
get_evbase
()
;
if
(
nghttp2_buf_len
(
&
sendbuf_
)
==
0
)
{
return
0
;
}
for
(;;)
{
if
(
ssl_
)
{
ERR_clear_error
();
rv
=
SSL_write
(
ssl_
,
sendbuf_
.
pos
,
nghttp2_buf_len
(
&
sendbuf_
));
if
(
rv
==
0
)
{
return
-
1
;
}
if
(
rv
<
0
)
{
return
handle_ssl_temporal_error
(
rv
);
}
bev_
=
bufferevent_openssl_socket_new
(
evbase
,
fd_
,
ssl_
,
BUFFEREVENT_SSL_ACCEPTING
,
BEV_OPT_DEFER_CALLBACKS
);
}
else
{
while
((
rv
=
write
(
fd_
,
sendbuf_
.
pos
,
nghttp2_buf_len
(
&
sendbuf_
)))
&&
rv
==
-
1
&&
errno
==
EINTR
);
if
(
rv
==
0
)
{
continue
;
bev_
=
bufferevent_socket_new
(
evbase
,
fd_
,
BEV_OPT_DEFER_CALLBACKS
);
}
if
(
rv
<
0
)
{
if
(
errno
==
EAGAIN
||
errno
==
EWOULDBLOCK
)
{
event_add
(
wev_
,
nullptr
);
return
1
;
}
return
-
1
;
}
}
sendbuf_
.
pos
+=
rv
;
if
(
nghttp2_buf_len
(
&
sendbuf_
)
==
0
)
{
nghttp2_buf_reset
(
&
sendbuf_
);
if
(
pending_data_
)
{
assert
(
nghttp2_buf_avail
(
&
sendbuf_
)
>=
(
ssize_t
)
pending_datalen_
);
sendbuf_
.
last
=
nghttp2_cpymem
(
sendbuf_
.
last
,
pending_data_
,
pending_datalen_
);
pending_data_
=
nullptr
;
pending_datalen_
=
0
;
continue
;
}
bufferevent_enable
(
bev_
,
EV_READ
)
;
bufferevent_setcb
(
bev_
,
readcb
,
writecb
,
eventcb
,
this
);
return
0
;
}
}
}
namespace
{
void
tls_handshake_cb
(
evutil_socket_t
fd
,
short
what
,
void
*
arg
)
int
Http2Handler
::
send
()
{
int
rv
;
auto
handler
=
static_cast
<
Http2Handler
*>
(
arg
);
if
(
what
&
(
EV_READ
|
EV_WRITE
))
{
rv
=
handler
->
tls_handshake
();
if
(
rv
==
-
1
)
{
delete_handler
(
handler
);
return
;
}
if
(
rv
==
1
)
{
return
;
}
rv
=
handler
->
on_connect
();
if
(
rv
!=
0
)
{
delete_handler
(
handler
);
return
;
}
uint8_t
buf
[
16384
];
auto
output
=
bufferevent_get_output
(
bev_
);
util
::
EvbufferBuffer
evbbuf
(
output
,
buf
,
sizeof
(
buf
));
for
(;;)
{
// Check buffer length and break if it is large enough.
if
(
evbuffer_get_length
(
output
)
+
evbbuf
.
get_buflen
()
>=
65536
)
{
break
;
}
}
}
// namespace
int
Http2Handler
::
tls_handshake
()
{
int
rv
;
ERR_clear_error
();
const
uint8_t
*
data
;
auto
datalen
=
nghttp2_session_mem_send
(
session_
,
&
data
);
rv
=
SSL_accept
(
ssl_
);
if
(
rv
==
0
)
{
if
(
datalen
<
0
)
{
std
::
cerr
<<
"nghttp2_session_mem_send() returned error: "
<<
nghttp2_strerror
(
datalen
)
<<
std
::
endl
;
return
-
1
;
}
if
(
rv
<
0
)
{
auto
sslerr
=
SSL_get_error
(
ssl_
,
rv
);
switch
(
sslerr
)
{
case
SSL_ERROR_NONE
:
case
SSL_ERROR_WANT_X509_LOOKUP
:
case
SSL_ERROR_ZERO_RETURN
:
if
(
datalen
==
0
)
{
break
;
case
SSL_ERROR_WANT_READ
:
event_add
(
rev_
,
nullptr
);
return
1
;
case
SSL_ERROR_WANT_WRITE
:
event_add
(
wev_
,
nullptr
);
return
1
;
}
rv
=
evbbuf
.
add
(
data
,
datalen
);
if
(
rv
!=
0
)
{
std
::
cerr
<<
"evbuffer_add() failed"
<<
std
::
endl
;
return
-
1
;
}
if
(
sessions_
->
get_config
()
->
verbose
)
{
std
::
cerr
<<
"SSL/TLS handshake completed"
<<
std
::
endl
;
}
if
(
verify_npn_result
()
!=
0
)
{
rv
=
evbbuf
.
flush
();
if
(
rv
!=
0
)
{
std
::
cerr
<<
"evbuffer_add() failed"
<<
std
::
endl
;
return
-
1
;
}
event_del
(
rev_
);
event_del
(
wev_
);
event_assign
(
rev_
,
sessions_
->
get_evbase
(),
fd_
,
EV_READ
,
rev_cb
,
this
);
event_assign
(
wev_
,
sessions_
->
get_evbase
(),
fd_
,
EV_WRITE
,
wev_cb
,
this
);
if
(
nghttp2_session_want_read
(
session_
)
==
0
&&
nghttp2_session_want_write
(
session_
)
==
0
&&
evbuffer_get_length
(
output
)
==
0
)
{
return
0
;
}
int
Http2Handler
::
setup_bev
()
{
if
(
ssl_
)
{
rev_
=
event_new
(
sessions_
->
get_evbase
(),
fd_
,
EV_READ
,
tls_handshake_cb
,
this
);
wev_
=
event_new
(
sessions_
->
get_evbase
(),
fd_
,
EV_WRITE
,
tls_handshake_cb
,
this
);
}
else
{
rev_
=
event_new
(
sessions_
->
get_evbase
(),
fd_
,
EV_READ
,
rev_cb
,
this
);
wev_
=
event_new
(
sessions_
->
get_evbase
(),
fd_
,
EV_WRITE
,
wev_cb
,
this
);
return
-
1
;
}
event_add
(
rev_
,
nullptr
);
// TODO set up timeout here
return
0
;
}
int
Http2Handler
::
wait_events
()
{
int
active
=
0
;
if
(
nghttp2_session_want_read
(
session_
))
{
event_add
(
rev_
,
nullptr
);
active
=
1
;
}
if
(
nghttp2_session_want_write
(
session_
))
{
event_add
(
wev_
,
nullptr
);
active
=
1
;
}
if
(
pending_datalen_
>
0
)
{
active
=
1
;
}
return
active
?
0
:
-
1
;
}
int
Http2Handler
::
on_read
()
{
int
rv
;
uint8_t
buf
[
16384
];
uint8_t
*
bufp
;
size_t
nread
;
if
(
ssl_
)
{
ERR_clear_error
();
rv
=
SSL_read
(
ssl_
,
buf
,
sizeof
(
buf
));
auto
input
=
bufferevent_get_input
(
bev_
);
if
(
rv
==
0
)
{
return
-
1
;
}
if
(
rv
<
0
)
{
return
handle_ssl_temporal_error
(
rv
);
}
}
else
{
while
((
rv
=
read
(
fd_
,
buf
,
sizeof
(
buf
)))
&&
rv
==
-
1
&&
errno
==
EINTR
);
for
(;;)
{
auto
len
=
evbuffer_get_contiguous_space
(
input
);
if
(
rv
==
0
)
{
return
-
1
;
}
if
(
rv
<
0
)
{
if
(
errno
==
EAGAIN
||
errno
==
EWOULDBLOCK
)
{
event_add
(
rev_
,
nullptr
);
return
1
;
}
return
-
1
;
}
if
(
len
==
0
)
{
break
;
}
nread
=
rv
;
bufp
=
buf
;
auto
data
=
evbuffer_pullup
(
input
,
len
);
rv
=
nghttp2_session_mem_recv
(
session_
,
bufp
,
nread
);
rv
=
nghttp2_session_mem_recv
(
session_
,
data
,
len
);
if
(
rv
<
0
)
{
std
::
cerr
<<
"nghttp2_session_mem_recv() returned error: "
<<
nghttp2_strerror
(
rv
)
<<
std
::
endl
;
return
-
1
;
}
return
wait_events
();
evbuffer_drain
(
input
,
len
);
}
return
send
();
}
int
Http2Handler
::
on_write
()
{
int
rv
;
//std::cerr << "DBG: on_write" << std::endl;
rv
=
tls_write_pending
();
if
(
rv
!=
0
)
{
return
rv
;
}
for
(;;)
{
const
uint8_t
*
data
;
auto
datalen
=
nghttp2_session_mem_send
(
session_
,
&
data
);
if
(
datalen
<
0
)
{
std
::
cerr
<<
"nghttp2_session_mem_send() returned error: "
<<
nghttp2_strerror
(
datalen
)
<<
std
::
endl
;
return
-
1
;
}
if
(
datalen
==
0
)
{
break
;
}
rv
=
tls_write
(
data
,
datalen
);
if
(
rv
!=
0
)
{
return
rv
;
}
}
rv
=
tls_write_pending
();
if
(
rv
!=
0
)
{
return
rv
;
}
return
wait_events
();
return
send
();
}
namespace
{
...
...
src/HttpServer.h
View file @
a9b74261
...
...
@@ -40,6 +40,7 @@
#include <openssl/ssl.h>
#include <event2/event.h>
#include <event2/bufferevent.h>
#include <nghttp2/nghttp2.h>
...
...
@@ -104,12 +105,11 @@ public:
void
remove_self
();
int
setup_bev
();
int
send
();
int
on_read
();
int
on_write
();
int
on_connect
();
int
verify_npn_result
();
int
sendcb
(
const
uint8_t
*
data
,
size_t
len
);
int
recvcb
(
uint8_t
*
buf
,
size_t
len
);
int
submit_file_response
(
const
std
::
string
&
status
,
Stream
*
stream
,
...
...
@@ -141,25 +141,15 @@ public:
const
Config
*
get_config
()
const
;
void
remove_settings_timer
();
void
terminate_session
(
uint32_t
error_code
);
int
tls_handshake
();
private:
int
handle_ssl_temporal_error
(
int
err
);
int
tls_write
(
const
uint8_t
*
data
,
size_t
datalen
);
int
tls_write_pending
();
int
wait_events
();
std
::
map
<
int32_t
,
std
::
unique_ptr
<
Stream
>>
id2stream_
;
nghttp2_buf
sendbuf_
;
int64_t
session_id_
;
nghttp2_session
*
session_
;
Sessions
*
sessions_
;
SSL
*
ssl_
;
event
*
rev_
,
*
w
ev_
;
SSL
*
ssl_
;
bufferevent
*
b
ev_
;
event
*
settings_timerev_
;
const
uint8_t
*
pending_data_
;
size_t
pending_datalen_
;
int
fd_
;
uint8_t
sendbufarray_
[
65536
];
};
class
HttpServer
{
...
...
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