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
1795d3ea
Commit
1795d3ea
authored
Jan 10, 2015
by
Tatsuhiro Tsujikawa
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
nghttp: Add include file to clarify used objects
parent
b933ee8e
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
1321 additions
and
1241 deletions
+1321
-1241
src/Makefile.am
src/Makefile.am
+1
-1
src/nghttp.cc
src/nghttp.cc
+1043
-1240
src/nghttp.h
src/nghttp.h
+277
-0
No files found.
src/Makefile.am
View file @
1795d3ea
...
...
@@ -72,7 +72,7 @@ if HAVE_LIBXML2
HTML_PARSER_OBJECTS
+=
HtmlParser.cc
endif
# HAVE_LIBXML2
nghttp_SOURCES
=
${HELPER_OBJECTS}
${HELPER_HFILES}
nghttp.cc
\
nghttp_SOURCES
=
${HELPER_OBJECTS}
${HELPER_HFILES}
nghttp.cc
nghttp.h
\
${HTML_PARSER_OBJECTS}
${HTML_PARSER_HFILES}
\
ssl.cc ssl.h
...
...
src/nghttp.cc
View file @
1795d3ea
...
...
@@ -22,17 +22,13 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "nghttp
2_config
.h"
#include "nghttp.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <signal.h>
#include <getopt.h>
#include <cassert>
...
...
@@ -40,40 +36,22 @@
#include <cerrno>
#include <cstdlib>
#include <cstring>
#include <string>
#include <iostream>
#include <string>
#include <set>
#include <iomanip>
#include <fstream>
#include <map>
#include <vector>
#include <sstream>
#include <tuple>
#include <chrono>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/conf.h>
#include <ev.h>
#include <nghttp2/nghttp2.h>
#ifdef HAVE_JANSSON
#include <jansson.h>
#endif // HAVE_JANSSON
#include "http-parser/http_parser.h"
#include "app_helper.h"
#include "HtmlParser.h"
#include "util.h"
#include "base64.h"
#include "http2.h"
#include "nghttp2_gzip.h"
#include "ssl.h"
#include "ringbuf.h"
#ifndef O_BINARY
#define O_BINARY (0)
...
...
@@ -92,36 +70,7 @@ enum {
ANCHOR_ID_LOWEST
=
9
,
};
namespace
{
struct
Config
{
Headers
headers
;
std
::
string
certfile
;
std
::
string
keyfile
;
std
::
string
datafile
;
std
::
string
harfile
;
nghttp2_option
*
http2_option
;
size_t
output_upper_thres
;
size_t
padding
;
ssize_t
peer_max_concurrent_streams
;
ssize_t
header_table_size
;
int32_t
weight
;
int
multiply
;
// milliseconds
ev_tstamp
timeout
;
int
window_bits
;
int
connection_window_bits
;
int
verbose
;
bool
null_out
;
bool
remote_name
;
bool
get_assets
;
bool
stat
;
bool
upgrade
;
bool
continuation
;
bool
no_content_length
;
bool
no_dep
;
bool
dep_idle
;
Config
()
Config
::
Config
()
:
output_upper_thres
(
1024
*
1024
),
padding
(
0
),
peer_max_concurrent_streams
(
NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS
),
header_table_size
(
-
1
),
weight
(
NGHTTP2_DEFAULT_WEIGHT
),
multiply
(
1
),
...
...
@@ -132,11 +81,9 @@ struct Config {
nghttp2_option_new
(
&
http2_option
);
nghttp2_option_set_peer_max_concurrent_streams
(
http2_option
,
peer_max_concurrent_streams
);
}
}
~
Config
()
{
nghttp2_option_del
(
http2_option
);
}
};
}
// namespace
Config
::~
Config
()
{
nghttp2_option_del
(
http2_option
);
}
namespace
{
Config
config
;
...
...
@@ -150,23 +97,6 @@ void print_protocol_nego_error() {
}
}
// namespace
enum
StatStage
{
STAT_INITIAL
,
STAT_ON_REQUEST
,
STAT_ON_RESPONSE
,
STAT_ON_COMPLETE
};
namespace
{
struct
RequestStat
{
std
::
chrono
::
steady_clock
::
time_point
on_request_time
;
std
::
chrono
::
steady_clock
::
time_point
on_response_time
;
std
::
chrono
::
steady_clock
::
time_point
on_complete_time
;
StatStage
stage
;
RequestStat
()
:
stage
(
STAT_INITIAL
)
{}
};
}
// namespace
namespace
{
std
::
string
strip_fragment
(
const
char
*
raw_uri
)
{
const
char
*
end
;
...
...
@@ -191,49 +121,10 @@ std::string numeric_name(addrinfo *addr) {
}
}
// namespace
namespace
{
struct
Request
;
}
// namespace
namespace
{
struct
Dependency
{
std
::
vector
<
std
::
vector
<
Request
*>>
deps
;
};
}
// namespace
namespace
{
struct
Request
{
Headers
res_nva
;
Headers
req_nva
;
// URI without fragment
std
::
string
uri
;
http_parser_url
u
;
std
::
shared_ptr
<
Dependency
>
dep
;
nghttp2_priority_spec
pri_spec
;
RequestStat
stat
;
int64_t
data_length
;
int64_t
data_offset
;
// Number of bytes received from server
int64_t
response_len
;
nghttp2_gzip
*
inflater
;
HtmlParser
*
html_parser
;
const
nghttp2_data_provider
*
data_prd
;
int32_t
stream_id
;
int
status
;
// Recursion level: 0: first entity, 1: entity linked from first entity
int
level
;
// RequestPriority value defined in HtmlParser.h
int
pri
;
int
res_hdidx
[
http2
::
HD_MAXIDX
];
// used for incoming PUSH_PROMISE
int
req_hdidx
[
http2
::
HD_MAXIDX
];
bool
expect_final_response
;
// For pushed request, |uri| is empty and |u| is zero-cleared.
Request
(
const
std
::
string
&
uri
,
const
http_parser_url
&
u
,
Request
::
Request
(
const
std
::
string
&
uri
,
const
http_parser_url
&
u
,
const
nghttp2_data_provider
*
data_prd
,
int64_t
data_length
,
const
nghttp2_priority_spec
&
pri_spec
,
std
::
shared_ptr
<
Dependency
>
dep
,
int
pri
=
0
,
int
level
=
0
)
std
::
shared_ptr
<
Dependency
>
dep
,
int
pri
,
int
level
)
:
uri
(
uri
),
u
(
u
),
dep
(
std
::
move
(
dep
)),
pri_spec
(
pri_spec
),
data_length
(
data_length
),
data_offset
(
0
),
response_len
(
0
),
inflater
(
nullptr
),
html_parser
(
nullptr
),
data_prd
(
data_prd
),
...
...
@@ -241,32 +132,30 @@ struct Request {
expect_final_response
(
false
)
{
http2
::
init_hdidx
(
res_hdidx
);
http2
::
init_hdidx
(
req_hdidx
);
}
}
~
Request
()
{
Request
::
~
Request
()
{
nghttp2_gzip_inflate_del
(
inflater
);
delete
html_parser
;
}
}
void
init_inflater
()
{
void
Request
::
init_inflater
()
{
int
rv
;
rv
=
nghttp2_gzip_inflate_new
(
&
inflater
);
assert
(
rv
==
0
);
}
}
void
init_html_parser
()
{
html_parser
=
new
HtmlParser
(
uri
);
}
void
Request
::
init_html_parser
()
{
html_parser
=
new
HtmlParser
(
uri
);
}
int
update_html_parser
(
const
uint8_t
*
data
,
size_t
len
,
int
fin
)
{
int
Request
::
update_html_parser
(
const
uint8_t
*
data
,
size_t
len
,
int
fin
)
{
if
(
!
html_parser
)
{
return
0
;
}
int
rv
;
rv
=
html_parser
->
parse_chunk
(
reinterpret_cast
<
const
char
*>
(
data
),
len
,
return
html_parser
->
parse_chunk
(
reinterpret_cast
<
const
char
*>
(
data
),
len
,
fin
);
return
rv
;
}
}
std
::
string
make_reqpath
()
const
{
std
::
string
Request
::
make_reqpath
()
const
{
std
::
string
path
=
util
::
has_uri_field
(
u
,
UF_PATH
)
?
util
::
get_uri_field
(
uri
.
c_str
(),
u
,
UF_PATH
)
:
"/"
;
...
...
@@ -276,18 +165,18 @@ struct Request {
u
.
field_data
[
UF_QUERY
].
len
);
}
return
path
;
}
}
int32_t
find_dep_stream_id
(
int
start
)
{
int32_t
Request
::
find_dep_stream_id
(
int
start
)
{
for
(
auto
i
=
start
;
i
>=
0
;
--
i
)
{
for
(
auto
req
:
dep
->
deps
[
i
])
{
return
req
->
stream_id
;
}
}
return
-
1
;
}
}
nghttp2_priority_spec
resolve_dep
(
int32_t
pri
)
{
nghttp2_priority_spec
Request
::
resolve_dep
(
int32_t
pri
)
{
nghttp2_priority_spec
pri_spec
;
int
exclusive
=
0
;
int32_t
stream_id
=
-
1
;
...
...
@@ -314,8 +203,7 @@ struct Request {
anchor_id
=
ANCHOR_ID_LOWEST
;
break
;
}
nghttp2_priority_spec_init
(
&
pri_spec
,
anchor_id
,
NGHTTP2_DEFAULT_WEIGHT
,
0
);
nghttp2_priority_spec_init
(
&
pri_spec
,
anchor_id
,
NGHTTP2_DEFAULT_WEIGHT
,
0
);
return
pri_spec
;
}
...
...
@@ -349,18 +237,18 @@ struct Request {
exclusive
);
return
pri_spec
;
}
}
bool
is_ipv6_literal_addr
()
const
{
bool
Request
::
is_ipv6_literal_addr
()
const
{
if
(
util
::
has_uri_field
(
u
,
UF_HOST
))
{
return
memchr
(
uri
.
c_str
()
+
u
.
field_data
[
UF_HOST
].
off
,
':'
,
u
.
field_data
[
UF_HOST
].
len
);
}
else
{
return
false
;
}
}
}
bool
response_pseudo_header_allowed
(
int
token
)
const
{
bool
Request
::
response_pseudo_header_allowed
(
int
token
)
const
{
if
(
!
res_nva
.
empty
()
&&
res_nva
.
back
().
name
.
c_str
()[
0
]
!=
':'
)
{
return
false
;
}
...
...
@@ -370,9 +258,9 @@ struct Request {
default:
return
false
;
}
}
}
bool
push_request_pseudo_header_allowed
(
int
token
)
const
{
bool
Request
::
push_request_pseudo_header_allowed
(
int
token
)
const
{
if
(
!
req_nva
.
empty
()
&&
req_nva
.
back
().
name
.
c_str
()[
0
]
!=
':'
)
{
return
false
;
}
...
...
@@ -385,157 +273,183 @@ struct Request {
default:
return
false
;
}
}
}
Headers
::
value_type
*
get_res_header
(
int
token
)
{
Headers
::
value_type
*
Request
::
get_res_header
(
int
token
)
{
auto
idx
=
res_hdidx
[
token
];
if
(
idx
==
-
1
)
{
return
nullptr
;
}
return
&
res_nva
[
idx
];
}
}
Headers
::
value_type
*
get_req_header
(
int
token
)
{
Headers
::
value_type
*
Request
::
get_req_header
(
int
token
)
{
auto
idx
=
req_hdidx
[
token
];
if
(
idx
==
-
1
)
{
return
nullptr
;
}
return
&
req_nva
[
idx
];
}
}
void
record_request_time
()
{
void
Request
::
record_request_time
()
{
stat
.
stage
=
STAT_ON_REQUEST
;
stat
.
on_request_time
=
get_time
();
}
}
void
record_response_time
()
{
void
Request
::
record_response_time
()
{
stat
.
stage
=
STAT_ON_RESPONSE
;
stat
.
on_response_time
=
get_time
();
}
}
void
record_complete_time
()
{
void
Request
::
record_complete_time
()
{
stat
.
stage
=
STAT_ON_COMPLETE
;
stat
.
on_complete_time
=
get_time
();
}
namespace
{
int
htp_msg_begincb
(
http_parser
*
htp
)
{
if
(
config
.
verbose
)
{
print_timer
();
std
::
cout
<<
" HTTP Upgrade response"
<<
std
::
endl
;
}
};
return
0
;
}
}
// namespace
namespace
{
struct
SessionStat
{
// The point in time when download was started.
std
::
chrono
::
system_clock
::
time_point
started_system_time
;
// The point of time when download was started.
std
::
chrono
::
steady_clock
::
time_point
on_started_time
;
// The point of time when DNS resolution was completed.
std
::
chrono
::
steady_clock
::
time_point
on_dns_complete_time
;
// The point of time when connection was established or SSL/TLS
// handshake was completed.
std
::
chrono
::
steady_clock
::
time_point
on_connect_time
;
// The point of time when HTTP/2 commnucation was started.
std
::
chrono
::
steady_clock
::
time_point
on_handshake_time
;
int
htp_statuscb
(
http_parser
*
htp
,
const
char
*
at
,
size_t
length
)
{
auto
client
=
static_cast
<
HttpClient
*>
(
htp
->
data
);
client
->
upgrade_response_status_code
=
htp
->
status_code
;
return
0
;
}
}
// namespace
namespace
{
int
htp_msg_completecb
(
http_parser
*
htp
)
{
auto
client
=
static_cast
<
HttpClient
*>
(
htp
->
data
);
client
->
upgrade_response_complete
=
true
;
return
0
;
}
}
// namespace
namespace
{
http_parser_settings
htp_hooks
=
{
htp_msg_begincb
,
// http_cb on_message_begin;
nullptr
,
// http_data_cb on_url;
htp_statuscb
,
// http_data_cb on_status;
nullptr
,
// http_data_cb on_header_field;
nullptr
,
// http_data_cb on_header_value;
nullptr
,
// http_cb on_headers_complete;
nullptr
,
// http_data_cb on_body;
htp_msg_completecb
// http_cb on_message_complete;
};
}
// namespace
namespace
{
size_t
populate_settings
(
nghttp2_settings_entry
*
iv
)
{
size_t
niv
=
2
;
int
submit_request
(
HttpClient
*
client
,
const
Headers
&
headers
,
Request
*
req
)
{
auto
path
=
req
->
make_reqpath
();
auto
scheme
=
util
::
get_uri_field
(
req
->
uri
.
c_str
(),
req
->
u
,
UF_SCHEMA
);
auto
build_headers
=
Headers
{{
":method"
,
req
->
data_prd
?
"POST"
:
"GET"
},
{
":path"
,
path
},
{
":scheme"
,
scheme
},
{
":authority"
,
client
->
hostport
},
{
"accept"
,
"*/*"
},
{
"accept-encoding"
,
"gzip, deflate"
},
{
"user-agent"
,
"nghttp2/"
NGHTTP2_VERSION
}};
if
(
config
.
continuation
)
{
for
(
size_t
i
=
0
;
i
<
6
;
++
i
)
{
build_headers
.
emplace_back
(
"continuation-test-"
+
util
::
utos
(
i
+
1
),
std
::
string
(
4096
,
'-'
));
}
}
auto
num_initial_headers
=
build_headers
.
size
();
if
(
!
config
.
no_content_length
&&
req
->
data_prd
)
{
build_headers
.
emplace_back
(
"content-length"
,
util
::
utos
(
req
->
data_length
));
}
for
(
auto
&
kv
:
headers
)
{
size_t
i
;
for
(
i
=
0
;
i
<
num_initial_headers
;
++
i
)
{
if
(
kv
.
name
==
build_headers
[
i
].
name
)
{
build_headers
[
i
].
value
=
kv
.
value
;
break
;
}
}
if
(
i
<
num_initial_headers
)
{
continue
;
}
iv
[
0
].
settings_id
=
NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS
;
iv
[
0
].
value
=
100
;
build_headers
.
emplace_back
(
kv
.
name
,
kv
.
value
,
kv
.
no_index
)
;
}
iv
[
1
].
settings_id
=
NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE
;
if
(
config
.
window_bits
!=
-
1
)
{
iv
[
1
].
value
=
(
1
<<
config
.
window_bits
)
-
1
;
}
else
{
iv
[
1
].
value
=
NGHTTP2_INITIAL_WINDOW_SIZE
;
auto
nva
=
std
::
vector
<
nghttp2_nv
>
()
;
nva
.
reserve
(
build_headers
.
size
());
for
(
auto
&
kv
:
build_headers
)
{
nva
.
push_back
(
http2
::
make_nv
(
kv
.
name
,
kv
.
value
,
kv
.
no_index
))
;
}
if
(
config
.
header_table_size
>=
0
)
{
iv
[
niv
].
settings_id
=
NGHTTP2_SETTINGS_HEADER_TABLE_SIZE
;
iv
[
niv
].
value
=
config
.
header_table_size
;
++
niv
;
auto
stream_id
=
nghttp2_submit_request
(
client
->
session
,
&
req
->
pri_spec
,
nva
.
data
(),
nva
.
size
(),
req
->
data_prd
,
req
);
if
(
stream_id
<
0
)
{
std
::
cerr
<<
"[ERROR] nghttp2_submit_request() returned error: "
<<
nghttp2_strerror
(
stream_id
)
<<
std
::
endl
;
return
-
1
;
}
return
niv
;
}
}
// namespace
namespace
{
extern
http_parser_settings
htp_hooks
;
}
// namespace
req
->
stream_id
=
stream_id
;
client
->
on_request
(
req
);
namespace
{
void
readcb
(
struct
ev_loop
*
loop
,
ev_io
*
w
,
int
revents
);
}
// namespace
req
->
req_nva
=
std
::
move
(
build_headers
);
namespace
{
void
writecb
(
struct
ev_loop
*
loop
,
ev_io
*
w
,
int
revents
);
return
0
;
}
}
// namespace
namespace
{
void
timeoutcb
(
struct
ev_loop
*
loop
,
ev_timer
*
w
,
int
revents
);
void
readcb
(
struct
ev_loop
*
loop
,
ev_io
*
w
,
int
revents
)
{
auto
client
=
static_cast
<
HttpClient
*>
(
w
->
data
);
if
(
client
->
do_read
()
!=
0
)
{
client
->
disconnect
();
}
}
}
// namespace
namespace
{
struct
HttpClient
;
void
writecb
(
struct
ev_loop
*
loop
,
ev_io
*
w
,
int
revents
)
{
auto
client
=
static_cast
<
HttpClient
*>
(
w
->
data
);
auto
rv
=
client
->
do_write
();
if
(
rv
==
HttpClient
::
ERR_CONNECT_FAIL
)
{
client
->
on_connect_fail
();
return
;
}
if
(
rv
!=
0
)
{
client
->
disconnect
();
}
}
}
// namespace
namespace
{
int
submit_request
(
HttpClient
*
client
,
const
Headers
&
headers
,
Request
*
req
);
void
timeoutcb
(
struct
ev_loop
*
loop
,
ev_timer
*
w
,
int
revents
)
{
auto
client
=
static_cast
<
HttpClient
*>
(
w
->
data
);
std
::
cerr
<<
"[ERROR] Timeout"
<<
std
::
endl
;
client
->
disconnect
();
}
}
// namespace
namespace
{
void
settings_timeout_cb
(
struct
ev_loop
*
loop
,
ev_timer
*
w
,
int
revents
);
}
// namespace
void
settings_timeout_cb
(
struct
ev_loop
*
loop
,
ev_timer
*
w
,
int
revents
)
{
auto
client
=
static_cast
<
HttpClient
*>
(
w
->
data
);
ev_timer_stop
(
loop
,
w
);
enum
client_state
{
STATE_IDLE
,
STATE_CONNECTED
}
;
nghttp2_session_terminate_session
(
client
->
session
,
NGHTTP2_SETTINGS_TIMEOUT
)
;
namespace
{
struct
HttpClient
{
std
::
vector
<
std
::
unique_ptr
<
Request
>>
reqvec
;
// Insert path already added in reqvec to prevent multiple request
// for 1 resource.
std
::
set
<
std
::
string
>
path_cache
;
std
::
string
scheme
;
std
::
string
host
;
std
::
string
hostport
;
// Used for parse the HTTP upgrade response from server
std
::
unique_ptr
<
http_parser
>
htp
;
SessionStat
stat
;
ev_io
wev
;
ev_io
rev
;
ev_timer
wt
;
ev_timer
rt
;
ev_timer
settings_timer
;
std
::
function
<
int
(
HttpClient
&
)
>
readfn
,
writefn
;
std
::
function
<
int
(
HttpClient
&
,
const
uint8_t
*
,
size_t
)
>
on_readfn
;
std
::
function
<
int
(
HttpClient
&
)
>
on_writefn
;
nghttp2_session
*
session
;
const
nghttp2_session_callbacks
*
callbacks
;
struct
ev_loop
*
loop
;
SSL_CTX
*
ssl_ctx
;
SSL
*
ssl
;
addrinfo
*
addrs
;
addrinfo
*
next_addr
;
addrinfo
*
cur_addr
;
// The number of completed requests, including failed ones.
size_t
complete
;
// The length of settings_payload
size_t
settings_payloadlen
;
client_state
state
;
// The HTTP status code of the response message of HTTP Upgrade.
unsigned
int
upgrade_response_status_code
;
int
fd
;
// true if the response message of HTTP Upgrade request is fully
// received. It is not relevant the upgrade succeeds, or not.
bool
upgrade_response_complete
;
RingBuf
<
65536
>
wb
;
// SETTINGS payload sent as token68 in HTTP Upgrade
uint8_t
settings_payload
[
128
];
enum
{
ERR_CONNECT_FAIL
=
-
100
};
HttpClient
(
const
nghttp2_session_callbacks
*
callbacks
,
struct
ev_loop
*
loop
,
SSL_CTX
*
ssl_ctx
)
client
->
signal_write
();
}
}
// namespace
HttpClient
::
HttpClient
(
const
nghttp2_session_callbacks
*
callbacks
,
struct
ev_loop
*
loop
,
SSL_CTX
*
ssl_ctx
)
:
session
(
nullptr
),
callbacks
(
callbacks
),
loop
(
loop
),
ssl_ctx
(
ssl_ctx
),
ssl
(
nullptr
),
addrs
(
nullptr
),
next_addr
(
nullptr
),
cur_addr
(
nullptr
),
complete
(
0
),
settings_payloadlen
(
0
),
state
(
STATE_IDLE
),
...
...
@@ -556,9 +470,9 @@ struct HttpClient {
ev_timer_init
(
&
settings_timer
,
settings_timeout_cb
,
0.
,
10.
);
settings_timer
.
data
=
this
;
}
}
~
HttpClient
()
{
HttpClient
::
~
HttpClient
()
{
disconnect
();
if
(
addrs
)
{
...
...
@@ -566,11 +480,13 @@ struct HttpClient {
addrs
=
nullptr
;
next_addr
=
nullptr
;
}
}
}
bool
need_upgrade
()
const
{
return
config
.
upgrade
&&
scheme
==
"http"
;
}
bool
HttpClient
::
need_upgrade
()
const
{
return
config
.
upgrade
&&
scheme
==
"http"
;
}
int
resolve_host
(
const
std
::
string
&
host
,
uint16_t
port
)
{
int
HttpClient
::
resolve_host
(
const
std
::
string
&
host
,
uint16_t
port
)
{
int
rv
;
addrinfo
hints
;
this
->
host
=
host
;
...
...
@@ -591,9 +507,9 @@ struct HttpClient {
}
next_addr
=
addrs
;
return
0
;
}
}
int
initiate_connection
()
{
int
HttpClient
::
initiate_connection
()
{
int
rv
;
cur_addr
=
nullptr
;
...
...
@@ -670,9 +586,9 @@ struct HttpClient {
ev_timer_again
(
loop
,
&
wt
);
return
0
;
}
}
void
disconnect
()
{
void
HttpClient
::
disconnect
()
{
state
=
STATE_IDLE
;
ev_timer_stop
(
loop
,
&
settings_timer
);
...
...
@@ -699,9 +615,9 @@ struct HttpClient {
close
(
fd
);
fd
=
-
1
;
}
}
}
int
read_clear
()
{
int
HttpClient
::
read_clear
()
{
ev_timer_again
(
loop
,
&
rt
);
uint8_t
buf
[
8192
];
...
...
@@ -727,9 +643,9 @@ struct HttpClient {
}
return
0
;
}
}
int
write_clear
()
{
int
HttpClient
::
write_clear
()
{
ev_timer_again
(
loop
,
&
rt
);
for
(;;)
{
...
...
@@ -765,11 +681,11 @@ struct HttpClient {
ev_timer_stop
(
loop
,
&
wt
);
return
0
;
}
}
int
noop
()
{
return
0
;
}
int
HttpClient
::
noop
()
{
return
0
;
}
void
on_connect_fail
()
{
void
HttpClient
::
on_connect_fail
()
{
if
(
state
==
STATE_IDLE
)
{
std
::
cerr
<<
"[ERROR] Could not connect to the address "
<<
numeric_name
(
cur_addr
)
<<
std
::
endl
;
...
...
@@ -782,9 +698,9 @@ struct HttpClient {
<<
std
::
endl
;
}
}
}
}
int
connected
()
{
int
HttpClient
::
connected
()
{
if
(
!
util
::
check_socket_connected
(
fd
))
{
return
ERR_CONNECT_FAIL
;
}
...
...
@@ -826,17 +742,40 @@ struct HttpClient {
}
return
0
;
}
namespace
{
size_t
populate_settings
(
nghttp2_settings_entry
*
iv
)
{
size_t
niv
=
2
;
iv
[
0
].
settings_id
=
NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS
;
iv
[
0
].
value
=
100
;
iv
[
1
].
settings_id
=
NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE
;
if
(
config
.
window_bits
!=
-
1
)
{
iv
[
1
].
value
=
(
1
<<
config
.
window_bits
)
-
1
;
}
else
{
iv
[
1
].
value
=
NGHTTP2_INITIAL_WINDOW_SIZE
;
}
int
on_upgrade_connect
()
{
if
(
config
.
header_table_size
>=
0
)
{
iv
[
niv
].
settings_id
=
NGHTTP2_SETTINGS_HEADER_TABLE_SIZE
;
iv
[
niv
].
value
=
config
.
header_table_size
;
++
niv
;
}
return
niv
;
}
}
// namespace
int
HttpClient
::
on_upgrade_connect
()
{
ssize_t
rv
;
record_handshake_time
();
assert
(
!
reqvec
.
empty
());
nghttp2_settings_entry
iv
[
32
];
size_t
niv
=
populate_settings
(
iv
);
assert
(
sizeof
(
settings_payload
)
>=
8
*
niv
);
rv
=
nghttp2_pack_settings_payload
(
settings_payload
,
sizeof
(
settings_payload
),
iv
,
niv
);
rv
=
nghttp2_pack_settings_payload
(
settings_payload
,
sizeof
(
settings_payload
)
,
iv
,
niv
);
if
(
rv
<
0
)
{
return
-
1
;
}
...
...
@@ -877,9 +816,9 @@ struct HttpClient {
signal_write
();
return
0
;
}
}
int
on_upgrade_read
(
const
uint8_t
*
data
,
size_t
len
)
{
int
HttpClient
::
on_upgrade_read
(
const
uint8_t
*
data
,
size_t
len
)
{
int
rv
;
auto
nread
=
http_parser_execute
(
htp
.
get
(),
&
htp_hooks
,
...
...
@@ -933,12 +872,12 @@ struct HttpClient {
}
return
0
;
}
}
int
do_read
()
{
return
readfn
(
*
this
);
}
int
do_write
()
{
return
writefn
(
*
this
);
}
int
HttpClient
::
do_read
()
{
return
readfn
(
*
this
);
}
int
HttpClient
::
do_write
()
{
return
writefn
(
*
this
);
}
int
on_connect
()
{
int
HttpClient
::
on_connect
()
{
int
rv
;
if
(
ssl
)
{
...
...
@@ -988,8 +927,8 @@ struct HttpClient {
if
(
!
reqvec
[
0
]
->
data_prd
)
{
stream_user_data
=
reqvec
[
0
].
get
();
}
rv
=
nghttp2_session_upgrade
(
session
,
settings_payload
,
settings_payloadlen
,
stream_user_data
);
rv
=
nghttp2_session_upgrade
(
session
,
settings_payload
,
settings_payloadlen
,
stream_user_data
);
if
(
rv
!=
0
)
{
std
::
cerr
<<
"[ERROR] nghttp2_session_upgrade() returned error: "
<<
nghttp2_strerror
(
rv
)
<<
std
::
endl
;
...
...
@@ -1019,8 +958,8 @@ struct HttpClient {
nghttp2_priority_spec
pri_spec
;
int32_t
dep_stream_id
=
0
;
for
(
auto
stream_id
:
{
ANCHOR_ID_HIGH
,
ANCHOR_ID_MEDIUM
,
ANCHOR_ID_LOW
,
ANCHOR_ID_LOWEST
})
{
for
(
auto
stream_id
:
{
ANCHOR_ID_HIGH
,
ANCHOR_ID_MEDIUM
,
ANCHOR_ID_LOW
,
ANCHOR_ID_LOWEST
})
{
nghttp2_priority_spec_init
(
&
pri_spec
,
dep_stream_id
,
NGHTTP2_DEFAULT_WEIGHT
,
0
);
...
...
@@ -1083,9 +1022,9 @@ struct HttpClient {
signal_write
();
return
0
;
}
}
int
on_read
(
const
uint8_t
*
data
,
size_t
len
)
{
int
HttpClient
::
on_read
(
const
uint8_t
*
data
,
size_t
len
)
{
auto
rv
=
nghttp2_session_mem_recv
(
session
,
data
,
len
);
if
(
rv
<
0
)
{
std
::
cerr
<<
"[ERROR] nghttp2_session_mem_recv() returned error: "
...
...
@@ -1103,9 +1042,9 @@ struct HttpClient {
signal_write
();
return
0
;
}
}
int
on_write
()
{
int
HttpClient
::
on_write
()
{
auto
rv
=
nghttp2_session_send
(
session
);
if
(
rv
!=
0
)
{
std
::
cerr
<<
"[ERROR] nghttp2_session_send() returned error: "
...
...
@@ -1119,9 +1058,9 @@ struct HttpClient {
}
return
0
;
}
}
int
tls_handshake
()
{
int
HttpClient
::
tls_handshake
()
{
ev_timer_again
(
loop
,
&
rt
);
ERR_clear_error
();
...
...
@@ -1159,9 +1098,9 @@ struct HttpClient {
}
return
0
;
}
}
int
read_tls
()
{
int
HttpClient
::
read_tls
()
{
ev_timer_again
(
loop
,
&
rt
);
ERR_clear_error
();
...
...
@@ -1191,9 +1130,9 @@ struct HttpClient {
return
-
1
;
}
}
}
}
int
write_tls
()
{
int
HttpClient
::
write_tls
()
{
ev_timer_again
(
loop
,
&
rt
);
ERR_clear_error
();
...
...
@@ -1241,17 +1180,19 @@ struct HttpClient {
ev_timer_stop
(
loop
,
&
wt
);
return
0
;
}
}
void
HttpClient
::
signal_write
()
{
ev_io_start
(
loop
,
&
wev
);
}
void
signal_write
()
{
ev_io_start
(
loop
,
&
wev
);
}
bool
HttpClient
::
all_requests_processed
()
const
{
return
complete
==
reqvec
.
size
();
}
bool
all_requests_processed
()
const
{
return
complete
==
reqvec
.
size
();
}
void
update_hostport
()
{
void
HttpClient
::
update_hostport
()
{
if
(
reqvec
.
empty
())
{
return
;
}
scheme
=
util
::
get_uri_field
(
reqvec
[
0
]
->
uri
.
c_str
(),
reqvec
[
0
]
->
u
,
UF_SCHEMA
);
scheme
=
util
::
get_uri_field
(
reqvec
[
0
]
->
uri
.
c_str
(),
reqvec
[
0
]
->
u
,
UF_SCHEMA
);
std
::
stringstream
ss
;
if
(
reqvec
[
0
]
->
is_ipv6_literal_addr
())
{
ss
<<
"["
;
...
...
@@ -1266,12 +1207,14 @@ struct HttpClient {
ss
<<
":"
<<
reqvec
[
0
]
->
u
.
port
;
}
hostport
=
ss
.
str
();
}
bool
add_request
(
const
std
::
string
&
uri
,
const
nghttp2_data_provider
*
data_prd
,
int64_t
data_length
,
}
bool
HttpClient
::
add_request
(
const
std
::
string
&
uri
,
const
nghttp2_data_provider
*
data_prd
,
int64_t
data_length
,
const
nghttp2_priority_spec
&
pri_spec
,
std
::
shared_ptr
<
Dependency
>
dep
,
int
pri
=
0
,
int
level
=
0
)
{
std
::
shared_ptr
<
Dependency
>
dep
,
int
pri
,
int
level
)
{
http_parser_url
u
;
memset
(
&
u
,
0
,
sizeof
(
u
));
if
(
http_parser_parse_url
(
uri
.
c_str
(),
uri
.
size
(),
0
,
&
u
)
!=
0
)
{
...
...
@@ -1288,20 +1231,24 @@ struct HttpClient {
reqvec
.
push_back
(
util
::
make_unique
<
Request
>
(
uri
,
u
,
data_prd
,
data_length
,
pri_spec
,
std
::
move
(
dep
),
pri
,
level
));
return
true
;
}
}
void
record_handshake_time
()
{
stat
.
on_handshake_time
=
get_time
();
}
void
HttpClient
::
record_handshake_time
()
{
stat
.
on_handshake_time
=
get_time
();
}
void
record_started_time
()
{
void
HttpClient
::
record_started_time
()
{
stat
.
started_system_time
=
std
::
chrono
::
system_clock
::
now
();
stat
.
on_started_time
=
get_time
();
}
}
void
record_dns_complete_time
()
{
stat
.
on_dns_complete_time
=
get_time
();
}
void
HttpClient
::
record_dns_complete_time
()
{
stat
.
on_dns_complete_time
=
get_time
();
}
void
record_connect_time
()
{
stat
.
on_connect_time
=
get_time
();
}
void
HttpClient
::
record_connect_time
()
{
stat
.
on_connect_time
=
get_time
();
}
void
on_request
(
Request
*
req
)
{
void
HttpClient
::
on_request
(
Request
*
req
)
{
req
->
record_request_time
();
if
(
req
->
pri
==
0
&&
req
->
dep
)
{
...
...
@@ -1335,10 +1282,10 @@ struct HttpClient {
if
(
itr
==
std
::
end
(
req
->
dep
->
deps
))
{
req
->
dep
->
deps
.
push_back
(
std
::
vector
<
Request
*>
{
req
});
}
}
}
#ifdef HAVE_JANSSON
void
output_har
(
FILE
*
outfile
)
{
void
HttpClient
::
output_har
(
FILE
*
outfile
)
{
static
auto
PAGE_ID
=
"page_0"
;
auto
root
=
json_object
();
...
...
@@ -1504,110 +1451,8 @@ struct HttpClient {
json_dumpf
(
root
,
outfile
,
JSON_PRESERVE_ORDER
|
JSON_INDENT
(
2
));
json_decref
(
root
);
}
#endif // HAVE_JANSSON
};
}
// namespace
namespace
{
int
htp_msg_begincb
(
http_parser
*
htp
)
{
if
(
config
.
verbose
)
{
print_timer
();
std
::
cout
<<
" HTTP Upgrade response"
<<
std
::
endl
;
}
return
0
;
}
}
// namespace
namespace
{
int
htp_statuscb
(
http_parser
*
htp
,
const
char
*
at
,
size_t
length
)
{
auto
client
=
static_cast
<
HttpClient
*>
(
htp
->
data
);
client
->
upgrade_response_status_code
=
htp
->
status_code
;
return
0
;
}
}
// namespace
namespace
{
int
htp_msg_completecb
(
http_parser
*
htp
)
{
auto
client
=
static_cast
<
HttpClient
*>
(
htp
->
data
);
client
->
upgrade_response_complete
=
true
;
return
0
;
}
}
// namespace
namespace
{
http_parser_settings
htp_hooks
=
{
htp_msg_begincb
,
// http_cb on_message_begin;
nullptr
,
// http_data_cb on_url;
htp_statuscb
,
// http_data_cb on_status;
nullptr
,
// http_data_cb on_header_field;
nullptr
,
// http_data_cb on_header_value;
nullptr
,
// http_cb on_headers_complete;
nullptr
,
// http_data_cb on_body;
htp_msg_completecb
// http_cb on_message_complete;
};
}
// namespace
namespace
{
int
submit_request
(
HttpClient
*
client
,
const
Headers
&
headers
,
Request
*
req
)
{
auto
path
=
req
->
make_reqpath
();
auto
scheme
=
util
::
get_uri_field
(
req
->
uri
.
c_str
(),
req
->
u
,
UF_SCHEMA
);
auto
build_headers
=
Headers
{{
":method"
,
req
->
data_prd
?
"POST"
:
"GET"
},
{
":path"
,
path
},
{
":scheme"
,
scheme
},
{
":authority"
,
client
->
hostport
},
{
"accept"
,
"*/*"
},
{
"accept-encoding"
,
"gzip, deflate"
},
{
"user-agent"
,
"nghttp2/"
NGHTTP2_VERSION
}};
if
(
config
.
continuation
)
{
for
(
size_t
i
=
0
;
i
<
6
;
++
i
)
{
build_headers
.
emplace_back
(
"continuation-test-"
+
util
::
utos
(
i
+
1
),
std
::
string
(
4096
,
'-'
));
}
}
auto
num_initial_headers
=
build_headers
.
size
();
if
(
!
config
.
no_content_length
&&
req
->
data_prd
)
{
build_headers
.
emplace_back
(
"content-length"
,
util
::
utos
(
req
->
data_length
));
}
for
(
auto
&
kv
:
headers
)
{
size_t
i
;
for
(
i
=
0
;
i
<
num_initial_headers
;
++
i
)
{
if
(
kv
.
name
==
build_headers
[
i
].
name
)
{
build_headers
[
i
].
value
=
kv
.
value
;
break
;
}
}
if
(
i
<
num_initial_headers
)
{
continue
;
}
build_headers
.
emplace_back
(
kv
.
name
,
kv
.
value
,
kv
.
no_index
);
}
auto
nva
=
std
::
vector
<
nghttp2_nv
>
();
nva
.
reserve
(
build_headers
.
size
());
for
(
auto
&
kv
:
build_headers
)
{
nva
.
push_back
(
http2
::
make_nv
(
kv
.
name
,
kv
.
value
,
kv
.
no_index
));
}
auto
stream_id
=
nghttp2_submit_request
(
client
->
session
,
&
req
->
pri_spec
,
nva
.
data
(),
nva
.
size
(),
req
->
data_prd
,
req
);
if
(
stream_id
<
0
)
{
std
::
cerr
<<
"[ERROR] nghttp2_submit_request() returned error: "
<<
nghttp2_strerror
(
stream_id
)
<<
std
::
endl
;
return
-
1
;
}
req
->
stream_id
=
stream_id
;
client
->
on_request
(
req
);
req
->
req_nva
=
std
::
move
(
build_headers
);
return
0
;
}
}
// namespace
#endif // HAVE_JANSSON
namespace
{
void
update_html_parser
(
HttpClient
*
client
,
Request
*
req
,
const
uint8_t
*
data
,
...
...
@@ -1642,7 +1487,7 @@ void update_html_parser(HttpClient *client, Request *req, const uint8_t *data,
}
// namespace
namespace
{
HttpClient
*
get_
session
(
void
*
user_data
)
{
HttpClient
*
get_
client
(
void
*
user_data
)
{
return
static_cast
<
HttpClient
*>
(
user_data
);
}
}
// namespace
...
...
@@ -1651,7 +1496,7 @@ namespace {
int
on_data_chunk_recv_callback
(
nghttp2_session
*
session
,
uint8_t
flags
,
int32_t
stream_id
,
const
uint8_t
*
data
,
size_t
len
,
void
*
user_data
)
{
auto
client
=
get_
session
(
user_data
);
auto
client
=
get_
client
(
user_data
);
auto
req
=
static_cast
<
Request
*>
(
nghttp2_session_get_stream_user_data
(
session
,
stream_id
));
...
...
@@ -1709,17 +1554,6 @@ int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
}
}
// namespace
namespace
{
void
settings_timeout_cb
(
struct
ev_loop
*
loop
,
ev_timer
*
w
,
int
revents
)
{
auto
client
=
static_cast
<
HttpClient
*>
(
w
->
data
);
ev_timer_stop
(
loop
,
w
);
nghttp2_session_terminate_session
(
client
->
session
,
NGHTTP2_SETTINGS_TIMEOUT
);
client
->
signal_write
();
}
}
// namespace
namespace
{
ssize_t
select_padding_callback
(
nghttp2_session
*
session
,
const
nghttp2_frame
*
frame
,
size_t
max_payload
,
...
...
@@ -1783,7 +1617,7 @@ void check_response_header(nghttp2_session *session, Request *req) {
namespace
{
int
on_begin_headers_callback
(
nghttp2_session
*
session
,
const
nghttp2_frame
*
frame
,
void
*
user_data
)
{
auto
client
=
get_
session
(
user_data
);
auto
client
=
get_
client
(
user_data
);
switch
(
frame
->
hd
.
type
)
{
case
NGHTTP2_PUSH_PROMISE
:
{
auto
stream_id
=
frame
->
push_promise
.
promised_stream_id
;
...
...
@@ -1894,7 +1728,7 @@ int on_frame_recv_callback2(nghttp2_session *session,
verbose_on_frame_recv_callback
(
session
,
frame
,
user_data
);
}
auto
client
=
get_
session
(
user_data
);
auto
client
=
get_
client
(
user_data
);
switch
(
frame
->
hd
.
type
)
{
case
NGHTTP2_HEADERS
:
{
auto
req
=
static_cast
<
Request
*>
(
...
...
@@ -1984,7 +1818,7 @@ int on_frame_recv_callback2(nghttp2_session *session,
namespace
{
int
on_stream_close_callback
(
nghttp2_session
*
session
,
int32_t
stream_id
,
uint32_t
error_code
,
void
*
user_data
)
{
auto
client
=
get_
session
(
user_data
);
auto
client
=
get_
client
(
user_data
);
auto
req
=
static_cast
<
Request
*>
(
nghttp2_session_get_stream_user_data
(
session
,
stream_id
));
...
...
@@ -2057,37 +1891,6 @@ int client_select_next_proto_cb(SSL *ssl, unsigned char **out,
}
}
// namespace
namespace
{
void
readcb
(
struct
ev_loop
*
loop
,
ev_io
*
w
,
int
revents
)
{
auto
client
=
static_cast
<
HttpClient
*>
(
w
->
data
);
if
(
client
->
do_read
()
!=
0
)
{
client
->
disconnect
();
}
}
}
// namespace
namespace
{
void
writecb
(
struct
ev_loop
*
loop
,
ev_io
*
w
,
int
revents
)
{
auto
client
=
static_cast
<
HttpClient
*>
(
w
->
data
);
auto
rv
=
client
->
do_write
();
if
(
rv
==
HttpClient
::
ERR_CONNECT_FAIL
)
{
client
->
on_connect_fail
();
return
;
}
if
(
rv
!=
0
)
{
client
->
disconnect
();
}
}
}
// namespace
namespace
{
void
timeoutcb
(
struct
ev_loop
*
loop
,
ev_timer
*
w
,
int
revents
)
{
auto
client
=
static_cast
<
HttpClient
*>
(
w
->
data
);
std
::
cerr
<<
"[ERROR] Timeout"
<<
std
::
endl
;
client
->
disconnect
();
}
}
// namespace
namespace
{
int
communicate
(
const
std
::
string
&
scheme
,
const
std
::
string
&
host
,
uint16_t
port
,
...
...
src/nghttp.h
0 → 100644
View file @
1795d3ea
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2015 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP_H
#define NGHTTP_H
#include "nghttp2_config.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string>
#include <vector>
#include <set>
#include <chrono>
#include <openssl/ssl.h>
#include <ev.h>
#include <nghttp2/nghttp2.h>
#include "http-parser/http_parser.h"
#include "ringbuf.h"
#include "http2.h"
#include "nghttp2_gzip.h"
namespace
nghttp2
{
class
HtmlParser
;
struct
Config
{
Config
();
~
Config
();
Headers
headers
;
std
::
string
certfile
;
std
::
string
keyfile
;
std
::
string
datafile
;
std
::
string
harfile
;
nghttp2_option
*
http2_option
;
size_t
output_upper_thres
;
size_t
padding
;
ssize_t
peer_max_concurrent_streams
;
ssize_t
header_table_size
;
int32_t
weight
;
int
multiply
;
// milliseconds
ev_tstamp
timeout
;
int
window_bits
;
int
connection_window_bits
;
int
verbose
;
bool
null_out
;
bool
remote_name
;
bool
get_assets
;
bool
stat
;
bool
upgrade
;
bool
continuation
;
bool
no_content_length
;
bool
no_dep
;
bool
dep_idle
;
};
enum
StatStage
{
STAT_INITIAL
,
STAT_ON_REQUEST
,
STAT_ON_RESPONSE
,
STAT_ON_COMPLETE
};
struct
RequestStat
{
std
::
chrono
::
steady_clock
::
time_point
on_request_time
;
std
::
chrono
::
steady_clock
::
time_point
on_response_time
;
std
::
chrono
::
steady_clock
::
time_point
on_complete_time
;
StatStage
stage
;
RequestStat
()
:
stage
(
STAT_INITIAL
)
{}
};
struct
Request
;
struct
Dependency
{
std
::
vector
<
std
::
vector
<
Request
*>>
deps
;
};
struct
Request
{
// For pushed request, |uri| is empty and |u| is zero-cleared.
Request
(
const
std
::
string
&
uri
,
const
http_parser_url
&
u
,
const
nghttp2_data_provider
*
data_prd
,
int64_t
data_length
,
const
nghttp2_priority_spec
&
pri_spec
,
std
::
shared_ptr
<
Dependency
>
dep
,
int
pri
=
0
,
int
level
=
0
);
~
Request
();
void
init_inflater
();
void
init_html_parser
();
int
update_html_parser
(
const
uint8_t
*
data
,
size_t
len
,
int
fin
);
std
::
string
make_reqpath
()
const
;
int32_t
find_dep_stream_id
(
int
start
);
nghttp2_priority_spec
resolve_dep
(
int32_t
pri
);
bool
is_ipv6_literal_addr
()
const
;
bool
response_pseudo_header_allowed
(
int
token
)
const
;
bool
push_request_pseudo_header_allowed
(
int
token
)
const
;
Headers
::
value_type
*
get_res_header
(
int
token
);
Headers
::
value_type
*
get_req_header
(
int
token
);
void
record_request_time
();
void
record_response_time
();
void
record_complete_time
();
Headers
res_nva
;
Headers
req_nva
;
// URI without fragment
std
::
string
uri
;
http_parser_url
u
;
std
::
shared_ptr
<
Dependency
>
dep
;
nghttp2_priority_spec
pri_spec
;
RequestStat
stat
;
int64_t
data_length
;
int64_t
data_offset
;
// Number of bytes received from server
int64_t
response_len
;
nghttp2_gzip
*
inflater
;
HtmlParser
*
html_parser
;
const
nghttp2_data_provider
*
data_prd
;
int32_t
stream_id
;
int
status
;
// Recursion level: 0: first entity, 1: entity linked from first entity
int
level
;
// RequestPriority value defined in HtmlParser.h
int
pri
;
int
res_hdidx
[
http2
::
HD_MAXIDX
];
// used for incoming PUSH_PROMISE
int
req_hdidx
[
http2
::
HD_MAXIDX
];
bool
expect_final_response
;
};
struct
SessionStat
{
// The point in time when download was started.
std
::
chrono
::
system_clock
::
time_point
started_system_time
;
// The point of time when download was started.
std
::
chrono
::
steady_clock
::
time_point
on_started_time
;
// The point of time when DNS resolution was completed.
std
::
chrono
::
steady_clock
::
time_point
on_dns_complete_time
;
// The point of time when connection was established or SSL/TLS
// handshake was completed.
std
::
chrono
::
steady_clock
::
time_point
on_connect_time
;
// The point of time when HTTP/2 commnucation was started.
std
::
chrono
::
steady_clock
::
time_point
on_handshake_time
;
};
enum
client_state
{
STATE_IDLE
,
STATE_CONNECTED
};
struct
HttpClient
{
HttpClient
(
const
nghttp2_session_callbacks
*
callbacks
,
struct
ev_loop
*
loop
,
SSL_CTX
*
ssl_ctx
);
~
HttpClient
();
bool
need_upgrade
()
const
;
int
resolve_host
(
const
std
::
string
&
host
,
uint16_t
port
);
int
initiate_connection
();
void
disconnect
();
void
on_connect_fail
();
int
noop
();
int
read_clear
();
int
write_clear
();
int
connected
();
int
tls_handshake
();
int
read_tls
();
int
write_tls
();
int
do_read
();
int
do_write
();
int
on_upgrade_connect
();
int
on_upgrade_read
(
const
uint8_t
*
data
,
size_t
len
);
int
on_read
(
const
uint8_t
*
data
,
size_t
len
);
int
on_write
();
int
on_connect
();
void
on_request
(
Request
*
req
);
void
signal_write
();
bool
all_requests_processed
()
const
;
void
update_hostport
();
bool
add_request
(
const
std
::
string
&
uri
,
const
nghttp2_data_provider
*
data_prd
,
int64_t
data_length
,
const
nghttp2_priority_spec
&
pri_spec
,
std
::
shared_ptr
<
Dependency
>
dep
,
int
pri
=
0
,
int
level
=
0
);
void
record_handshake_time
();
void
record_started_time
();
void
record_dns_complete_time
();
void
record_connect_time
();
#ifdef HAVE_JANSSON
void
output_har
(
FILE
*
outfile
);
#endif // HAVE_JANSSON
std
::
vector
<
std
::
unique_ptr
<
Request
>>
reqvec
;
// Insert path already added in reqvec to prevent multiple request
// for 1 resource.
std
::
set
<
std
::
string
>
path_cache
;
std
::
string
scheme
;
std
::
string
host
;
std
::
string
hostport
;
// Used for parse the HTTP upgrade response from server
std
::
unique_ptr
<
http_parser
>
htp
;
SessionStat
stat
;
ev_io
wev
;
ev_io
rev
;
ev_timer
wt
;
ev_timer
rt
;
ev_timer
settings_timer
;
std
::
function
<
int
(
HttpClient
&
)
>
readfn
,
writefn
;
std
::
function
<
int
(
HttpClient
&
,
const
uint8_t
*
,
size_t
)
>
on_readfn
;
std
::
function
<
int
(
HttpClient
&
)
>
on_writefn
;
nghttp2_session
*
session
;
const
nghttp2_session_callbacks
*
callbacks
;
struct
ev_loop
*
loop
;
SSL_CTX
*
ssl_ctx
;
SSL
*
ssl
;
addrinfo
*
addrs
;
addrinfo
*
next_addr
;
addrinfo
*
cur_addr
;
// The number of completed requests, including failed ones.
size_t
complete
;
// The length of settings_payload
size_t
settings_payloadlen
;
client_state
state
;
// The HTTP status code of the response message of HTTP Upgrade.
unsigned
int
upgrade_response_status_code
;
int
fd
;
// true if the response message of HTTP Upgrade request is fully
// received. It is not relevant the upgrade succeeds, or not.
bool
upgrade_response_complete
;
RingBuf
<
65536
>
wb
;
// SETTINGS payload sent as token68 in HTTP Upgrade
uint8_t
settings_payload
[
128
];
enum
{
ERR_CONNECT_FAIL
=
-
100
};
};
}
// namespace nghttp2
#endif // NGHTTP_H
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