Commit dba2406a authored by Tatsuhiro Tsujikawa's avatar Tatsuhiro Tsujikawa

nghttp2_sesson_mem_recv: Process incoming data in streaming fashion

Now incoming data is processed in very small buffer (up to 8 bytes)
using state machine. GOAWAY debug data can get to 16K - 1, and we
don't have callback for it. Since we don't want to buffer that
amount of data just for debugging, we currently discard it.
This change also makes parse_error callback not function.
It probably be removed from API.
parent 83175590
......@@ -270,6 +270,25 @@ int nghttp2_frame_unpack_headers_without_nv(nghttp2_headers *frame,
return 0;
}
int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
const uint8_t *payload,
size_t payloadlen)
{
/* TODO Return error if header continuation is used for now */
if((frame->hd.flags & NGHTTP2_FLAG_END_HEADERS) == 0) {
return NGHTTP2_ERR_PROTO;
}
if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
assert(payloadlen == 4);
frame->pri = nghttp2_get_uint32(payload) & NGHTTP2_PRIORITY_MASK;
} else {
frame->pri = NGHTTP2_PRI_DEFAULT;
}
frame->nva = NULL;
frame->nvlen = 0;
return 0;
}
ssize_t nghttp2_frame_pack_priority(uint8_t **buf_ptr, size_t *buflen_ptr,
nghttp2_priority *frame)
{
......@@ -295,7 +314,13 @@ int nghttp2_frame_unpack_priority(nghttp2_priority *frame,
nghttp2_frame_unpack_frame_hd(&frame->hd, head);
frame->pri = nghttp2_get_uint32(payload) & NGHTTP2_PRIORITY_MASK;
return 0;
}
void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
const uint8_t *payload,
size_t payloadlen)
{
frame->pri = nghttp2_get_uint32(payload) & NGHTTP2_PRIORITY_MASK;
}
ssize_t nghttp2_frame_pack_rst_stream(uint8_t **buf_ptr, size_t *buflen_ptr,
......@@ -325,6 +350,13 @@ int nghttp2_frame_unpack_rst_stream(nghttp2_rst_stream *frame,
return 0;
}
void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
const uint8_t *payload,
size_t payloadlen)
{
frame->error_code = nghttp2_get_uint32(payload);
}
ssize_t nghttp2_frame_pack_settings(uint8_t **buf_ptr, size_t *buflen_ptr,
nghttp2_settings *frame)
{
......@@ -371,6 +403,29 @@ int nghttp2_frame_unpack_settings(nghttp2_settings *frame,
return 0;
}
int nghttp2_frame_unpack_settings_payload2(nghttp2_settings *frame,
nghttp2_settings_entry *iv,
size_t niv)
{
size_t payloadlen = niv * sizeof(nghttp2_settings_entry);
frame->iv = malloc(payloadlen);
if(frame->iv == NULL) {
return NGHTTP2_ERR_NOMEM;
}
memcpy(frame->iv, iv, payloadlen);
frame->niv = niv;
return 0;
}
void nghttp2_frame_unpack_settings_entry(nghttp2_settings_entry *iv,
const uint8_t *payload)
{
iv->settings_id = nghttp2_get_uint32(&payload[0]) &
NGHTTP2_SETTINGS_ID_MASK;
iv->value = nghttp2_get_uint32(&payload[4]);
}
int nghttp2_frame_unpack_settings_payload(nghttp2_settings_entry **iv_ptr,
size_t *niv_ptr,
const uint8_t *payload,
......@@ -384,9 +439,7 @@ int nghttp2_frame_unpack_settings_payload(nghttp2_settings_entry **iv_ptr,
}
for(i = 0; i < *niv_ptr; ++i) {
size_t off = i*8;
(*iv_ptr)[i].settings_id = nghttp2_get_uint32(&payload[off]) &
NGHTTP2_SETTINGS_ID_MASK;
(*iv_ptr)[i].value = nghttp2_get_uint32(&payload[4+off]);
nghttp2_frame_unpack_settings_entry(&(*iv_ptr)[i], &payload[off]);
}
return 0;
}
......@@ -440,6 +493,21 @@ int nghttp2_frame_unpack_push_promise_without_nv(nghttp2_push_promise *frame,
return 0;
}
int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
const uint8_t *payload,
size_t payloadlen)
{
/* TODO Return error if header continuation is used for now */
if((frame->hd.flags & NGHTTP2_FLAG_END_PUSH_PROMISE) == 0) {
return NGHTTP2_ERR_PROTO;
}
frame->promised_stream_id = nghttp2_get_uint32(payload) &
NGHTTP2_STREAM_ID_MASK;
frame->nva = NULL;
frame->nvlen = 0;
return 0;
}
ssize_t nghttp2_frame_pack_ping(uint8_t **buf_ptr, size_t *buflen_ptr,
nghttp2_ping *frame)
{
......@@ -467,6 +535,12 @@ int nghttp2_frame_unpack_ping(nghttp2_ping *frame,
return 0;
}
void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame,
const uint8_t *payload,
size_t payloadlen)
{
memcpy(frame->opaque_data, payload, sizeof(frame->opaque_data));
}
ssize_t nghttp2_frame_pack_goaway(uint8_t **buf_ptr, size_t *buflen_ptr,
nghttp2_goaway *frame)
......@@ -508,6 +582,17 @@ int nghttp2_frame_unpack_goaway(nghttp2_goaway *frame,
return 0;
}
void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
const uint8_t *payload,
size_t payloadlen)
{
frame->last_stream_id = nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK;
frame->error_code = nghttp2_get_uint32(payload+4);
/* TODO Currently we don't buffer debug data */
frame->opaque_data = NULL;
frame->opaque_data_len = 0;
}
ssize_t nghttp2_frame_pack_window_update(uint8_t **buf_ptr, size_t *buflen_ptr,
nghttp2_window_update *frame)
{
......@@ -537,6 +622,14 @@ int nghttp2_frame_unpack_window_update(nghttp2_window_update *frame,
return 0;
}
void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame,
const uint8_t *payload,
size_t payloadlen)
{
frame->window_size_increment = nghttp2_get_uint32(payload) &
NGHTTP2_WINDOW_SIZE_INCREMENT_MASK;
}
nghttp2_settings_entry* nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv,
size_t niv)
{
......
......@@ -161,6 +161,10 @@ int nghttp2_frame_unpack_headers_without_nv(nghttp2_headers *frame,
const uint8_t *payload,
size_t payloadlen);
int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
const uint8_t *payload,
size_t payloadlen);
/*
* Packs PRIORITY frame |frame| in wire format and store it in
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr|
......@@ -189,6 +193,10 @@ int nghttp2_frame_unpack_priority(nghttp2_priority *frame,
const uint8_t *head, size_t headlen,
const uint8_t *payload, size_t payloadlen);
void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
const uint8_t *payload,
size_t payloadlen);
/*
* Packs RST_STREAM frame |frame| in wire frame format and store it in
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr|
......@@ -218,6 +226,10 @@ int nghttp2_frame_unpack_rst_stream(nghttp2_rst_stream *frame,
const uint8_t *head, size_t headlen,
const uint8_t *payload, size_t payloadlen);
void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
const uint8_t *payload,
size_t payloadlen);
/*
* Packs SETTINGS frame |frame| in wire format and store it in
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr|
......@@ -259,6 +271,13 @@ int nghttp2_frame_unpack_settings(nghttp2_settings *frame,
const uint8_t *payload, size_t payloadlen);
void nghttp2_frame_unpack_settings_entry(nghttp2_settings_entry *iv,
const uint8_t *payload);
int nghttp2_frame_unpack_settings_payload2(nghttp2_settings *frame,
nghttp2_settings_entry *iv,
size_t niv);
/*
* Unpacks SETTINGS payload into |*iv_ptr|. The number of entries are
* assigned to the |*niv_ptr|. This function allocates enough memory
......@@ -347,6 +366,10 @@ int nghttp2_frame_unpack_push_promise_without_nv(nghttp2_push_promise *frame,
const uint8_t *payload,
size_t payloadlen);
int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
const uint8_t *payload,
size_t payloadlen);
/*
* Packs PING frame |frame| in wire format and store it in
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr|
......@@ -375,6 +398,10 @@ int nghttp2_frame_unpack_ping(nghttp2_ping *frame,
const uint8_t *head, size_t headlen,
const uint8_t *payload, size_t payloadlen);
void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame,
const uint8_t *payload,
size_t payloadlen);
/*
* Packs GOAWAY frame |frame | in wire format and store it in
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr|
......@@ -405,6 +432,10 @@ int nghttp2_frame_unpack_goaway(nghttp2_goaway *frame,
const uint8_t *head, size_t headlen,
const uint8_t *payload, size_t payloadlen);
void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
const uint8_t *payload,
size_t payloadlen);
/*
* Packs WINDOW_UPDATE frame |frame| in wire frame format and store it
* in |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr|
......@@ -434,6 +465,10 @@ int nghttp2_frame_unpack_window_update(nghttp2_window_update *frame,
const uint8_t *payload,
size_t payloadlen);
void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame,
const uint8_t *payload,
size_t payloadlen);
/*
* Initializes HEADERS frame |frame| with given values. |frame| takes
* ownership of |nva|, so caller must not free it. If |stream_id| is
......
......@@ -45,7 +45,9 @@ typedef int (*nghttp2_compar)(const void *lhs, const void *rhs);
inclusive. */
typedef enum {
NGHTTP2_ERR_CREDENTIAL_PENDING = -101,
NGHTTP2_ERR_BUFFER_ERROR = - 102
NGHTTP2_ERR_BUFFER_ERROR = -102,
NGHTTP2_ERR_IGN_HEADER_BLOCK = -103,
NGHTTP2_ERR_IGN_PAYLOAD = -104,
} nghttp2_internal_error;
#endif /* NGHTTP2_INT_H */
This diff is collapsed.
......@@ -37,6 +37,7 @@
#include "nghttp2_stream.h"
#include "nghttp2_buffer.h"
#include "nghttp2_outbound_item.h"
#include "nghttp2_int.h"
/*
* Option flags.
......@@ -72,39 +73,36 @@ typedef struct {
/* Internal state when receiving incoming frame */
typedef enum {
/* Receiving frame header */
NGHTTP2_RECV_HEAD,
/* Receiving frame payload (comes after length field) */
NGHTTP2_RECV_PAYLOAD,
/* Receiving frame payload, but the received bytes are discarded. */
NGHTTP2_RECV_PAYLOAD_IGN
NGHTTP2_IB_READ_HEAD,
NGHTTP2_IB_READ_NBYTE,
NGHTTP2_IB_READ_HEADER_BLOCK,
NGHTTP2_IB_IGN_HEADER_BLOCK,
NGHTTP2_IB_IGN_PAYLOAD,
NGHTTP2_IB_FRAME_SIZE_ERROR,
NGHTTP2_IB_READ_SETTINGS,
NGHTTP2_IB_READ_GOAWAY_DEBUG,
NGHTTP2_IB_READ_DATA,
NGHTTP2_IB_IGN_DATA
} nghttp2_inbound_state;
typedef struct {
nghttp2_frame frame;
/* Payload for non-DATA frames. */
uint8_t *buf;
/* How many bytes are filled in headbuf */
size_t headbufoff;
/* Capacity of buf */
size_t bufmax;
/* For frames without name/value header block, this is how many
bytes are going to filled in buf. For frames with the block, buf
only contains bytes that come before ther block, but this value
includes the length of the block. buflen <= bufmax must be
fulfilled. */
size_t buflen;
/* length in Length field */
size_t payloadlen;
/* How many bytes are received for this frame. off <= payloadlen
must be fulfilled. */
size_t off;
/* How many bytes are decompressed inside |buf|. This is used for
header decompression. */
size_t inflate_offset;
/* The received SETTINGS entry. The protocol says that we only cares
about the defined settings ID. If unknown ID is received, it is
subject to connection error */
nghttp2_settings_entry iv[5];
/* The number of entry filled in |iv| */
size_t niv;
/* How many bytes we still need to receive in the |buf| */
size_t left;
/* How many bytes we still need to receive for current frame */
size_t payloadleft;
nghttp2_inbound_state state;
/* Error code */
/* TODO, remove this. Error code */
int error_code;
uint8_t headbuf[NGHTTP2_FRAME_HEAD_LENGTH];
uint8_t buf[8];
/* How many bytes have been written to |buf| */
uint8_t buflen;
} nghttp2_inbound_frame;
typedef enum {
......@@ -131,9 +129,6 @@ struct nghttp2_session {
/* Sequence number of outbound frame to maintain the order of
enqueue if priority is equal. */
int64_t next_seq;
/* Buffer used to store inflated name/value pairs in wire format
temporarily on pack/unpack. */
uint8_t *nvbuf;
void *user_data;
/* In-flight SETTINGS values. NULL does not necessarily mean there
is no in-flight SETTINGS. */
......@@ -358,6 +353,15 @@ int nghttp2_session_close_stream_if_shut_rdwr(nghttp2_session *session,
nghttp2_stream *stream);
int nghttp2_session_end_request_headers_received(nghttp2_session *session,
nghttp2_frame *frame);
int nghttp2_session_end_response_headers_received(nghttp2_session *session,
nghttp2_frame *frame);
int nghttp2_session_end_headers_received(nghttp2_session *session,
nghttp2_frame *frame);
int nghttp2_session_on_request_headers_received(nghttp2_session *session,
nghttp2_frame *frame);
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment