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
Hide 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 @@
...
@@ -43,7 +43,7 @@
#include <event.h>
#include <event.h>
#include <event2/listener.h>
#include <event2/listener.h>
#include <event2/bufferevent.h>
#include <event2/bufferevent
_ssl
.h>
#ifdef __cplusplus
#ifdef __cplusplus
extern
"C"
{
extern
"C"
{
...
@@ -336,25 +336,14 @@ Http2Handler::Http2Handler(Sessions *sessions,
...
@@ -336,25 +336,14 @@ Http2Handler::Http2Handler(Sessions *sessions,
session_
(
nullptr
),
session_
(
nullptr
),
sessions_
(
sessions
),
sessions_
(
sessions
),
ssl_
(
ssl
),
ssl_
(
ssl
),
rev_
(
nullptr
),
bev_
(
nullptr
),
wev_
(
nullptr
),
settings_timerev_
(
nullptr
),
settings_timerev_
(
nullptr
),
pending_data_
(
nullptr
),
pending_datalen_
(
0
),
fd_
(
fd
)
fd_
(
fd
)
{
{}
nghttp2_buf_wrap_init
(
&
sendbuf_
,
sendbufarray_
,
sizeof
(
sendbufarray_
));
}
Http2Handler
::~
Http2Handler
()
Http2Handler
::~
Http2Handler
()
{
{
on_session_closed
(
this
,
session_id_
);
on_session_closed
(
this
,
session_id_
);
if
(
rev_
)
{
event_free
(
rev_
);
}
if
(
wev_
)
{
event_free
(
wev_
);
}
if
(
settings_timerev_
)
{
if
(
settings_timerev_
)
{
event_free
(
settings_timerev_
);
event_free
(
settings_timerev_
);
}
}
...
@@ -363,6 +352,10 @@ Http2Handler::~Http2Handler()
...
@@ -363,6 +352,10 @@ Http2Handler::~Http2Handler()
SSL_set_shutdown
(
ssl_
,
SSL_RECEIVED_SHUTDOWN
);
SSL_set_shutdown
(
ssl_
,
SSL_RECEIVED_SHUTDOWN
);
SSL_shutdown
(
ssl_
);
SSL_shutdown
(
ssl_
);
}
}
if
(
bev_
)
{
bufferevent_disable
(
bev_
,
EV_READ
|
EV_WRITE
);
bufferevent_free
(
bev_
);
}
if
(
ssl_
)
{
if
(
ssl_
)
{
SSL_free
(
ssl_
);
SSL_free
(
ssl_
);
}
}
...
@@ -376,333 +369,157 @@ void Http2Handler::remove_self()
...
@@ -376,333 +369,157 @@ void Http2Handler::remove_self()
}
}
namespace
{
namespace
{
void
re
v_cb
(
evutil_socket_t
fd
,
short
what
,
void
*
arg
)
void
re
adcb
(
bufferevent
*
bev
,
void
*
arg
)
{
{
int
rv
;
int
rv
;
auto
handler
=
static_cast
<
Http2Handler
*>
(
arg
);
auto
handler
=
static_cast
<
Http2Handler
*>
(
arg
);
if
(
what
&
EV_READ
)
{
rv
=
handler
->
on_read
();
rv
=
handler
->
on_read
();
if
(
rv
==
-
1
)
{
if
(
rv
==
-
1
)
{
delete_handler
(
handler
);
delete_handler
(
handler
);
}
}
}
}
}
}
// namespace
}
// namespace
namespace
{
namespace
{
void
w
ev_cb
(
evutil_socket_t
fd
,
short
what
,
void
*
arg
)
void
w
ritecb
(
bufferevent
*
bev
,
void
*
arg
)
{
{
int
rv
;
int
rv
;
auto
handler
=
static_cast
<
Http2Handler
*>
(
arg
);
auto
handler
=
static_cast
<
Http2Handler
*>
(
arg
);
if
(
what
&
EV_WRITE
)
{
rv
=
handler
->
on_write
();
rv
=
handler
->
on_write
();
if
(
rv
==
-
1
)
{
if
(
rv
==
-
1
)
{
delete_handler
(
handler
);
delete_handler
(
handler
);
}
}
}
}
}
}
// namespace
}
// 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
;
}
return
-
1
;
}
int
Http2Handler
::
tls_write
(
const
uint8_t
*
data
,
size_t
datalen
)
{
{
int
rv
;
auto
handler
=
static_cast
<
Http2Handler
*>
(
arg
);
size_t
max_avail
;
// OpenSSL sends at most 16K bytes
max_avail
=
ssl_
?
std
::
min
((
ssize_t
)
16384
,
nghttp2_buf_avail
(
&
sendbuf_
))
:
nghttp2_buf_avail
(
&
sendbuf_
);
if
(
max_avail
<
datalen
)
{
if
(
nghttp2_buf_len
(
&
sendbuf_
)
>
0
)
{
rv
=
tls_write_pending
();
if
(
rv
==
-
1
)
{
return
-
1
;
}
if
(
rv
==
1
)
{
pending_data_
=
data
;
pending_datalen_
=
datalen
;
return
1
;
}
}
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
;
}
int
Http2Handler
::
tls_write_pending
()
if
(
events
&
(
BEV_EVENT_EOF
|
BEV_EVENT_ERROR
|
BEV_EVENT_TIMEOUT
))
{
{
delete_handler
(
handler
);
int
rv
;
if
(
nghttp2_buf_len
(
&
sendbuf_
)
==
0
)
{
return
;
return
0
;
}
}
for
(;;)
{
if
(
events
&
BEV_EVENT_CONNECTED
)
{
if
(
ssl_
)
{
if
(
handler
->
get_sessions
()
->
get_config
()
->
verbose
)
{
ERR_clear_error
();
std
::
cerr
<<
"SSL/TLS handshake completed"
<<
std
::
endl
;
rv
=
SSL_write
(
ssl_
,
sendbuf_
.
pos
,
nghttp2_buf_len
(
&
sendbuf_
));
if
(
rv
==
0
)
{
return
-
1
;
}
if
(
rv
<
0
)
{
return
handle_ssl_temporal_error
(
rv
);
}
}
else
{
while
((
rv
=
write
(
fd_
,
sendbuf_
.
pos
,
nghttp2_buf_len
(
&
sendbuf_
)))
&&
rv
==
-
1
&&
errno
==
EINTR
);
if
(
rv
==
0
)
{
continue
;
}
if
(
rv
<
0
)
{
if
(
errno
==
EAGAIN
||
errno
==
EWOULDBLOCK
)
{
event_add
(
wev_
,
nullptr
);
return
1
;
}
return
-
1
;
}
}
}
sendbuf_
.
pos
+=
rv
;
if
(
handler
->
verify_npn_result
()
!=
0
)
{
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
;
}
return
0
;
}
}
}
namespace
{
void
tls_handshake_cb
(
evutil_socket_t
fd
,
short
what
,
void
*
arg
)
{
int
rv
;
auto
handler
=
static_cast
<
Http2Handler
*>
(
arg
);
if
(
what
&
(
EV_READ
|
EV_WRITE
))
{
rv
=
handler
->
tls_handshake
();
if
(
rv
==
-
1
)
{
delete_handler
(
handler
);
delete_handler
(
handler
);
return
;
}
if
(
rv
==
1
)
{
return
;
return
;
}
}
rv
=
handler
->
on_connect
();
if
(
handler
->
on_connect
()
!=
0
)
{
if
(
rv
!=
0
)
{
delete_handler
(
handler
);
delete_handler
(
handler
);
return
;
return
;
}
}
}
}
}
}
}
// namespace
}
// namespace
int
Http2Handler
::
tls_handshake
()
{
int
rv
;
ERR_clear_error
();
rv
=
SSL_accept
(
ssl_
);
if
(
rv
==
0
)
{
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
:
break
;
case
SSL_ERROR_WANT_READ
:
event_add
(
rev_
,
nullptr
);
return
1
;
case
SSL_ERROR_WANT_WRITE
:
event_add
(
wev_
,
nullptr
);
return
1
;
}
}
if
(
sessions_
->
get_config
()
->
verbose
)
{
std
::
cerr
<<
"SSL/TLS handshake completed"
<<
std
::
endl
;
}
if
(
verify_npn_result
()
!=
0
)
{
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
);
return
0
;
}
int
Http2Handler
::
setup_bev
()
int
Http2Handler
::
setup_bev
()
{
{
auto
evbase
=
sessions_
->
get_evbase
();
if
(
ssl_
)
{
if
(
ssl_
)
{
rev_
=
event_new
(
sessions_
->
get_evbase
(),
fd_
,
EV_READ
,
tls_handshake_cb
,
bev_
=
bufferevent_openssl_socket_new
(
evbase
,
fd_
,
ssl_
,
this
);
BUFFEREVENT_SSL_ACCEPTING
,
wev_
=
event_new
(
sessions_
->
get_evbase
(),
fd_
,
EV_WRITE
,
tls_handshake_cb
,
BEV_OPT_DEFER_CALLBACKS
);
this
);
}
else
{
}
else
{
rev_
=
event_new
(
sessions_
->
get_evbase
(),
fd_
,
EV_READ
,
rev_cb
,
this
);
bev_
=
bufferevent_socket_new
(
evbase
,
fd_
,
BEV_OPT_DEFER_CALLBACKS
);
wev_
=
event_new
(
sessions_
->
get_evbase
(),
fd_
,
EV_WRITE
,
wev_cb
,
this
);
}
}
event_add
(
rev_
,
nullptr
);
bufferevent_enable
(
bev_
,
EV_READ
);
// TODO set up timeout here
bufferevent_setcb
(
bev_
,
readcb
,
writecb
,
eventcb
,
this
);
return
0
;
return
0
;
}
}
int
Http2Handler
::
wait_events
()
int
Http2Handler
::
send
()
{
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
;
int
rv
;
uint8_t
buf
[
16384
];
uint8_t
buf
[
16384
];
uint8_t
*
bufp
;
auto
output
=
bufferevent_get_output
(
bev_
);
size_t
nread
;
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
;
}
if
(
ssl_
)
{
const
uint8_t
*
data
;
ERR_clear_error
();
auto
datalen
=
nghttp2_session_mem_send
(
session_
,
&
data
);
rv
=
SSL_read
(
ssl_
,
buf
,
sizeof
(
buf
));
if
(
rv
==
0
)
{
if
(
datalen
<
0
)
{
std
::
cerr
<<
"nghttp2_session_mem_send() returned error: "
<<
nghttp2_strerror
(
datalen
)
<<
std
::
endl
;
return
-
1
;
return
-
1
;
}
}
if
(
rv
<
0
)
{
if
(
datalen
==
0
)
{
return
handle_ssl_temporal_error
(
rv
);
break
;
}
}
else
{
while
((
rv
=
read
(
fd_
,
buf
,
sizeof
(
buf
)))
&&
rv
==
-
1
&&
errno
==
EINTR
);
if
(
rv
==
0
)
{
return
-
1
;
}
}
if
(
rv
<
0
)
{
rv
=
evbbuf
.
add
(
data
,
datalen
);
if
(
errno
==
EAGAIN
||
errno
==
EWOULDBLOCK
)
{
if
(
rv
!=
0
)
{
event_add
(
rev_
,
nullptr
);
std
::
cerr
<<
"evbuffer_add() failed"
<<
std
::
endl
;
return
1
;
}
return
-
1
;
return
-
1
;
}
}
}
}
nread
=
rv
;
rv
=
evbbuf
.
flush
();
bufp
=
buf
;
if
(
rv
!=
0
)
{
std
::
cerr
<<
"evbuffer_add() failed"
<<
std
::
endl
;
return
-
1
;
}
if
(
nghttp2_session_want_read
(
session_
)
==
0
&&
nghttp2_session_want_write
(
session_
)
==
0
&&
evbuffer_get_length
(
output
)
==
0
)
{
rv
=
nghttp2_session_mem_recv
(
session_
,
bufp
,
nread
);
if
(
rv
<
0
)
{
std
::
cerr
<<
"nghttp2_session_mem_recv() returned error: "
<<
nghttp2_strerror
(
rv
)
<<
std
::
endl
;
return
-
1
;
return
-
1
;
}
}
return
wait_events
()
;
return
0
;
}
}
int
Http2Handler
::
on_
write
()
int
Http2Handler
::
on_
read
()
{
{
int
rv
;
int
rv
;
//std::cerr << "DBG: on_write" << std::endl;
auto
input
=
bufferevent_get_input
(
bev_
);
rv
=
tls_write_pending
();
if
(
rv
!=
0
)
{
return
rv
;
}
for
(;;)
{
for
(;;)
{
const
uint8_t
*
data
;
auto
len
=
evbuffer_get_contiguous_space
(
input
);
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
(
data
len
==
0
)
{
if
(
len
==
0
)
{
break
;
break
;
}
}
rv
=
tls_write
(
data
,
data
len
);
auto
data
=
evbuffer_pullup
(
input
,
len
);
if
(
rv
!=
0
)
{
rv
=
nghttp2_session_mem_recv
(
session_
,
data
,
len
);
return
rv
;
if
(
rv
<
0
)
{
std
::
cerr
<<
"nghttp2_session_mem_recv() returned error: "
<<
nghttp2_strerror
(
rv
)
<<
std
::
endl
;
return
-
1
;
}
}
}
rv
=
tls_write_pending
();
evbuffer_drain
(
input
,
len
);
if
(
rv
!=
0
)
{
return
rv
;
}
}
return
wait_events
();
return
send
();
}
int
Http2Handler
::
on_write
()
{
return
send
();
}
}
namespace
{
namespace
{
...
...
src/HttpServer.h
View file @
a9b74261
...
@@ -40,6 +40,7 @@
...
@@ -40,6 +40,7 @@
#include <openssl/ssl.h>
#include <openssl/ssl.h>
#include <event2/event.h>
#include <event2/event.h>
#include <event2/bufferevent.h>
#include <nghttp2/nghttp2.h>
#include <nghttp2/nghttp2.h>
...
@@ -104,12 +105,11 @@ public:
...
@@ -104,12 +105,11 @@ public:
void
remove_self
();
void
remove_self
();
int
setup_bev
();
int
setup_bev
();
int
send
();
int
on_read
();
int
on_read
();
int
on_write
();
int
on_write
();
int
on_connect
();
int
on_connect
();
int
verify_npn_result
();
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
,
int
submit_file_response
(
const
std
::
string
&
status
,
Stream
*
stream
,
Stream
*
stream
,
...
@@ -141,25 +141,15 @@ public:
...
@@ -141,25 +141,15 @@ public:
const
Config
*
get_config
()
const
;
const
Config
*
get_config
()
const
;
void
remove_settings_timer
();
void
remove_settings_timer
();
void
terminate_session
(
uint32_t
error_code
);
void
terminate_session
(
uint32_t
error_code
);
int
tls_handshake
();
private:
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_
;
std
::
map
<
int32_t
,
std
::
unique_ptr
<
Stream
>>
id2stream_
;
nghttp2_buf
sendbuf_
;
int64_t
session_id_
;
int64_t
session_id_
;
nghttp2_session
*
session_
;
nghttp2_session
*
session_
;
Sessions
*
sessions_
;
Sessions
*
sessions_
;
SSL
*
ssl_
;
SSL
*
ssl_
;
event
*
rev_
,
*
w
ev_
;
bufferevent
*
b
ev_
;
event
*
settings_timerev_
;
event
*
settings_timerev_
;
const
uint8_t
*
pending_data_
;
size_t
pending_datalen_
;
int
fd_
;
int
fd_
;
uint8_t
sendbufarray_
[
65536
];
};
};
class
HttpServer
{
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