You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by bc...@apache.org on 2015/08/25 22:21:12 UTC
[1/2] trafficserver git commit: TS-3752: Problem with larger headers
and HTTP/2
Repository: trafficserver
Updated Branches:
refs/heads/6.0.x ed8e7a4b3 -> a248e11c0
TS-3752: Problem with larger headers and HTTP/2
(cherry picked from commit 00ce2f1113baa9485262695a66ee67a08fc5d121)
Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo
Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/8013e761
Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/8013e761
Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/8013e761
Branch: refs/heads/6.0.x
Commit: 8013e761122bd9e86cd2e097cb7c0c224d6fb895
Parents: ed8e7a4
Author: Masaori Koshiba <mk...@yahoo-corp.jp>
Authored: Fri Aug 14 15:37:38 2015 -0700
Committer: Bryan Call <bc...@apache.org>
Committed: Tue Aug 25 13:19:45 2015 -0700
----------------------------------------------------------------------
proxy/http2/HPACK.cc | 14 +-
proxy/http2/HTTP2.cc | 71 ++++-----
proxy/http2/HTTP2.h | 23 ++-
proxy/http2/Http2ClientSession.cc | 24 ++-
proxy/http2/Http2ConnectionState.cc | 264 ++++++++++++++++---------------
proxy/http2/Http2ConnectionState.h | 63 +++++---
6 files changed, 244 insertions(+), 215 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/8013e761/proxy/http2/HPACK.cc
----------------------------------------------------------------------
diff --git a/proxy/http2/HPACK.cc b/proxy/http2/HPACK.cc
index b37eef6..d65a6b1 100644
--- a/proxy/http2/HPACK.cc
+++ b/proxy/http2/HPACK.cc
@@ -43,8 +43,6 @@ const unsigned HPACK_LEN_STATUS = countof(":status") - 1;
// Section 6.2), plus 32.
const static unsigned ADDITIONAL_OCTETS = 32;
-const static uint32_t HEADER_FIELD_LIMIT_LENGTH = 4096;
-
typedef enum {
TS_HPACK_STATIC_TABLE_0 = 0,
TS_HPACK_STATIC_TABLE_AUTHORITY,
@@ -241,8 +239,10 @@ Http2DynamicTable::add_header_field(const MIMEField *field)
uint32_t header_size = ADDITIONAL_OCTETS + name_len + value_len;
if (header_size > _settings_dynamic_table_size) {
- // 5.3. It is not an error to attempt to add an entry that is larger than the maximum size; an
- // attempt to add an entry larger than the entire table causes the table to be emptied of all existing entries.
+ // 5.3. It is not an error to attempt to add an entry that is larger than
+ // the maximum size; an
+ // attempt to add an entry larger than the entire table causes the table to
+ // be emptied of all existing entries.
_headers.clear();
_mhdr->fields_clear();
} else {
@@ -538,7 +538,7 @@ decode_string(Arena &arena, char **str, uint32_t &str_length, const uint8_t *buf
return HPACK_ERROR_COMPRESSION_ERROR;
p += len;
- if (encoded_string_len > HEADER_FIELD_LIMIT_LENGTH || (p + encoded_string_len) > buf_end) {
+ if ((p + encoded_string_len) > buf_end) {
return HPACK_ERROR_COMPRESSION_ERROR;
}
@@ -603,7 +603,8 @@ decode_literal_header_field(MIMEFieldWrapper &header, const uint8_t *buf_start,
HpackFieldType ftype = hpack_parse_field_type(*p);
if (ftype == HPACK_FIELD_INDEXED_LITERAL) {
- // 7.2.1. index extraction based on Literal Header Field with Incremental Indexing
+ // 7.2.1. index extraction based on Literal Header Field with Incremental
+ // Indexing
len = decode_integer(index, p, buf_end, 6);
isIncremental = true;
} else if (ftype == HPACK_FIELD_NEVERINDEX_LITERAL) {
@@ -655,7 +656,6 @@ decode_literal_header_field(MIMEFieldWrapper &header, const uint8_t *buf_start,
p += len;
header.value_set(value_str, value_str_len);
-
// Incremental Indexing adds header to header table as new entry
if (isIncremental) {
dynamic_table.add_header_field(header.field_get());
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/8013e761/proxy/http2/HTTP2.cc
----------------------------------------------------------------------
diff --git a/proxy/http2/HTTP2.cc b/proxy/http2/HTTP2.cc
index 3a84a59..d77242c 100644
--- a/proxy/http2/HTTP2.cc
+++ b/proxy/http2/HTTP2.cc
@@ -111,7 +111,8 @@ http2_are_frame_flags_valid(uint8_t ftype, uint8_t fflags)
HTTP2_FLAGS_WINDOW_UPDATE_MASK, HTTP2_FLAGS_CONTINUATION_MASK,
};
- // The frame flags are valid for this frame if nothing outside the defined bits is set.
+ // The frame flags are valid for this frame if nothing outside the defined
+ // bits is set.
return (fflags & ~mask[ftype]) == 0;
}
@@ -325,7 +326,6 @@ http2_parse_headers_parameter(IOVec iov, Http2HeadersParameter ¶ms)
return true;
}
-
// 6.3. PRIORITY
//
// 0 1 2 3
@@ -401,7 +401,6 @@ http2_parse_settings_parameter(IOVec iov, Http2SettingsParameter ¶m)
return true;
}
-
// 6.8. GOAWAY
//
// 0 1 2 3
@@ -429,7 +428,6 @@ http2_parse_goaway(IOVec iov, Http2Goaway &goaway)
return true;
}
-
// 6.9. WINDOW_UPDATE
//
// 0 1 2 3
@@ -584,8 +582,10 @@ http2_write_header_fragment(HTTPHdr *in, MIMEFieldIter &field_iter, uint8_t *out
ink_assert(http_hdr_type_get(in->m_http) != HTTP_TYPE_UNKNOWN);
ink_assert(in);
- // TODO Get a index value from the tables for the header field, and then choose a representation type.
- // TODO Each indexing types per field should be passed by a caller, HTTP/2 implementation.
+ // TODO Get a index value from the tables for the header field, and then
+ // choose a representation type.
+ // TODO Each indexing types per field should be passed by a caller, HTTP/2
+ // implementation.
// Get first header field which is required encoding
MIMEField *field;
@@ -629,17 +629,17 @@ http2_write_header_fragment(HTTPHdr *in, MIMEFieldIter &field_iter, uint8_t *out
return p - out;
}
+/*
+ * Decode Header Blocks to Header List.
+ */
int64_t
-http2_parse_header_fragment(HTTPHdr *hdr, IOVec iov, Http2DynamicTable &dynamic_table, bool cont)
+http2_decode_header_blocks(HTTPHdr *hdr, const uint8_t *buf_start, const uint8_t *buf_end, Http2DynamicTable &dynamic_table)
{
- const uint8_t *buf_start = (uint8_t *)iov.iov_base;
- const uint8_t *buf_end = buf_start + iov.iov_len;
-
- uint8_t *cursor = (uint8_t *)iov.iov_base; // place the cursor at the start
+ const uint8_t *cursor = buf_start;
HdrHeap *heap = hdr->m_heap;
HTTPHdrImpl *hh = hdr->m_http;
- do {
+ while (cursor < buf_end) {
int64_t read_bytes = 0;
// decode a header field encoded by HPACK
@@ -651,13 +651,7 @@ http2_parse_header_fragment(HTTPHdr *hdr, IOVec iov, Http2DynamicTable &dynamic_
case HPACK_FIELD_INDEX:
read_bytes = decode_indexed_header_field(header, cursor, buf_end, dynamic_table);
if (read_bytes == HPACK_ERROR_COMPRESSION_ERROR) {
- if (cont) {
- // Parsing a part of headers is done
- return cursor - buf_start;
- } else {
- // Parse error
- return HPACK_ERROR_COMPRESSION_ERROR;
- }
+ return HPACK_ERROR_COMPRESSION_ERROR;
}
cursor += read_bytes;
break;
@@ -666,26 +660,14 @@ http2_parse_header_fragment(HTTPHdr *hdr, IOVec iov, Http2DynamicTable &dynamic_
case HPACK_FIELD_NEVERINDEX_LITERAL:
read_bytes = decode_literal_header_field(header, cursor, buf_end, dynamic_table);
if (read_bytes == HPACK_ERROR_COMPRESSION_ERROR) {
- if (cont) {
- // Parsing a part of headers is done
- return cursor - buf_start;
- } else {
- // Parse error
- return HPACK_ERROR_COMPRESSION_ERROR;
- }
+ return HPACK_ERROR_COMPRESSION_ERROR;
}
cursor += read_bytes;
break;
case HPACK_FIELD_TABLESIZE_UPDATE:
read_bytes = update_dynamic_table_size(cursor, buf_end, dynamic_table);
if (read_bytes == HPACK_ERROR_COMPRESSION_ERROR) {
- if (cont) {
- // Parsing a part of headers is done
- return cursor - buf_start;
- } else {
- // Parse error
- return HPACK_ERROR_COMPRESSION_ERROR;
- }
+ return HPACK_ERROR_COMPRESSION_ERROR;
}
cursor += read_bytes;
continue;
@@ -700,7 +682,8 @@ http2_parse_header_fragment(HTTPHdr *hdr, IOVec iov, Http2DynamicTable &dynamic_
return HPACK_ERROR_HTTP2_PROTOCOL_ERROR;
}
- // rfc7540,sec8.1.2.2: Any message containing connection-specific header fields MUST be treated as malformed
+ // rfc7540,sec8.1.2.2: Any message containing connection-specific header
+ // fields MUST be treated as malformed
if (name == MIME_FIELD_CONNECTION) {
return HPACK_ERROR_HTTP2_PROTOCOL_ERROR;
}
@@ -738,10 +721,10 @@ http2_parse_header_fragment(HTTPHdr *hdr, IOVec iov, Http2DynamicTable &dynamic_
return HPACK_ERROR_HTTP2_PROTOCOL_ERROR;
}
}
- } while (cursor < buf_end);
+ }
// Psuedo headers is insufficient
- if (hdr->fields_count() < 4 && !cont) {
+ if (hdr->fields_count() < 4) {
return HPACK_ERROR_HTTP2_PROTOCOL_ERROR;
}
@@ -788,7 +771,6 @@ Http2::init()
static_cast<int>(HTTP2_STAT_TOTAL_CLIENT_CONNECTION_COUNT), RecRawStatSyncSum);
}
-
#if TS_HAS_TESTS
#include "ts/TestBox.h"
@@ -799,10 +781,11 @@ const static int MAX_TEST_FIELD_NUM = 8;
/***********************************************************************************
* *
- * Test cases for regression test *
+ * Test cases for regression test *
* *
- * Some test cases are based on examples of specification. *
- * http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-09#appendix-D *
+ * Some test cases are based on examples of specification. *
+ * http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-09#appendix-D
+ **
* *
***********************************************************************************/
@@ -909,7 +892,7 @@ const static struct {
/***********************************************************************************
* *
- * Regression test codes *
+ * Regression test codes *
* *
***********************************************************************************/
@@ -1153,9 +1136,9 @@ REGRESSION_TEST(HPACK_Decode)(RegressionTest *t, int, int *pstatus)
ats_scoped_obj<HTTPHdr> headers(new HTTPHdr);
headers->create(HTTP_TYPE_REQUEST);
- http2_parse_header_fragment(headers,
- make_iovec(encoded_field_test_case[i].encoded_field, encoded_field_test_case[i].encoded_field_len),
- dynamic_table, false);
+ http2_decode_header_blocks(headers, encoded_field_test_case[i].encoded_field,
+ encoded_field_test_case[i].encoded_field + encoded_field_test_case[i].encoded_field_len,
+ dynamic_table);
for (unsigned int j = 0; j < sizeof(raw_field_test_case[i]) / sizeof(raw_field_test_case[i][0]); j++) {
const char *expected_name = raw_field_test_case[i][j].raw_name;
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/8013e761/proxy/http2/HTTP2.h
----------------------------------------------------------------------
diff --git a/proxy/http2/HTTP2.h b/proxy/http2/HTTP2.h
index 3183ec0..29f31fe 100644
--- a/proxy/http2/HTTP2.h
+++ b/proxy/http2/HTTP2.h
@@ -34,7 +34,8 @@ class HTTPHdr;
typedef unsigned Http2StreamId;
-// 6.9.2 Initial Flow Control Window Size - the flow control window can be come negative
+// 6.9.2 Initial Flow Control Window Size - the flow control window can be come
+// negative
// so we need to track it with a signed type.
typedef int32_t Http2WindowSize;
@@ -62,7 +63,8 @@ const uint32_t HTTP2_MAX_HEADER_LIST_SIZE = UINT_MAX;
// Statistics
enum {
- HTTP2_STAT_CURRENT_CLIENT_SESSION_COUNT, // Current # of active HTTP2 sessions.
+ HTTP2_STAT_CURRENT_CLIENT_SESSION_COUNT, // Current # of active HTTP2
+ // sessions.
HTTP2_STAT_CURRENT_CLIENT_STREAM_COUNT, // Current # of active HTTP2 streams.
HTTP2_STAT_TOTAL_TRANSACTIONS_TIME, // Total stream time and streams
HTTP2_STAT_TOTAL_CLIENT_CONNECTION_COUNT, // Total connections running http2
@@ -247,6 +249,8 @@ struct Http2Priority {
// 6.2 HEADERS Format
struct Http2HeadersParameter {
+ Http2HeadersParameter() : pad_length(0) {}
+
uint8_t pad_length;
Http2Priority priority;
};
@@ -258,8 +262,10 @@ struct Http2Goaway {
Http2StreamId last_streamid;
uint32_t error_code;
- // NOTE: we don't (de)serialize the variable length debug data at this layer because there's
- // really nothing we can do with it without some out of band agreement. Trying to deal with it
+ // NOTE: we don't (de)serialize the variable length debug data at this layer
+ // because there's
+ // really nothing we can do with it without some out of band agreement. Trying
+ // to deal with it
// just complicates memory management.
};
@@ -314,7 +320,7 @@ bool http2_parse_goaway(IOVec, Http2Goaway &);
bool http2_parse_window_update(IOVec, uint32_t &);
-int64_t http2_parse_header_fragment(HTTPHdr *, IOVec, Http2DynamicTable &, bool);
+int64_t http2_decode_header_blocks(HTTPHdr *, const uint8_t *, const uint8_t *, Http2DynamicTable &);
MIMEParseResult convert_from_2_to_1_1_header(HTTPHdr *);
@@ -322,9 +328,10 @@ int64_t http2_write_psuedo_headers(HTTPHdr *, uint8_t *, uint64_t, Http2DynamicT
int64_t http2_write_header_fragment(HTTPHdr *, MIMEFieldIter &, uint8_t *, uint64_t, Http2DynamicTable &, bool &);
-
-// Not sure where else to put this, but figure this is as good of a start as anything else.
-// Right now, only the static init() is available, which sets up some basic librecords
+// Not sure where else to put this, but figure this is as good of a start as
+// anything else.
+// Right now, only the static init() is available, which sets up some basic
+// librecords
// dependencies.
class Http2
{
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/8013e761/proxy/http2/Http2ClientSession.cc
----------------------------------------------------------------------
diff --git a/proxy/http2/Http2ClientSession.cc b/proxy/http2/Http2ClientSession.cc
index 0ea6fca..535cfe8 100644
--- a/proxy/http2/Http2ClientSession.cc
+++ b/proxy/http2/Http2ClientSession.cc
@@ -42,7 +42,8 @@
ClassAllocator<Http2ClientSession> http2ClientSessionAllocator("http2ClientSessionAllocator");
-// memcpy the requested bytes from the IOBufferReader, returning how many were actually copied.
+// memcpy the requested bytes from the IOBufferReader, returning how many were
+// actually copied.
static inline unsigned
copy_from_buffer_reader(void *dst, IOBufferReader *reader, unsigned nbytes)
{
@@ -95,7 +96,8 @@ Http2ClientSession::start()
// 3.5 HTTP/2 Connection Preface. Upon establishment of a TCP connection and
// determination that HTTP/2 will be used by both peers, each endpoint MUST
// send a connection preface as a final confirmation ...
- // this->write_buffer->write(HTTP2_CONNECTION_PREFACE, HTTP2_CONNECTION_PREFACE_LEN);
+ // this->write_buffer->write(HTTP2_CONNECTION_PREFACE,
+ // HTTP2_CONNECTION_PREFACE_LEN);
this->connection_state.init();
send_connection_event(&this->connection_state, HTTP2_SESSION_EVENT_INIT, this);
@@ -150,7 +152,8 @@ Http2ClientSession::set_upgrade_context(HTTPHdr *h)
Http2SettingsParameter param;
if (!http2_parse_settings_parameter(make_iovec(out_buf + nbytes, HTTP2_SETTINGS_PARAMETER_LEN), param) ||
!http2_settings_parameter_is_valid(param)) {
- // TODO ignore incoming invalid parameters and send suitable SETTINGS frame.
+ // TODO ignore incoming invalid parameters and send suitable SETTINGS
+ // frame.
}
upgrade_context.client_settings.set((Http2SettingsIdentifier)param.id, param.value);
}
@@ -186,7 +189,8 @@ Http2ClientSession::do_io_shutdown(ShutdownHowTo_t howto)
this->client_vc->do_io_shutdown(howto);
}
-// XXX Currently, we don't have a half-closed state, but we will need to implement that. After we send a GOAWAY, there
+// XXX Currently, we don't have a half-closed state, but we will need to
+// implement that. After we send a GOAWAY, there
// are scenarios where we would like to complete the outstanding streams.
void
@@ -294,8 +298,10 @@ Http2ClientSession::state_read_connection_preface(int event, void *edata)
}
}
- // XXX We don't have enough data to check the connection preface. We should reset the accept inactivity
- // timeout. We should have a maximum timeout to get the session started though.
+ // XXX We don't have enough data to check the connection preface. We should
+ // reset the accept inactivity
+ // timeout. We should have a maximum timeout to get the session started
+ // though.
vio->reenable();
return 0;
@@ -351,9 +357,11 @@ Http2ClientSession::state_start_frame_read(int event, void *edata)
}
// CONTINUATIONs MUST follow behind HEADERS which doesn't have END_HEADERS
- if (this->connection_state.get_continued_id() != 0 && this->current_hdr.type != HTTP2_FRAME_TYPE_CONTINUATION) {
+ Http2StreamId continued_stream_id = this->connection_state.get_continued_stream_id();
+
+ if (continued_stream_id != 0 && this->current_hdr.type != HTTP2_FRAME_TYPE_CONTINUATION) {
SCOPED_MUTEX_LOCK(lock, this->connection_state.mutex, this_ethread());
- if (!this->connection_state.is_state_closed()) {
+ if (!this->connection_state.is_state_closed() || continued_stream_id != this->current_hdr.streamid) {
this->connection_state.send_goaway_frame(this->current_hdr.streamid, HTTP2_ERROR_PROTOCOL_ERROR);
}
return 0;
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/8013e761/proxy/http2/Http2ConnectionState.cc
----------------------------------------------------------------------
diff --git a/proxy/http2/Http2ConnectionState.cc b/proxy/http2/Http2ConnectionState.cc
index 311e508..7569ff3 100644
--- a/proxy/http2/Http2ConnectionState.cc
+++ b/proxy/http2/Http2ConnectionState.cc
@@ -71,7 +71,8 @@ rcv_data_frame(Http2ClientSession &cs, Http2ConnectionState &cstate, const Http2
DebugSsn(&cs, "http2_cs", "[%" PRId64 "] Received DATA frame.", cs.connection_id());
- // If a DATA frame is received whose stream identifier field is 0x0, the recipient MUST
+ // If a DATA frame is received whose stream identifier field is 0x0, the
+ // recipient MUST
// respond with a connection error of type PROTOCOL_ERROR.
if (!http2_is_client_streamid(id)) {
return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_PROTOCOL_ERROR);
@@ -86,7 +87,8 @@ rcv_data_frame(Http2ClientSession &cs, Http2ConnectionState &cstate, const Http2
}
}
- // If a DATA frame is received whose stream is not in "open" or "half closed (local)" state,
+ // If a DATA frame is received whose stream is not in "open" or "half closed
+ // (local)" state,
// the recipient MUST respond with a stream error of type STREAM_CLOSED.
if (stream->get_state() != HTTP2_STREAM_STATE_OPEN && stream->get_state() != HTTP2_STREAM_STATE_HALF_CLOSED_LOCAL) {
return Http2Error(HTTP2_ERROR_CLASS_STREAM, HTTP2_ERROR_STREAM_CLOSED);
@@ -158,28 +160,33 @@ rcv_data_frame(Http2ClientSession &cs, Http2ConnectionState &cstate, const Http2
return Http2Error(HTTP2_ERROR_CLASS_NONE);
}
+/*
+ * [RFC 7540] 6.2 HEADERS Frame
+ *
+ * NOTE: HEADERS Frame and CONTINUATION Frame
+ * 1. A HEADERS frame with the END_STREAM flag set can be followed by
+ *CONTINUATION frames on the same stream.
+ * 2. A HEADERS frame without the END_HEADERS flag set MUST be followed by a
+ *CONTINUATION frame
+ */
static Http2Error
rcv_headers_frame(Http2ClientSession &cs, Http2ConnectionState &cstate, const Http2Frame &frame)
{
- char buf[BUFFER_SIZE_FOR_INDEX(buffer_size_index[HTTP2_FRAME_TYPE_HEADERS])];
- unsigned nbytes = 0;
- Http2StreamId id = frame.header().streamid;
- Http2HeadersParameter params;
+ const Http2StreamId stream_id = frame.header().streamid;
const uint32_t payload_length = frame.header().length;
DebugSsn(&cs, "http2_cs", "[%" PRId64 "] Received HEADERS frame.", cs.connection_id());
- if (!http2_is_client_streamid(id)) {
+ if (!http2_is_client_streamid(stream_id)) {
return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_PROTOCOL_ERROR);
}
- if (id <= cstate.get_latest_stream_id()) {
+ if (stream_id <= cstate.get_latest_stream_id()) {
return Http2Error(HTTP2_ERROR_CLASS_STREAM, HTTP2_ERROR_STREAM_CLOSED);
}
// Create new stream
- Http2Stream *stream = cstate.create_stream(id);
-
+ Http2Stream *stream = cstate.create_stream(stream_id);
if (!stream) {
return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_PROTOCOL_ERROR);
}
@@ -192,83 +199,71 @@ rcv_headers_frame(Http2ClientSession &cs, Http2ConnectionState &cstate, const Ht
return Http2Error(HTTP2_ERROR_CLASS_STREAM, HTTP2_ERROR_PROTOCOL_ERROR);
}
- // A receiver MUST treat the receipt of any other type of frame or
- // a frame on a different stream as a connection error of type PROTOCOL_ERROR.
- if (cstate.get_continued_id() != 0) {
- return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_PROTOCOL_ERROR);
- }
+ Http2HeadersParameter params;
+ uint32_t header_block_fragment_offset = 0;
+ uint32_t header_block_fragment_length = payload_length;
- // Change state. If changing is invalid, raise PROTOCOL_ERROR
- if (!stream->change_state(frame.header().type, frame.header().flags)) {
- return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_PROTOCOL_ERROR);
+ if (frame.header().flags & HTTP2_FLAGS_HEADERS_END_STREAM) {
+ stream->end_stream = true;
}
- // Check whether padding exists or not.
+ // NOTE: Strip padding if exists
if (frame.header().flags & HTTP2_FLAGS_HEADERS_PADDED) {
- frame.reader()->memcpy(buf, HTTP2_HEADERS_PADLEN_LEN, nbytes);
- nbytes += HTTP2_HEADERS_PADLEN_LEN;
+ uint8_t buf[HTTP2_HEADERS_PADLEN_LEN] = {0};
+ frame.reader()->memcpy(buf, HTTP2_HEADERS_PADLEN_LEN);
+
if (!http2_parse_headers_parameter(make_iovec(buf, HTTP2_HEADERS_PADLEN_LEN), params)) {
return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_PROTOCOL_ERROR);
}
if (params.pad_length > payload_length) {
- // If the length of the padding is the length of the
- // frame payload or greater, the recipient MUST treat this as a
- // connection error of type PROTOCOL_ERROR.
return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_PROTOCOL_ERROR);
}
- } else {
- params.pad_length = 0;
+
+ header_block_fragment_offset += HTTP2_HEADERS_PADLEN_LEN;
+ header_block_fragment_length -= (HTTP2_HEADERS_PADLEN_LEN + params.pad_length);
}
- // Check whether parameters of priority exist or not.
- // TODO Currently priority is NOT supported.
+ // NOTE: Parse priority parameters if exists
+ // TODO: Currently priority is NOT supported. TS-3535 will fix this.
if (frame.header().flags & HTTP2_FLAGS_HEADERS_PRIORITY) {
- frame.reader()->memcpy(buf, HTTP2_PRIORITY_LEN, nbytes);
- nbytes += HTTP2_PRIORITY_LEN;
+ uint8_t buf[HTTP2_PRIORITY_LEN] = {0};
+
+ frame.reader()->memcpy(buf, HTTP2_PRIORITY_LEN, header_block_fragment_offset);
if (!http2_parse_priority_parameter(make_iovec(buf, HTTP2_PRIORITY_LEN), params.priority)) {
return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_PROTOCOL_ERROR);
}
- }
- // Parse request headers encoded by HPACK
- const uint32_t unpadded_length = payload_length - params.pad_length;
- uint32_t remaining_bytes = 0;
- for (;;) {
- size_t read_len = sizeof(buf) - remaining_bytes;
- if (nbytes + read_len > unpadded_length)
- read_len -= nbytes + read_len - unpadded_length;
- unsigned read_bytes = read_rcv_buffer(buf + remaining_bytes, read_len, nbytes, frame);
- IOVec header_block_fragment = make_iovec(buf, read_bytes + remaining_bytes);
+ header_block_fragment_offset += HTTP2_PRIORITY_LEN;
+ header_block_fragment_length -= HTTP2_PRIORITY_LEN;
+ }
- bool cont = nbytes < payload_length || !(frame.header().flags & HTTP2_FLAGS_HEADERS_END_HEADERS);
- int64_t decoded_bytes = stream->decode_request_header(header_block_fragment, *cstate.local_dynamic_table, cont);
+ stream->header_blocks = static_cast<uint8_t *>(ats_malloc(header_block_fragment_length));
+ frame.reader()->memcpy(stream->header_blocks, header_block_fragment_length, header_block_fragment_offset);
- // 4.3. A receiver MUST terminate the connection with a
- // connection error of type COMPRESSION_ERROR if it does
- // not decompress a header block.
- if (decoded_bytes == 0 || decoded_bytes == HPACK_ERROR_COMPRESSION_ERROR) {
- return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_COMPRESSION_ERROR);
- }
+ stream->header_blocks_length = header_block_fragment_length;
- if (decoded_bytes == HPACK_ERROR_HTTP2_PROTOCOL_ERROR) {
- return Http2Error(HTTP2_ERROR_CLASS_STREAM, HTTP2_ERROR_PROTOCOL_ERROR);
+ if (frame.header().flags & HTTP2_FLAGS_HEADERS_END_HEADERS) {
+ // NOTE: If there are END_HEADERS flag, decode stored Header Blocks.
+ if (!stream->change_state(HTTP2_FRAME_TYPE_HEADERS, frame.header().flags)) {
+ return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_PROTOCOL_ERROR);
}
- remaining_bytes = header_block_fragment.iov_len - decoded_bytes;
- memmove(buf, buf + header_block_fragment.iov_len - remaining_bytes, remaining_bytes);
+ const int64_t decoded_bytes = stream->decode_header_blocks(*cstate.local_dynamic_table);
- if (nbytes >= payload_length - params.pad_length) {
- if (!(frame.header().flags & HTTP2_FLAGS_HEADERS_END_HEADERS)) {
- cstate.set_continued_headers(buf, remaining_bytes, id);
- }
- break;
+ if (decoded_bytes == 0 || decoded_bytes == HPACK_ERROR_COMPRESSION_ERROR) {
+ return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_COMPRESSION_ERROR);
+ } else if (decoded_bytes == HPACK_ERROR_HTTP2_PROTOCOL_ERROR) {
+ return Http2Error(HTTP2_ERROR_CLASS_STREAM, HTTP2_ERROR_PROTOCOL_ERROR);
}
- }
- // backposting
- if (frame.header().flags & HTTP2_FLAGS_HEADERS_END_HEADERS) {
stream->init_fetcher(cstate);
+ } else {
+ // NOTE: Expect CONTINUATION Frame. Do NOT change state of stream or decode
+ // Header Blocks.
+ DebugSsn(&cs, "http2_cs", "[%" PRId64 "] No END_HEADERS flag, expecting CONTINUATION frame.", cs.connection_id());
+
+ cstate.set_continued_stream_id(stream_id);
}
return Http2Error(HTTP2_ERROR_CLASS_NONE);
@@ -415,7 +410,8 @@ rcv_settings_frame(Http2ClientSession &cs, Http2ConnectionState &cstate, const H
cstate.client_settings.set((Http2SettingsIdentifier)param.id, param.value);
}
- // 6.5 Once all values have been applied, the recipient MUST immediately emit a
+ // 6.5 Once all values have been applied, the recipient MUST immediately emit
+ // a
// SETTINGS frame with the ACK flag set.
Http2Frame ackFrame(HTTP2_FRAME_TYPE_SETTINGS, 0, HTTP2_FLAGS_SETTINGS_ACK);
cstate.ua_session->handleEvent(HTTP2_SESSION_EVENT_XMIT, &ackFrame);
@@ -441,8 +437,10 @@ rcv_ping_frame(Http2ClientSession &cs, Http2ConnectionState &cstate, const Http2
DebugSsn(&cs, "http2_cs", "[%" PRId64 "] Received PING frame.", cs.connection_id());
- // If a PING frame is received with a stream identifier field value other than
- // 0x0, the recipient MUST respond with a connection error of type PROTOCOL_ERROR.
+ // If a PING frame is received with a stream identifier field value other
+ // than
+ // 0x0, the recipient MUST respond with a connection error of type
+ // PROTOCOL_ERROR.
if (frame.header().streamid != 0x0) {
return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_PROTOCOL_ERROR);
}
@@ -518,8 +516,10 @@ rcv_window_update_frame(Http2ClientSession &cs, Http2ConnectionState &cstate, co
frame.reader()->memcpy(buf, sizeof(buf), 0);
http2_parse_window_update(make_iovec(buf, sizeof(buf)), size);
- // A receiver MUST treat the receipt of a WINDOW_UPDATE frame with a connection
- // flow control window increment of 0 as a connection error of type PROTOCOL_ERROR;
+ // A receiver MUST treat the receipt of a WINDOW_UPDATE frame with a
+ // connection
+ // flow control window increment of 0 as a connection error of type
+ // PROTOCOL_ERROR;
if (size == 0) {
return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_PROTOCOL_ERROR);
}
@@ -553,7 +553,8 @@ rcv_window_update_frame(Http2ClientSession &cs, Http2ConnectionState &cstate, co
http2_parse_window_update(make_iovec(buf, sizeof(buf)), size);
// A receiver MUST treat the receipt of a WINDOW_UPDATE frame with an
- // flow control window increment of 0 as a stream error of type PROTOCOL_ERROR;
+ // flow control window increment of 0 as a stream error of type
+ // PROTOCOL_ERROR;
if (size == 0) {
return Http2Error(HTTP2_ERROR_CLASS_STREAM, HTTP2_ERROR_PROTOCOL_ERROR);
}
@@ -579,19 +580,30 @@ rcv_window_update_frame(Http2ClientSession &cs, Http2ConnectionState &cstate, co
return Http2Error(HTTP2_ERROR_CLASS_NONE);
}
+/*
+ * [RFC 7540] 6.10 CONTINUATION
+ *
+ * NOTE: Logically, the CONTINUATION frames are part of the HEADERS frame. ([RFC
+ *7540] 6.2 HEADERS)
+ *
+ */
static Http2Error
rcv_continuation_frame(Http2ClientSession &cs, Http2ConnectionState &cstate, const Http2Frame &frame)
{
- char buf[BUFFER_SIZE_FOR_INDEX(buffer_size_index[HTTP2_FRAME_TYPE_CONTINUATION])];
- unsigned nbytes = 0;
const Http2StreamId stream_id = frame.header().streamid;
+ const uint32_t payload_length = frame.header().length;
DebugSsn(&cs, "http2_cs", "[%" PRId64 "] Received CONTINUATION frame.", cs.connection_id());
+ if (!http2_is_client_streamid(stream_id)) {
+ return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_PROTOCOL_ERROR);
+ }
+
// Find opened stream
// CONTINUATION frames MUST be associated with a stream. If a
// CONTINUATION frame is received whose stream identifier field is 0x0,
- // the recipient MUST respond with a connection error (Section 5.4.1) of
+ // the recipient MUST respond with a connection error ([RFC 7540] Section
+ // 5.4.1) of
// type PROTOCOL_ERROR.
Http2Stream *stream = cstate.find_stream(stream_id);
if (stream == NULL) {
@@ -600,70 +612,54 @@ rcv_continuation_frame(Http2ClientSession &cs, Http2ConnectionState &cstate, con
} else {
return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_PROTOCOL_ERROR);
}
+ } else {
+ switch (stream->get_state()) {
+ case HTTP2_STREAM_STATE_HALF_CLOSED_REMOTE:
+ return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_STREAM_CLOSED);
+ case HTTP2_STREAM_STATE_IDLE:
+ break;
+ default:
+ return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_PROTOCOL_ERROR);
+ }
}
- // A CONTINUATION frame MUST be preceded by a HEADERS, PUSH_PROMISE or
- // CONTINUATION frame without the END_HEADERS flag set. A recipient
- // that observes violation of this rule MUST respond with a connection
- // error (Section 5.4.1) of type PROTOCOL_ERROR.
- if (stream->get_state() != HTTP2_STREAM_STATE_HALF_CLOSED_REMOTE && stream->get_state() != HTTP2_STREAM_STATE_HALF_CLOSED_LOCAL) {
+ // keep track of how many bytes we get in the frame
+ stream->request_header_length += payload_length;
+ if (stream->request_header_length > Http2::max_request_header_size) {
+ Error("HTTP/2 payload for headers exceeded: %u", stream->request_header_length);
return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_PROTOCOL_ERROR);
}
- // A receiver MUST treat the receipt of any other type of frame or
- // a frame on a different stream as a connection error of type PROTOCOL_ERROR.
- if (stream->get_id() != cstate.get_continued_id()) {
+ if (!stream->header_blocks) {
return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_PROTOCOL_ERROR);
}
- const IOVec remaining_data = cstate.get_continued_headers();
- uint32_t remaining_bytes = remaining_data.iov_len;
- if (remaining_bytes && remaining_data.iov_base) {
- memcpy(buf, remaining_data.iov_base, remaining_data.iov_len);
- }
+ uint32_t header_blocks_offset = stream->header_blocks_length;
+ stream->header_blocks_length += payload_length;
- // Parse request headers encoded by HPACK
- for (;;) {
- unsigned read_bytes = read_rcv_buffer(buf + remaining_bytes, sizeof(buf) - remaining_bytes, nbytes, frame);
- IOVec header_block_fragment = make_iovec(buf, read_bytes + remaining_bytes);
-
- // keep track of how many bytes we get in the frame
- stream->request_header_length += frame.header().length;
- if (stream->request_header_length > Http2::max_request_header_size) {
- Error("HTTP/2 payload for headers exceeded: %u", stream->request_header_length);
- // XXX Should we respond with 431 (Request Header Fields Too Large) ?
- return Http2Error(HTTP2_ERROR_CLASS_STREAM, HTTP2_ERROR_PROTOCOL_ERROR);
- }
+ stream->header_blocks = static_cast<uint8_t *>(ats_realloc(stream->header_blocks, stream->header_blocks_length));
+ frame.reader()->memcpy(stream->header_blocks + header_blocks_offset, payload_length);
- bool cont = nbytes < frame.header().length || !(frame.header().flags & HTTP2_FLAGS_HEADERS_END_HEADERS);
- int64_t decoded_bytes = stream->decode_request_header(header_block_fragment, *cstate.local_dynamic_table, cont);
-
- // A receiver MUST terminate the connection with a
- // connection error of type COMPRESSION_ERROR if it does
- // not decompress a header block.
- if (decoded_bytes == 0 || decoded_bytes == HPACK_ERROR_COMPRESSION_ERROR) {
- return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_COMPRESSION_ERROR);
- }
+ if (frame.header().flags & HTTP2_FLAGS_HEADERS_END_HEADERS) {
+ // NOTE: If there are END_HEADERS flag, decode stored Header Blocks.
+ cstate.clear_continued_stream_id();
- if (decoded_bytes == HPACK_ERROR_HTTP2_PROTOCOL_ERROR) {
+ if (!stream->change_state(HTTP2_FRAME_TYPE_CONTINUATION, frame.header().flags)) {
return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_PROTOCOL_ERROR);
}
- remaining_bytes = header_block_fragment.iov_len - decoded_bytes;
- memmove(buf, buf + header_block_fragment.iov_len - remaining_bytes, remaining_bytes);
+ const int64_t decoded_bytes = stream->decode_header_blocks(*cstate.local_dynamic_table);
- if (nbytes >= frame.header().length) {
- if (!(frame.header().flags & HTTP2_FLAGS_HEADERS_END_HEADERS)) {
- cstate.set_continued_headers(buf, remaining_bytes, stream_id);
- }
- break;
+ if (decoded_bytes == 0 || decoded_bytes == HPACK_ERROR_COMPRESSION_ERROR) {
+ return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_COMPRESSION_ERROR);
+ } else if (decoded_bytes == HPACK_ERROR_HTTP2_PROTOCOL_ERROR) {
+ return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_PROTOCOL_ERROR);
}
- }
- // backposting
- if (frame.header().flags & HTTP2_FLAGS_HEADERS_END_HEADERS) {
- cstate.finish_continued_headers();
stream->init_fetcher(cstate);
+ } else {
+ // NOTE: Expect another CONTINUATION Frame. Do nothing.
+ DebugSsn(&cs, "http2_cs", "[%" PRId64 "] No END_HEADERS flag, expecting CONTINUATION frame.", cs.connection_id());
}
return Http2Error(HTTP2_ERROR_CLASS_NONE);
@@ -693,10 +689,12 @@ Http2ConnectionState::main_event_handler(int event, void *edata)
// 3.5 HTTP/2 Connection Preface. Upon establishment of a TCP connection and
// determination that HTTP/2 will be used by both peers, each endpoint MUST
- // send a connection preface as a final confirmation ... The server connection
+ // send a connection preface as a final confirmation ... The server
+ // connection
// preface consists of a potentially empty SETTINGS frame.
- // Load the server settings from the records.config / RecordsConfig.cc settings.
+ // Load the server settings from the records.config / RecordsConfig.cc
+ // settings.
Http2ConnectionSettings configured_settings;
configured_settings.settings_from_configs();
send_settings_frame(configured_settings);
@@ -723,7 +721,8 @@ Http2ConnectionState::main_event_handler(int event, void *edata)
Http2Error error;
// 5.5 Extending HTTP/2
- // Implementations MUST discard frames that have unknown or unsupported types.
+ // Implementations MUST discard frames that have unknown or unsupported
+ // types.
if (frame->header().type >= HTTP2_FRAME_TYPE_MAX) {
DebugSsn(this->ua_session, "http2_cs", "[%" PRId64 "] Discard a frame which has unknown type, type=%x",
this->ua_session->connection_id(), frame->header().type);
@@ -740,9 +739,12 @@ Http2ConnectionState::main_event_handler(int event, void *edata)
if (error.cls == HTTP2_ERROR_CLASS_CONNECTION) {
this->send_goaway_frame(last_streamid, error.code);
cleanup_streams();
- // XXX We need to think a bit harder about how to coordinate the client session and the
- // protocol connection. At this point, the protocol is shutting down, but there's no way
- // to tell that to the client session. Perhaps this could be solved by implementing the
+ // XXX We need to think a bit harder about how to coordinate the client
+ // session and the
+ // protocol connection. At this point, the protocol is shutting down,
+ // but there's no way
+ // to tell that to the client session. Perhaps this could be solved by
+ // implementing the
// half-closed state ...
SET_HANDLER(&Http2ConnectionState::state_closed);
} else if (error.cls == HTTP2_ERROR_CLASS_STREAM) {
@@ -956,8 +958,10 @@ Http2ConnectionState::send_data_frame(FetchSM *fetch_sm)
if (flags & HTTP2_FLAGS_DATA_END_STREAM) {
// Delete a stream immediately
- // TODO its should not be deleted for a several time to handling RST_STREAM and WINDOW_UPDATE.
- // See 'closed' state written at https://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-5.1
+ // TODO its should not be deleted for a several time to handling
+ // RST_STREAM and WINDOW_UPDATE.
+ // See 'closed' state written at
+ // https://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-5.1
this->delete_stream(stream);
break;
}
@@ -979,7 +983,8 @@ Http2ConnectionState::send_headers_frame(FetchSM *fetch_sm)
payload_length += http2_write_psuedo_headers(resp_header, payload_buffer, buf_len, *(this->remote_dynamic_table));
// If response body is empty, set END_STREAM flag to HEADERS frame
- // Must check to ensure content-length is there. Otherwise the value defaults to 0
+ // Must check to ensure content-length is there. Otherwise the value defaults
+ // to 0
if (resp_header->presence(MIME_PRESENCE_CONTENT_LENGTH) && resp_header->get_content_length() == 0) {
flags |= HTTP2_FLAGS_HEADERS_END_STREAM;
}
@@ -1156,7 +1161,7 @@ Http2Stream::set_body_to_fetcher(const void *data, size_t len)
}
/*
- * 5.1. Stream States
+ * 5.1. Stream States
*
* +--------+
* PP | | PP
@@ -1190,8 +1195,13 @@ Http2Stream::change_state(uint8_t type, uint8_t flags)
switch (_state) {
case HTTP2_STREAM_STATE_IDLE:
if (type == HTTP2_FRAME_TYPE_HEADERS) {
- if (flags & HTTP2_FLAGS_HEADERS_END_STREAM) {
- // Skip OPEN _state
+ if (end_stream && flags & HTTP2_FLAGS_HEADERS_END_HEADERS) {
+ _state = HTTP2_STREAM_STATE_HALF_CLOSED_REMOTE;
+ } else {
+ _state = HTTP2_STREAM_STATE_OPEN;
+ }
+ } else if (type == HTTP2_FRAME_TYPE_CONTINUATION) {
+ if (end_stream && flags & HTTP2_FLAGS_CONTINUATION_END_HEADERS) {
_state = HTTP2_STREAM_STATE_HALF_CLOSED_REMOTE;
} else {
_state = HTTP2_STREAM_STATE_OPEN;
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/8013e761/proxy/http2/Http2ConnectionState.h
----------------------------------------------------------------------
diff --git a/proxy/http2/Http2ConnectionState.h b/proxy/http2/Http2ConnectionState.h
index 14d7f01..41297f0 100644
--- a/proxy/http2/Http2ConnectionState.h
+++ b/proxy/http2/Http2ConnectionState.h
@@ -35,7 +35,8 @@ class Http2ConnectionSettings
public:
Http2ConnectionSettings()
{
- // 6.5.2. Defined SETTINGS Parameters. These should generally not be modified,
+ // 6.5.2. Defined SETTINGS Parameters. These should generally not be
+ // modified,
// only if the protocol changes should these change.
settings[indexof(HTTP2_SETTINGS_ENABLE_PUSH)] = 0; // Disabled for now
@@ -99,14 +100,14 @@ class Http2Stream
{
public:
Http2Stream(Http2StreamId sid = 0, ssize_t initial_rwnd = Http2::initial_window_size)
- : client_rwnd(initial_rwnd), server_rwnd(initial_rwnd), _id(sid), _state(HTTP2_STREAM_STATE_IDLE), _fetch_sm(NULL),
- body_done(false), data_length(0)
+ : client_rwnd(initial_rwnd), server_rwnd(initial_rwnd), header_blocks(NULL), header_blocks_length(0), request_header_length(0),
+ end_stream(false), _id(sid), _state(HTTP2_STREAM_STATE_IDLE), _fetch_sm(NULL), body_done(false), data_length(0)
{
_thread = this_ethread();
HTTP2_INCREMENT_THREAD_DYN_STAT(HTTP2_STAT_CURRENT_CLIENT_STREAM_COUNT, _thread);
_start_time = ink_hrtime();
+ // FIXME: Are you sure? every "stream" needs _req_header?
_req_header.create(HTTP_TYPE_REQUEST);
- request_header_length = 0;
}
~Http2Stream()
@@ -120,6 +121,9 @@ public:
_fetch_sm->ext_destroy();
_fetch_sm = NULL;
}
+ if (header_blocks) {
+ ats_free(header_blocks);
+ }
}
// Operate FetchSM
@@ -154,9 +158,10 @@ public:
bool change_state(uint8_t type, uint8_t flags);
int64_t
- decode_request_header(const IOVec &iov, Http2DynamicTable &dynamic_table, bool cont)
+ decode_header_blocks(Http2DynamicTable &dynamic_table)
{
- return http2_parse_header_fragment(&_req_header, iov, dynamic_table, cont);
+ return http2_decode_header_blocks(&_req_header, (const uint8_t *)header_blocks,
+ (const uint8_t *)header_blocks + header_blocks_length, dynamic_table);
}
// Check entire DATA payload length if content-length: header is exist
@@ -177,7 +182,12 @@ public:
LINK(Http2Stream, link);
- uint32_t request_header_length;
+ uint8_t *header_blocks;
+ uint32_t header_blocks_length; // total length of header blocks (not include
+ // Padding or other fields)
+ uint32_t request_header_length; // total length of payload (include Padding
+ // and other fields)
+ bool end_stream;
private:
ink_hrtime _start_time;
@@ -191,10 +201,10 @@ private:
uint64_t data_length;
};
-
// Http2ConnectionState
//
-// Capture the semantics of a HTTP/2 connection. The client session captures the frame layer, and the
+// Capture the semantics of a HTTP/2 connection. The client session captures the
+// frame layer, and the
// connection state captures the connection-wide state.
class Http2ConnectionState : public Continuation
@@ -202,7 +212,7 @@ class Http2ConnectionState : public Continuation
public:
Http2ConnectionState()
: Continuation(NULL), ua_session(NULL), client_rwnd(Http2::initial_window_size), server_rwnd(Http2::initial_window_size),
- stream_list(), latest_streamid(0), client_streams_count(0), continued_id(0)
+ stream_list(), latest_streamid(0), client_streams_count(0), continued_stream_id(0)
{
SET_HANDLER(&Http2ConnectionState::main_event_handler);
}
@@ -257,17 +267,20 @@ public:
// Continuated header decoding
Http2StreamId
- get_continued_id() const
+ get_continued_stream_id() const
+ {
+ return continued_stream_id;
+ }
+ void
+ set_continued_stream_id(Http2StreamId stream_id)
{
- return continued_id;
+ continued_stream_id = stream_id;
}
- const IOVec &
- get_continued_headers() const
+ void
+ clear_continued_stream_id()
{
- return continued_buffer;
+ continued_stream_id = 0;
}
- void set_continued_headers(const char *buf, uint32_t len, Http2StreamId id);
- void finish_continued_headers();
// Connection level window size
ssize_t client_rwnd, server_rwnd;
@@ -292,17 +305,25 @@ private:
Http2ConnectionState &operator=(const Http2ConnectionState &); // noncopyable
// NOTE: 'stream_list' has only active streams.
- // If given Stream Identifier is not found in stream_list and it is less than or equal to latest_streamid, the state of Stream
+ // If given Stream Identifier is not found in stream_list and it is less
+ // than or equal to latest_streamid, the state of Stream
// is CLOSED.
- // If given Stream Identifier is not found in stream_list and it is greater than latest_streamid, the state of Stream is IDLE.
+ // If given Stream Identifier is not found in stream_list and it is greater
+ // than latest_streamid, the state of Stream is IDLE.
DLL<Http2Stream> stream_list;
Http2StreamId latest_streamid;
// Counter for current acive streams which is started by client
uint32_t client_streams_count;
- // The buffer used for storing incomplete fragments of a header field which consists of multiple frames.
- Http2StreamId continued_id;
+ // NOTE: Id of stream which MUST receive CONTINUATION frame.
+ // - [RFC 7540] 6.2 HEADERS
+ // "A HEADERS frame without the END_HEADERS flag set MUST be followed by a
+ // CONTINUATION frame for the same stream."
+ // - [RFC 7540] 6.10 CONTINUATION
+ // "If the END_HEADERS bit is not set, this frame MUST be followed by
+ // another CONTINUATION frame."
+ Http2StreamId continued_stream_id;
IOVec continued_buffer;
};
[2/2] trafficserver git commit: TS-3752: Problem with larger headers
and HTTP/2 Added back in the debug messages
Posted by bc...@apache.org.
TS-3752: Problem with larger headers and HTTP/2
Added back in the debug messages
(cherry picked from commit a5818b350d48ea14598d1c876124b393a936f3c9)
Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo
Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/a248e11c
Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/a248e11c
Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/a248e11c
Branch: refs/heads/6.0.x
Commit: a248e11c054503dc8ce6d35e6eac7cca7d3e95f2
Parents: 8013e76
Author: Bryan Call <bc...@apache.org>
Authored: Thu Aug 13 14:05:22 2015 -0700
Committer: Bryan Call <bc...@apache.org>
Committed: Tue Aug 25 13:20:46 2015 -0700
----------------------------------------------------------------------
proxy/http2/Http2ConnectionState.cc | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/a248e11c/proxy/http2/Http2ConnectionState.cc
----------------------------------------------------------------------
diff --git a/proxy/http2/Http2ConnectionState.cc b/proxy/http2/Http2ConnectionState.cc
index 7569ff3..4e34a8f 100644
--- a/proxy/http2/Http2ConnectionState.cc
+++ b/proxy/http2/Http2ConnectionState.cc
@@ -861,6 +861,8 @@ Http2ConnectionState::cleanup_streams()
void
Http2ConnectionState::set_continued_headers(const char *buf, uint32_t len, Http2StreamId id)
{
+ DebugSsn(this->ua_session, "http2_cs", "[%" PRId64 "] Send CONTINUATION frame.", this->ua_session->connection_id());
+
if (buf && len > 0) {
if (!continued_buffer.iov_base) {
continued_buffer.iov_base = static_cast<uint8_t *>(ats_malloc(len));
@@ -906,11 +908,11 @@ Http2ConnectionState::update_initial_rwnd(Http2WindowSize new_size)
void
Http2ConnectionState::send_data_frame(FetchSM *fetch_sm)
{
+ DebugSsn(this->ua_session, "http2_cs", "[%" PRId64 "] Send DATA frame", this->ua_session->connection_id());
+
size_t buf_len = BUFFER_SIZE_FOR_INDEX(buffer_size_index[HTTP2_FRAME_TYPE_DATA]) - HTTP2_FRAME_HEADER_LEN;
uint8_t payload_buffer[buf_len];
- DebugSsn(this->ua_session, "http2_cs", "[%" PRId64 "] Send DATA frame.", this->ua_session->connection_id());
-
Http2Stream *stream = static_cast<Http2Stream *>(fetch_sm->ext_get_user_data());
for (;;) {
@@ -971,6 +973,8 @@ Http2ConnectionState::send_data_frame(FetchSM *fetch_sm)
void
Http2ConnectionState::send_headers_frame(FetchSM *fetch_sm)
{
+ DebugSsn(this->ua_session, "http2_cs", "[%" PRId64 "] Send HEADERS frame.", this->ua_session->connection_id());
+
const size_t buf_len = BUFFER_SIZE_FOR_INDEX(buffer_size_index[HTTP2_FRAME_TYPE_HEADERS]) - HTTP2_FRAME_HEADER_LEN;
uint8_t payload_buffer[buf_len];
size_t payload_length = 0;
@@ -1021,6 +1025,8 @@ Http2ConnectionState::send_headers_frame(FetchSM *fetch_sm)
void
Http2ConnectionState::send_rst_stream_frame(Http2StreamId id, Http2ErrorCode ec)
{
+ DebugSsn(this->ua_session, "http2_cs", "[%" PRId64 "] Send RST_STREAM frame.", this->ua_session->connection_id());
+
Http2Frame rst_stream(HTTP2_FRAME_TYPE_RST_STREAM, id, 0);
rst_stream.alloc(buffer_size_index[HTTP2_FRAME_TYPE_RST_STREAM]);
@@ -1070,6 +1076,8 @@ Http2ConnectionState::send_settings_frame(const Http2ConnectionSettings &new_set
void
Http2ConnectionState::send_ping_frame(Http2StreamId id, uint8_t flag, const uint8_t *opaque_data)
{
+ DebugSsn(this->ua_session, "http2_cs", "[%" PRId64 "] Send PING frame.", this->ua_session->connection_id());
+
Http2Frame ping(HTTP2_FRAME_TYPE_PING, id, flag);
ping.alloc(buffer_size_index[HTTP2_FRAME_TYPE_PING]);
@@ -1084,6 +1092,8 @@ Http2ConnectionState::send_ping_frame(Http2StreamId id, uint8_t flag, const uint
void
Http2ConnectionState::send_goaway_frame(Http2StreamId id, Http2ErrorCode ec)
{
+ DebugSsn(this->ua_session, "http2_cs", "[%" PRId64 "] Send GOAWAY frame.", this->ua_session->connection_id());
+
Http2Frame frame(HTTP2_FRAME_TYPE_GOAWAY, 0, 0);
Http2Goaway goaway;
@@ -1106,6 +1116,8 @@ Http2ConnectionState::send_goaway_frame(Http2StreamId id, Http2ErrorCode ec)
void
Http2ConnectionState::send_window_update_frame(Http2StreamId id, uint32_t size)
{
+ DebugSsn(this->ua_session, "http2_cs", "[%" PRId64 "] Send WINDOW_UPDATE frame.", this->ua_session->connection_id());
+
// Create WINDOW_UPDATE frame
Http2Frame window_update(HTTP2_FRAME_TYPE_WINDOW_UPDATE, id, 0x0);
window_update.alloc(buffer_size_index[HTTP2_FRAME_TYPE_WINDOW_UPDATE]);