1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "quiche/http2/decoder/payload_decoders/settings_payload_decoder.h"
6 
7 #include "quiche/http2/decoder/decode_buffer.h"
8 #include "quiche/http2/decoder/http2_frame_decoder_listener.h"
9 #include "quiche/http2/http2_constants.h"
10 #include "quiche/http2/http2_structures.h"
11 #include "quiche/common/platform/api/quiche_logging.h"
12 
13 namespace http2 {
14 
StartDecodingPayload(FrameDecoderState * state,DecodeBuffer * db)15 DecodeStatus SettingsPayloadDecoder::StartDecodingPayload(
16     FrameDecoderState* state, DecodeBuffer* db) {
17   const Http2FrameHeader& frame_header = state->frame_header();
18   const uint32_t total_length = frame_header.payload_length;
19 
20   QUICHE_DVLOG(2) << "SettingsPayloadDecoder::StartDecodingPayload: "
21                   << frame_header;
22   QUICHE_DCHECK_EQ(Http2FrameType::SETTINGS, frame_header.type);
23   QUICHE_DCHECK_LE(db->Remaining(), total_length);
24   QUICHE_DCHECK_EQ(0, frame_header.flags & ~(Http2FrameFlag::ACK));
25 
26   if (frame_header.IsAck()) {
27     if (total_length == 0) {
28       state->listener()->OnSettingsAck(frame_header);
29       return DecodeStatus::kDecodeDone;
30     } else {
31       state->InitializeRemainders();
32       return state->ReportFrameSizeError();
33     }
34   } else {
35     state->InitializeRemainders();
36     state->listener()->OnSettingsStart(frame_header);
37     return StartDecodingSettings(state, db);
38   }
39 }
40 
ResumeDecodingPayload(FrameDecoderState * state,DecodeBuffer * db)41 DecodeStatus SettingsPayloadDecoder::ResumeDecodingPayload(
42     FrameDecoderState* state, DecodeBuffer* db) {
43   QUICHE_DVLOG(2) << "SettingsPayloadDecoder::ResumeDecodingPayload"
44                   << "  remaining_payload=" << state->remaining_payload()
45                   << "  db->Remaining=" << db->Remaining();
46   QUICHE_DCHECK_EQ(Http2FrameType::SETTINGS, state->frame_header().type);
47   QUICHE_DCHECK_LE(db->Remaining(), state->frame_header().payload_length);
48 
49   DecodeStatus status =
50       state->ResumeDecodingStructureInPayload(&setting_fields_, db);
51   if (status == DecodeStatus::kDecodeDone) {
52     state->listener()->OnSetting(setting_fields_);
53     return StartDecodingSettings(state, db);
54   }
55   return HandleNotDone(state, db, status);
56 }
57 
StartDecodingSettings(FrameDecoderState * state,DecodeBuffer * db)58 DecodeStatus SettingsPayloadDecoder::StartDecodingSettings(
59     FrameDecoderState* state, DecodeBuffer* db) {
60   QUICHE_DVLOG(2) << "SettingsPayloadDecoder::StartDecodingSettings"
61                   << "  remaining_payload=" << state->remaining_payload()
62                   << "  db->Remaining=" << db->Remaining();
63   while (state->remaining_payload() > 0) {
64     DecodeStatus status =
65         state->StartDecodingStructureInPayload(&setting_fields_, db);
66     if (status == DecodeStatus::kDecodeDone) {
67       state->listener()->OnSetting(setting_fields_);
68       continue;
69     }
70     return HandleNotDone(state, db, status);
71   }
72   QUICHE_DVLOG(2) << "LEAVING SettingsPayloadDecoder::StartDecodingSettings"
73                   << "\n\tdb->Remaining=" << db->Remaining()
74                   << "\n\t remaining_payload=" << state->remaining_payload();
75   state->listener()->OnSettingsEnd();
76   return DecodeStatus::kDecodeDone;
77 }
78 
HandleNotDone(FrameDecoderState * state,DecodeBuffer * db,DecodeStatus status)79 DecodeStatus SettingsPayloadDecoder::HandleNotDone(FrameDecoderState* state,
80                                                    DecodeBuffer* db,
81                                                    DecodeStatus status) {
82   // Not done decoding the structure. Either we've got more payload to decode,
83   // or we've run out because the payload is too short, in which case
84   // OnFrameSizeError will have already been called.
85   QUICHE_DCHECK(
86       (status == DecodeStatus::kDecodeInProgress &&
87        state->remaining_payload() > 0) ||
88       (status == DecodeStatus::kDecodeError && state->remaining_payload() == 0))
89       << "\n status=" << status
90       << "; remaining_payload=" << state->remaining_payload()
91       << "; db->Remaining=" << db->Remaining();
92   return status;
93 }
94 
95 }  // namespace http2
96