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
0b143196
Commit
0b143196
authored
Jan 18, 2014
by
Tatsuhiro Tsujikawa
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
doc, examples: Update tutorial and examples
parent
e960c56a
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
184 additions
and
43 deletions
+184
-43
doc/tutorial-client.rst
doc/tutorial-client.rst
+52
-4
doc/tutorial-server.rst
doc/tutorial-server.rst
+42
-19
examples/libevent-client.c
examples/libevent-client.c
+59
-8
examples/libevent-server.c
examples/libevent-server.c
+31
-12
No files found.
doc/tutorial-client.rst
View file @
0b143196
...
...
@@ -163,11 +163,13 @@ finished successfully. We first initialize nghttp2 session object in
callbacks.on_frame_recv_callback = on_frame_recv_callback;
callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback;
callbacks.on_stream_close_callback = on_stream_close_callback;
callbacks.on_header_callback = on_header_callback;
callbacks.on_end_headers_callback = on_end_headers_callback;
nghttp2_session_client_new(&session_data->session, &callbacks, session_data);
}
Since we are creating client, we use `nghttp2_session_client_new()` to
initialize nghttp2 session object. We setup
5
callbacks for the
initialize nghttp2 session object. We setup
7
callbacks for the
nghttp2 session. We'll explain these callbacks later.
The `delete_http2_session_data()` destroys ``session_data`` and frees
...
...
@@ -395,9 +397,8 @@ received from the remote peer::
case NGHTTP2_HEADERS:
if(frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
session_data->stream_data->stream_id == frame->hd.stream_id) {
/* Print response headers for the initiated request. */
fprintf(stderr, "Response headers:\n");
print_headers(stderr, frame->headers.nva, frame->headers.nvlen);
fprintf(stderr, "Response headers for stream ID=%d:\n",
frame->hd.stream_id);
}
break;
}
...
...
@@ -409,6 +410,53 @@ HEADERS. We check te frame type and its category (it should be
:macro:`NGHTTP2_HCAT_RESPONSE` for HTTP response HEADERS). Also check
its stream ID.
Each request header name/value pair is emitted via
``on_header_callback`` function::
static int on_header_callback(nghttp2_session *session,
const nghttp2_frame *frame,
const uint8_t *name, size_t namelen,
const uint8_t *value, size_t valuelen,
void *user_data)
{
http2_session_data *session_data = (http2_session_data*)user_data;
switch(frame->hd.type) {
case NGHTTP2_HEADERS:
if(frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
session_data->stream_data->stream_id == frame->hd.stream_id) {
/* Print response headers for the initiated request. */
print_header(stderr, name, namelen, value, valuelen);
break;
}
}
return 0;
}
In this turotial, we just print the name/value pair.
After all name/value pairs are emitted for a frame,
``on_end_headers_callback`` function is called::
static int on_end_headers_callback(nghttp2_session *session,
const nghttp2_frame *frame,
nghttp2_error_code error_code,
void *user_data)
{
http2_session_data *session_data = (http2_session_data*)user_data;
switch(frame->hd.type) {
case NGHTTP2_HEADERS:
if(frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
session_data->stream_data->stream_id == frame->hd.stream_id) {
fprintf(stderr, "All headers received with error_code=%d\n", error_code);
}
break;
}
return 0;
}
This callback may be called prematurely because of errors (e.g.,
header decompression failure) which is indicated by ``error_code``.
The ``on_data_chunk_recv_callback()`` function is invoked when a chunk
of data is received from the remote peer::
...
...
doc/tutorial-server.rst
View file @
0b143196
...
...
@@ -243,11 +243,12 @@ We initialize nghttp2 session object which is done in
callbacks.on_frame_recv_callback = on_frame_recv_callback;
callbacks.on_request_recv_callback = on_request_recv_callback;
callbacks.on_stream_close_callback = on_stream_close_callback;
callbacks.on_header_callback = on_header_callback;
nghttp2_session_server_new(&session_data->session, &callbacks, session_data);
}
Since we are creating server, nghttp2 session object is created using
`nghttp2_session_server_new()` function. We registers
4
callbacks to
`nghttp2_session_server_new()` function. We registers
5
callbacks to
nghttp2 session object. We'll talk about these callbacks later.
After initialization of nghttp2 session object, we are going to send
...
...
@@ -421,8 +422,6 @@ received from the remote peer::
{
http2_session_data *session_data = (http2_session_data*)user_data;
http2_stream_data *stream_data;
size_t i;
const char PATH[] = ":path";
switch(frame->hd.type) {
case NGHTTP2_HEADERS:
if(frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
...
...
@@ -431,16 +430,6 @@ received from the remote peer::
stream_data = create_http2_stream_data(session_data, frame->hd.stream_id);
nghttp2_session_set_stream_user_data(session, frame->hd.stream_id,
stream_data);
for(i = 0; i < frame->headers.nvlen; ++i) {
nghttp2_nv *nv = &frame->headers.nva[i];
if(nv->namelen == sizeof(PATH) - 1 &&
memcmp(PATH, nv->name, nv->namelen) == 0) {
size_t j;
for(j = 0; j < nv->valuelen && nv->value[j] != '?'; ++j);
stream_data->request_path = percent_decode(nv->value, j);
break;
}
}
break;
default:
break;
...
...
@@ -457,13 +446,47 @@ in nghttp2 session object using `nghttp2_set_stream_user_data()` in
order to get the object without searching through doubly linked list.
In this example server, we want to serve files relative to the current
working directory the program was invoked. We search ``:path`` header
field in request headers and keep the requested path in
``http2_stream_data`` object. In this example program, we ignore
``:method`` header field and always treat the request as GET request.
working directory the program was invoked. Each header name/value pair
is emitted via ``on_header_callback`` function, which is called after
``on_frame_recv_callback()``::
static int on_header_callback(nghttp2_session *session,
const nghttp2_frame *frame,
const uint8_t *name, size_t namelen,
const uint8_t *value, size_t valuelen,
void *user_data)
{
http2_stream_data *stream_data;
const char PATH[] = ":path";
switch(frame->hd.type) {
case NGHTTP2_HEADERS:
if(frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
break;
}
stream_data = nghttp2_session_get_stream_user_data(session,
frame->hd.stream_id);
if(stream_data->request_path) {
break;
}
if(namelen == sizeof(PATH) - 1 && memcmp(PATH, name, namelen) == 0) {
size_t j;
for(j = 0; j < valuelen && value[j] != '?'; ++j);
stream_data->request_path = percent_decode(value, j);
}
break;
}
return 0;
}
We search ``:path`` header field in request headers and keep the
requested path in ``http2_stream_data`` object. In this example
program, we ignore ``:method`` header field and always treat the
request as GET request.
It is ok for the server to start sending response in this callback. In
this example, we defer it to ``on_request_recv_callback()`` function.
It is ok for the server to start sending response in this callback (or
in `nghttp2_on_end_headers_callback()`, which is not used in this
tutorial). In this example, we defer it to
``on_request_recv_callback()`` function.
The ``on_request_recv_callback()`` function is invoked when all HTTP
request, including entity body, was received::
...
...
examples/libevent-client.c
View file @
0b143196
...
...
@@ -151,6 +151,16 @@ static void delete_http2_session_data(http2_session_data *session_data)
free
(
session_data
);
}
static
void
print_header
(
FILE
*
f
,
const
uint8_t
*
name
,
size_t
namelen
,
const
uint8_t
*
value
,
size_t
valuelen
)
{
fwrite
(
name
,
namelen
,
1
,
f
);
fprintf
(
f
,
": "
);
fwrite
(
value
,
valuelen
,
1
,
f
);
fprintf
(
f
,
"
\n
"
);
}
/* Print HTTP headers to |f|. Please note that this function does not
take into account that header name and value are sequence of
octets, therefore they may contain non-printable characters. */
...
...
@@ -158,12 +168,11 @@ static void print_headers(FILE *f, nghttp2_nv *nva, size_t nvlen)
{
size_t
i
;
for
(
i
=
0
;
i
<
nvlen
;
++
i
)
{
fwrite
(
nva
[
i
].
name
,
nva
[
i
].
namelen
,
1
,
stderr
);
fprintf
(
stderr
,
": "
);
fwrite
(
nva
[
i
].
value
,
nva
[
i
].
valuelen
,
1
,
stderr
);
fprintf
(
stderr
,
"
\n
"
);
print_header
(
f
,
nva
[
i
].
name
,
nva
[
i
].
namelen
,
nva
[
i
].
value
,
nva
[
i
].
valuelen
);
}
fprintf
(
stderr
,
"
\n
"
);
fprintf
(
f
,
"
\n
"
);
}
/* nghttp2_send_callback. Here we transmit the |data|, |length| bytes,
...
...
@@ -201,6 +210,47 @@ static int before_frame_send_callback
return
0
;
}
/* nghttp2_on_header_callback: Called when nghttp2 library emits
single header name/value pair. */
static
int
on_header_callback
(
nghttp2_session
*
session
,
const
nghttp2_frame
*
frame
,
const
uint8_t
*
name
,
size_t
namelen
,
const
uint8_t
*
value
,
size_t
valuelen
,
void
*
user_data
)
{
http2_session_data
*
session_data
=
(
http2_session_data
*
)
user_data
;
switch
(
frame
->
hd
.
type
)
{
case
NGHTTP2_HEADERS
:
if
(
frame
->
headers
.
cat
==
NGHTTP2_HCAT_RESPONSE
&&
session_data
->
stream_data
->
stream_id
==
frame
->
hd
.
stream_id
)
{
/* Print response headers for the initiated request. */
print_header
(
stderr
,
name
,
namelen
,
value
,
valuelen
);
break
;
}
}
return
0
;
}
/* nghttp2_on_end_headers_callback: Called when nghttp2 library emits
all header name/value pairs, or may be called prematurely because
of errors which is indicated by |error_code|. */
static
int
on_end_headers_callback
(
nghttp2_session
*
session
,
const
nghttp2_frame
*
frame
,
nghttp2_error_code
error_code
,
void
*
user_data
)
{
http2_session_data
*
session_data
=
(
http2_session_data
*
)
user_data
;
switch
(
frame
->
hd
.
type
)
{
case
NGHTTP2_HEADERS
:
if
(
frame
->
headers
.
cat
==
NGHTTP2_HCAT_RESPONSE
&&
session_data
->
stream_data
->
stream_id
==
frame
->
hd
.
stream_id
)
{
fprintf
(
stderr
,
"All headers received with error_code=%d
\n
"
,
error_code
);
}
break
;
}
return
0
;
}
/* nghttp2_on_frame_recv_callback: Called when nghttp2 library
received a frame from the remote peer. */
static
int
on_frame_recv_callback
(
nghttp2_session
*
session
,
...
...
@@ -211,9 +261,8 @@ static int on_frame_recv_callback(nghttp2_session *session,
case
NGHTTP2_HEADERS
:
if
(
frame
->
headers
.
cat
==
NGHTTP2_HCAT_RESPONSE
&&
session_data
->
stream_data
->
stream_id
==
frame
->
hd
.
stream_id
)
{
/* Print response headers for the initiated request. */
fprintf
(
stderr
,
"Response headers:
\n
"
);
print_headers
(
stderr
,
frame
->
headers
.
nva
,
frame
->
headers
.
nvlen
);
fprintf
(
stderr
,
"Response headers for stream ID=%d:
\n
"
,
frame
->
hd
.
stream_id
);
}
break
;
}
...
...
@@ -311,6 +360,8 @@ static void initialize_nghttp2_session(http2_session_data *session_data)
callbacks
.
on_frame_recv_callback
=
on_frame_recv_callback
;
callbacks
.
on_data_chunk_recv_callback
=
on_data_chunk_recv_callback
;
callbacks
.
on_stream_close_callback
=
on_stream_close_callback
;
callbacks
.
on_header_callback
=
on_header_callback
;
callbacks
.
on_end_headers_callback
=
on_end_headers_callback
;
nghttp2_session_client_new
(
&
session_data
->
session
,
&
callbacks
,
session_data
);
}
...
...
examples/libevent-server.c
View file @
0b143196
...
...
@@ -325,13 +325,41 @@ static char* percent_decode(const uint8_t *value, size_t valuelen)
return
res
;
}
/* nghttp2_on_header_callback: Called when nghttp2 library emits
single header name/value pair. */
static
int
on_header_callback
(
nghttp2_session
*
session
,
const
nghttp2_frame
*
frame
,
const
uint8_t
*
name
,
size_t
namelen
,
const
uint8_t
*
value
,
size_t
valuelen
,
void
*
user_data
)
{
http2_stream_data
*
stream_data
;
const
char
PATH
[]
=
":path"
;
switch
(
frame
->
hd
.
type
)
{
case
NGHTTP2_HEADERS
:
if
(
frame
->
headers
.
cat
!=
NGHTTP2_HCAT_REQUEST
)
{
break
;
}
stream_data
=
nghttp2_session_get_stream_user_data
(
session
,
frame
->
hd
.
stream_id
);
if
(
stream_data
->
request_path
)
{
break
;
}
if
(
namelen
==
sizeof
(
PATH
)
-
1
&&
memcmp
(
PATH
,
name
,
namelen
)
==
0
)
{
size_t
j
;
for
(
j
=
0
;
j
<
valuelen
&&
value
[
j
]
!=
'?'
;
++
j
);
stream_data
->
request_path
=
percent_decode
(
value
,
j
);
}
break
;
}
return
0
;
}
static
int
on_frame_recv_callback
(
nghttp2_session
*
session
,
const
nghttp2_frame
*
frame
,
void
*
user_data
)
{
http2_session_data
*
session_data
=
(
http2_session_data
*
)
user_data
;
http2_stream_data
*
stream_data
;
size_t
i
;
const
char
PATH
[]
=
":path"
;
switch
(
frame
->
hd
.
type
)
{
case
NGHTTP2_HEADERS
:
if
(
frame
->
headers
.
cat
!=
NGHTTP2_HCAT_REQUEST
)
{
...
...
@@ -340,16 +368,6 @@ static int on_frame_recv_callback(nghttp2_session *session,
stream_data
=
create_http2_stream_data
(
session_data
,
frame
->
hd
.
stream_id
);
nghttp2_session_set_stream_user_data
(
session
,
frame
->
hd
.
stream_id
,
stream_data
);
for
(
i
=
0
;
i
<
frame
->
headers
.
nvlen
;
++
i
)
{
nghttp2_nv
*
nv
=
&
frame
->
headers
.
nva
[
i
];
if
(
nv
->
namelen
==
sizeof
(
PATH
)
-
1
&&
memcmp
(
PATH
,
nv
->
name
,
nv
->
namelen
)
==
0
)
{
size_t
j
;
for
(
j
=
0
;
j
<
nv
->
valuelen
&&
nv
->
value
[
j
]
!=
'?'
;
++
j
);
stream_data
->
request_path
=
percent_decode
(
nv
->
value
,
j
);
break
;
}
}
break
;
default:
break
;
...
...
@@ -503,6 +521,7 @@ static void initialize_nghttp2_session(http2_session_data *session_data)
callbacks
.
on_frame_recv_callback
=
on_frame_recv_callback
;
callbacks
.
on_request_recv_callback
=
on_request_recv_callback
;
callbacks
.
on_stream_close_callback
=
on_stream_close_callback
;
callbacks
.
on_header_callback
=
on_header_callback
;
nghttp2_session_server_new
(
&
session_data
->
session
,
&
callbacks
,
session_data
);
}
...
...
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