Index: net/http2/decoder/decode_http2_structures.cc |
diff --git a/net/http2/decoder/decode_http2_structures.cc b/net/http2/decoder/decode_http2_structures.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..cd419e38bfbf1d41a42dfadaed2cd022739c7279 |
--- /dev/null |
+++ b/net/http2/decoder/decode_http2_structures.cc |
@@ -0,0 +1,355 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "net/http2/decoder/decode_http2_structures.h" |
+ |
+#include <string.h> |
+ |
+#include "base/logging.h" |
+#include "net/http2/decoder/decode_buffer.h" |
+#include "net/http2/http2_constants.h" |
+ |
+namespace net { |
+ |
+// Http2FrameHeader decoding: |
+ |
+void DoDecode(Http2FrameHeader* out, DecodeBuffer* b) { |
+ DCHECK_NE(nullptr, out); |
+ DCHECK_NE(nullptr, b); |
+ DCHECK_LE(Http2FrameHeader::EncodedSize(), b->Remaining()); |
+ out->payload_length = b->DecodeUInt24(); |
+ out->type = static_cast<Http2FrameType>(b->DecodeUInt8()); |
+ out->flags = static_cast<Http2FrameFlag>(b->DecodeUInt8()); |
+ out->stream_id = b->DecodeUInt31(); |
+} |
+ |
+bool MaybeDecode(Http2FrameHeader* out, DecodeBuffer* b) { |
+ DCHECK_NE(nullptr, out); |
+ DCHECK_NE(nullptr, b); |
+ if (b->Remaining() >= Http2FrameHeader::EncodedSize()) { |
+ DoDecode(out, b); |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+bool SlowDecode(Http2FrameHeader* out, DecodeBuffer* b, uint32_t* offset) { |
+ DCHECK_NE(nullptr, out); |
+ DCHECK_NE(nullptr, b); |
+ DCHECK_NE(nullptr, offset); |
+ DCHECK_GT(Http2FrameHeader::EncodedSize(), *offset); |
+ if (b->SlowDecodeUInt24(0 /* field_offset */, offset, &out->payload_length) && |
+ b->SlowDecodeEnum(1 /* field_size */, 3 /* field_offset */, offset, |
+ &out->type) && |
+ b->SlowDecodeEnum(1 /* field_size */, 4 /* field_offset */, offset, |
+ &out->flags) && |
+ b->SlowDecodeUInt31(5 /* field_offset */, offset, &out->stream_id)) { |
+ DCHECK_EQ(Http2FrameHeader::EncodedSize(), *offset); |
+ return true; |
+ } |
+ DCHECK_GT(Http2FrameHeader::EncodedSize(), *offset); |
+ return false; |
+} |
+ |
+// Http2PriorityFields decoding: |
+ |
+void DoDecode(Http2PriorityFields* out, DecodeBuffer* b) { |
+ DCHECK_NE(nullptr, out); |
+ DCHECK_NE(nullptr, b); |
+ DCHECK_LE(Http2PriorityFields::EncodedSize(), b->Remaining()); |
+ uint32_t stream_id_and_flag = b->DecodeUInt32(); |
+ out->stream_dependency = stream_id_and_flag & StreamIdMask(); |
+ if (out->stream_dependency == stream_id_and_flag) { |
+ out->is_exclusive = false; |
+ } else { |
+ out->is_exclusive = true; |
+ } |
+ // Note that chars are automatically promoted to ints during arithmetic, |
+ // so 255 + 1 doesn't end up as zero. |
+ out->weight = b->DecodeUInt8() + 1; |
+} |
+ |
+bool MaybeDecode(Http2PriorityFields* out, DecodeBuffer* b) { |
+ DCHECK_NE(nullptr, out); |
+ DCHECK_NE(nullptr, b); |
+ if (b->Remaining() >= Http2PriorityFields::EncodedSize()) { |
+ DoDecode(out, b); |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+bool SlowDecode(Http2PriorityFields* out, DecodeBuffer* b, uint32_t* offset) { |
+ DCHECK_NE(nullptr, out); |
+ DCHECK_NE(nullptr, b); |
+ DCHECK_NE(nullptr, offset); |
+ DCHECK_GT(Http2PriorityFields::EncodedSize(), *offset); |
+ const uint32_t start_offset = *offset; |
+ if (b->SlowDecodeUInt32(0 /* field_offset */, offset, |
+ &out->stream_dependency) && |
+ b->SlowDecodeUnsignedInt(1, // field_size |
+ 4, // field_offset |
+ offset, &out->weight)) { |
+ DCHECK_EQ(Http2PriorityFields::EncodedSize(), *offset); |
+ if (start_offset < *offset) { |
+ // First time here. Extract is_exclusive from stream_dependency. |
+ const uint32_t stream_id_only = out->stream_dependency & StreamIdMask(); |
+ if (out->stream_dependency != stream_id_only) { |
+ out->stream_dependency = stream_id_only; |
+ out->is_exclusive = true; |
+ } else { |
+ out->is_exclusive = false; |
+ } |
+ // Need to add one to the weight field because the encoding is 0-255, but |
+ // interpreted as 1-256. |
+ ++(out->weight); |
+ } |
+ return true; |
+ } |
+ DCHECK_GT(Http2PriorityFields::EncodedSize(), *offset); |
+ return false; |
+} |
+ |
+// Http2RstStreamFields decoding: |
+ |
+void DoDecode(Http2RstStreamFields* out, DecodeBuffer* b) { |
+ DCHECK_NE(nullptr, out); |
+ DCHECK_NE(nullptr, b); |
+ DCHECK_LE(Http2RstStreamFields::EncodedSize(), b->Remaining()); |
+ out->error_code = static_cast<Http2ErrorCode>(b->DecodeUInt32()); |
+} |
+ |
+bool MaybeDecode(Http2RstStreamFields* out, DecodeBuffer* b) { |
+ DCHECK_NE(nullptr, out); |
+ DCHECK_NE(nullptr, b); |
+ if (b->Remaining() >= Http2RstStreamFields::EncodedSize()) { |
+ DoDecode(out, b); |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+bool SlowDecode(Http2RstStreamFields* out, DecodeBuffer* b, uint32_t* offset) { |
+ DCHECK_NE(nullptr, out); |
+ DCHECK_NE(nullptr, b); |
+ DCHECK_NE(nullptr, offset); |
+ DCHECK_GT(Http2RstStreamFields::EncodedSize(), *offset); |
+ |
+ if (b->SlowDecodeEnum(4 /* field_size */, 0 /* field_offset */, offset, |
+ &out->error_code)) { |
+ DCHECK_EQ(Http2RstStreamFields::EncodedSize(), *offset); |
+ return true; |
+ } |
+ DCHECK_GT(Http2RstStreamFields::EncodedSize(), *offset); |
+ return false; |
+} |
+ |
+// Http2SettingFields decoding: |
+ |
+void DoDecode(Http2SettingFields* out, DecodeBuffer* b) { |
+ DCHECK_NE(nullptr, out); |
+ DCHECK_NE(nullptr, b); |
+ DCHECK_LE(Http2SettingFields::EncodedSize(), b->Remaining()); |
+ out->parameter = static_cast<Http2SettingsParameter>(b->DecodeUInt16()); |
+ out->value = b->DecodeUInt32(); |
+} |
+ |
+bool MaybeDecode(Http2SettingFields* out, DecodeBuffer* b) { |
+ DCHECK_NE(nullptr, out); |
+ DCHECK_NE(nullptr, b); |
+ if (b->Remaining() >= Http2SettingFields::EncodedSize()) { |
+ DoDecode(out, b); |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+bool SlowDecode(Http2SettingFields* out, DecodeBuffer* b, uint32_t* offset) { |
+ DCHECK_NE(nullptr, out); |
+ DCHECK_NE(nullptr, b); |
+ DCHECK_NE(nullptr, offset); |
+ DCHECK_LT(*offset, Http2SettingFields::EncodedSize()); |
+ |
+ if (b->SlowDecodeEnum(2 /* field_size */, 0 /* field_offset */, offset, |
+ &out->parameter) && |
+ b->SlowDecodeUInt32(2 /* field_offset */, offset, &out->value)) { |
+ DCHECK_EQ(Http2SettingFields::EncodedSize(), *offset); |
+ return true; |
+ } |
+ DCHECK_LT(*offset, Http2SettingFields::EncodedSize()); |
+ return false; |
+} |
+ |
+// Http2PushPromiseFields decoding: |
+ |
+void DoDecode(Http2PushPromiseFields* out, DecodeBuffer* b) { |
+ DCHECK_NE(nullptr, out); |
+ DCHECK_NE(nullptr, b); |
+ DCHECK_LE(Http2PushPromiseFields::EncodedSize(), b->Remaining()); |
+ out->promised_stream_id = b->DecodeUInt31(); |
+} |
+ |
+bool MaybeDecode(Http2PushPromiseFields* out, DecodeBuffer* b) { |
+ DCHECK_NE(nullptr, out); |
+ DCHECK_NE(nullptr, b); |
+ if (b->Remaining() >= Http2PushPromiseFields::EncodedSize()) { |
+ DoDecode(out, b); |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+bool SlowDecode(Http2PushPromiseFields* out, |
+ DecodeBuffer* b, |
+ uint32_t* offset) { |
+ DCHECK_NE(nullptr, out); |
+ DCHECK_NE(nullptr, b); |
+ DCHECK_NE(nullptr, offset); |
+ DCHECK_LT(*offset, Http2PushPromiseFields::EncodedSize()); |
+ if (b->SlowDecodeUInt31(0 /* field_offset */, offset, |
+ &out->promised_stream_id)) { |
+ DCHECK_EQ(Http2PushPromiseFields::EncodedSize(), *offset); |
+ return true; |
+ } |
+ DCHECK_LT(*offset, Http2PushPromiseFields::EncodedSize()); |
+ return false; |
+} |
+ |
+// Http2PingFields decoding: |
+ |
+void DoDecode(Http2PingFields* out, DecodeBuffer* b) { |
+ DCHECK_NE(nullptr, out); |
+ DCHECK_NE(nullptr, b); |
+ DCHECK_LE(Http2PingFields::EncodedSize(), b->Remaining()); |
+ memcpy(out->opaque_data, b->cursor(), Http2PingFields::EncodedSize()); |
+ b->AdvanceCursor(Http2PingFields::EncodedSize()); |
+} |
+ |
+bool MaybeDecode(Http2PingFields* out, DecodeBuffer* b) { |
+ DCHECK_NE(nullptr, out); |
+ DCHECK_NE(nullptr, b); |
+ if (b->Remaining() >= Http2PingFields::EncodedSize()) { |
+ DoDecode(out, b); |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+bool SlowDecode(Http2PingFields* out, DecodeBuffer* b, uint32_t* offset) { |
+ DCHECK_NE(nullptr, out); |
+ DCHECK_NE(nullptr, b); |
+ DCHECK_NE(nullptr, offset); |
+ DCHECK_LT(*offset, Http2PingFields::EncodedSize()); |
+ while (*offset < Http2PingFields::EncodedSize()) { |
+ if (b->Empty()) { |
+ return false; |
+ } |
+ out->opaque_data[(*offset)++] = b->DecodeUInt8(); |
+ } |
+ return true; |
+} |
+ |
+// Http2GoAwayFields decoding: |
+ |
+void DoDecode(Http2GoAwayFields* out, DecodeBuffer* b) { |
+ DCHECK_NE(nullptr, out); |
+ DCHECK_NE(nullptr, b); |
+ DCHECK_LE(Http2GoAwayFields::EncodedSize(), b->Remaining()); |
+ out->last_stream_id = b->DecodeUInt31(); |
+ out->error_code = static_cast<Http2ErrorCode>(b->DecodeUInt32()); |
+} |
+ |
+bool MaybeDecode(Http2GoAwayFields* out, DecodeBuffer* b) { |
+ DCHECK_NE(nullptr, out); |
+ DCHECK_NE(nullptr, b); |
+ if (b->Remaining() >= Http2GoAwayFields::EncodedSize()) { |
+ DoDecode(out, b); |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+bool SlowDecode(Http2GoAwayFields* out, DecodeBuffer* b, uint32_t* offset) { |
+ DCHECK_NE(nullptr, out); |
+ DCHECK_NE(nullptr, b); |
+ DCHECK_NE(nullptr, offset); |
+ DCHECK_LT(*offset, Http2GoAwayFields::EncodedSize()); |
+ if (b->SlowDecodeUInt31(0 /* field_offset */, offset, &out->last_stream_id) && |
+ b->SlowDecodeEnum(4 /* field_size */, 4 /* field_offset */, offset, |
+ &out->error_code)) { |
+ DCHECK_EQ(Http2GoAwayFields::EncodedSize(), *offset); |
+ return true; |
+ } |
+ DCHECK_LT(*offset, Http2GoAwayFields::EncodedSize()); |
+ return false; |
+} |
+ |
+// Http2WindowUpdateFields decoding: |
+ |
+void DoDecode(Http2WindowUpdateFields* out, DecodeBuffer* b) { |
+ DCHECK_NE(nullptr, out); |
+ DCHECK_NE(nullptr, b); |
+ DCHECK_LE(Http2WindowUpdateFields::EncodedSize(), b->Remaining()); |
+ out->window_size_increment = b->DecodeUInt31(); |
+} |
+ |
+bool MaybeDecode(Http2WindowUpdateFields* out, DecodeBuffer* b) { |
+ DCHECK_NE(nullptr, out); |
+ DCHECK_NE(nullptr, b); |
+ if (b->Remaining() >= Http2WindowUpdateFields::EncodedSize()) { |
+ DoDecode(out, b); |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+bool SlowDecode(Http2WindowUpdateFields* out, |
+ DecodeBuffer* b, |
+ uint32_t* offset) { |
+ DCHECK_NE(nullptr, out); |
+ DCHECK_NE(nullptr, b); |
+ DCHECK_NE(nullptr, offset); |
+ DCHECK_LT(*offset, Http2WindowUpdateFields::EncodedSize()); |
+ if (b->SlowDecodeUInt31(0 /* field_offset */, offset, |
+ &out->window_size_increment)) { |
+ DCHECK_EQ(Http2WindowUpdateFields::EncodedSize(), *offset); |
+ return true; |
+ } |
+ DCHECK_LT(*offset, Http2WindowUpdateFields::EncodedSize()); |
+ return false; |
+} |
+ |
+// Http2AltSvcFields decoding: |
+ |
+void DoDecode(Http2AltSvcFields* out, DecodeBuffer* b) { |
+ DCHECK_NE(nullptr, out); |
+ DCHECK_NE(nullptr, b); |
+ DCHECK_LE(Http2AltSvcFields::EncodedSize(), b->Remaining()); |
+ out->origin_length = b->DecodeUInt16(); |
+} |
+ |
+bool MaybeDecode(Http2AltSvcFields* out, DecodeBuffer* b) { |
+ DCHECK_NE(nullptr, out); |
+ DCHECK_NE(nullptr, b); |
+ if (b->Remaining() >= Http2AltSvcFields::EncodedSize()) { |
+ DoDecode(out, b); |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+bool SlowDecode(Http2AltSvcFields* out, DecodeBuffer* b, uint32_t* offset) { |
+ DCHECK_NE(nullptr, out); |
+ DCHECK_NE(nullptr, b); |
+ DCHECK_NE(nullptr, offset); |
+ DCHECK_LT(*offset, Http2AltSvcFields::EncodedSize()); |
+ if (b->SlowDecodeUInt16(0 /* field_offset */, offset, &out->origin_length)) { |
+ DCHECK_EQ(Http2AltSvcFields::EncodedSize(), *offset); |
+ return true; |
+ } |
+ DCHECK_LT(*offset, Http2AltSvcFields::EncodedSize()); |
+ return false; |
+} |
+ |
+} // namespace net |