summaryrefslogtreecommitdiff
path: root/chromium/net/spdy/alps_decoder.h
blob: 67bb7d84fd9c59a85d6c9caaa824a3fb0f73ca83 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef NET_SPDY_ALPS_DECODER_H_
#define NET_SPDY_ALPS_DECODER_H_

#include <cstddef>

#include "base/containers/span.h"
#include "base/strings/string_number_conversions.h"
#include "net/base/net_export.h"
#include "net/third_party/quiche/src/quiche/spdy/core/http2_frame_decoder_adapter.h"
#include "net/third_party/quiche/src/quiche/spdy/core/spdy_no_op_visitor.h"
#include "net/third_party/quiche/src/quiche/spdy/core/spdy_protocol.h"

namespace net {

// Class to parse HTTP/2 frames in the extension_data field
// of the ALPS TLS extension.
class NET_EXPORT_PRIVATE AlpsDecoder {
 public:
  // These values are persisted to logs. Entries should not be renumbered, and
  // numeric values should never be reused.
  enum class Error {
    // No error has occurred.
    kNoError = 0,
    // HTTP/2 framing error detected by Http2DecoderAdapter.
    kFramingError = 1,
    // Forbidden HTTP/2 frame received.
    kForbiddenFrame = 2,
    // Input does not end on HTTP/2 frame boundary.
    kNotOnFrameBoundary = 3,
    // SETTINGS frame with ACK received.
    kSettingsWithAck = 4,
    // ACCEPT_CH received on invalid stream.
    kAcceptChInvalidStream = 5,
    // ACCEPT_CH received with flags.
    kAcceptChWithFlags = 6,
    // Malformed ACCEPT_CH payload.
    kAcceptChMalformed = 7,
    kMaxValue = kAcceptChMalformed
  };

  AlpsDecoder();
  ~AlpsDecoder();

  // Decode a stream of HTTP/2 frames received via the ALPS TLS extension.
  // The HTTP/2 connection preface MUST NOT be present in the input.
  // Frames other than SETTINGS and ACCEPT_CH are ignored other than for the
  // purposes of enforcing HTTP/2 framing rules.
  // May only be called once, with the entire ALPS extension_data.
  // Returns an error code, or Error::kNoError if no error has occurred.
  // The requirement that the first frame MUST be SETTINGS is not enforced,
  // because that only applies to HTTP/2 connections, not ALPS data.
  [[nodiscard]] Error Decode(base::span<const char> data);

  // The number of SETTINGS frames received.
  int settings_frame_count() const;

  // The HTTP/2 setting parameters parsed from |data|.
  const spdy::SettingsMap& GetSettings() const {
    return settings_parser_.GetSettings();
  }
  // Origins and corresponding Accept-CH values parsed from |data|.  See
  // https://tools.ietf.org/html/draft-davidben-http-client-hint-reliability-02
  const std::vector<spdy::AcceptChOriginValuePair>& GetAcceptCh() const {
    return accept_ch_parser_.GetAcceptCh();
  }

 private:
  class SettingsParser : public spdy::SpdyNoOpVisitor {
   public:
    SettingsParser();
    ~SettingsParser() override;

    bool forbidden_frame_received() const { return forbidden_frame_received_; }
    bool settings_ack_received() const { return settings_ack_received_; }
    int settings_frame_count() const { return settings_frame_count_; }
    // Number of SETTINGS frames received.
    const spdy::SettingsMap& GetSettings() const { return settings_; }

    // SpdyFramerVisitorInterface overrides.
    void OnCommonHeader(spdy::SpdyStreamId stream_id,
                        size_t length,
                        uint8_t type,
                        uint8_t flags) override;
    void OnSettings() override;
    void OnSetting(spdy::SpdySettingsId id, uint32_t value) override;
    void OnSettingsAck() override;

   private:
    // True if a forbidden HTTP/2 frame has been received.
    bool forbidden_frame_received_ = false;
    // True if a SETTINGS frame with ACK flag has been received.
    bool settings_ack_received_ = false;
    // Number of SETTINGS frames received.
    int settings_frame_count_ = 0;
    // Accumulated setting parameters.
    spdy::SettingsMap settings_;
  };

  // Class to parse ACCEPT_CH frames.
  class AcceptChParser : public spdy::ExtensionVisitorInterface {
   public:
    AcceptChParser();
    ~AcceptChParser() override;

    const std::vector<spdy::AcceptChOriginValuePair>& GetAcceptCh() const {
      return accept_ch_;
    }

    // Returns an error code, or Error::kNoError if no error has occurred.
    Error error() const { return error_; }

    // ExtensionVisitorInterface implementation.

    // Settings are parsed in a SpdyFramerVisitorInterface implementation,
    // because ExtensionVisitorInterface does not provide information about
    // receiving an empty SETTINGS frame.
    void OnSetting(spdy::SpdySettingsId id, uint32_t value) override {}

    bool OnFrameHeader(spdy::SpdyStreamId stream_id,
                       size_t length,
                       uint8_t type,
                       uint8_t flags) override;
    void OnFramePayload(const char* data, size_t len) override;

   private:
    // Accumulated ACCEPT_CH values.
    std::vector<spdy::AcceptChOriginValuePair> accept_ch_;

    Error error_ = Error::kNoError;
  };

  SettingsParser settings_parser_;
  AcceptChParser accept_ch_parser_;
  http2::Http2DecoderAdapter decoder_adapter_;
};

}  // namespace net

#endif  // NET_SPDY_ALPS_DECODER_H_