summaryrefslogtreecommitdiff
path: root/chromium/net/third_party/quiche/src/spdy/core/spdy_frame_builder.h
blob: 01fce6be819dfd476dc2a9fc47a580d1efc4ff32 (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
144
145
146
// Copyright (c) 2012 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.

#ifndef QUICHE_SPDY_CORE_SPDY_FRAME_BUILDER_H_
#define QUICHE_SPDY_CORE_SPDY_FRAME_BUILDER_H_

#include <cstddef>
#include <cstdint>
#include <memory>

#include "absl/strings/string_view.h"
#include "common/platform/api/quiche_export.h"
#include "common/quiche_endian.h"
#include "spdy/core/spdy_protocol.h"
#include "spdy/core/zero_copy_output_buffer.h"
#include "spdy/platform/api/spdy_bug_tracker.h"

namespace spdy {

namespace test {
class SpdyFrameBuilderPeer;
}  // namespace test

// This class provides facilities for basic binary value packing
// into Spdy frames.
//
// The SpdyFrameBuilder supports appending primitive values (int, string, etc)
// to a frame instance.  The SpdyFrameBuilder grows its internal memory buffer
// dynamically to hold the sequence of primitive values.   The internal memory
// buffer is exposed as the "data" of the SpdyFrameBuilder.
class QUICHE_EXPORT_PRIVATE SpdyFrameBuilder {
 public:
  // Initializes a SpdyFrameBuilder with a buffer of given size
  explicit SpdyFrameBuilder(size_t size);
  // Doesn't take ownership of output.
  SpdyFrameBuilder(size_t size, ZeroCopyOutputBuffer* output);

  ~SpdyFrameBuilder();

  // Returns the total size of the SpdyFrameBuilder's data, which may include
  // multiple frames.
  size_t length() const { return offset_ + length_; }

  // Seeks forward by the given number of bytes. Useful in conjunction with
  // GetWriteableBuffer() above.
  bool Seek(size_t length);

  // Populates this frame with a HTTP2 frame prefix using length information
  // from |capacity_|. The given type must be a control frame type.
  bool BeginNewFrame(SpdyFrameType type, uint8_t flags, SpdyStreamId stream_id);

  // Populates this frame with a HTTP2 frame prefix with type and length
  // information.  |type| must be a defined frame type.
  bool BeginNewFrame(SpdyFrameType type,
                     uint8_t flags,
                     SpdyStreamId stream_id,
                     size_t length);

  // Populates this frame with a HTTP2 frame prefix with type and length
  // information.  |raw_frame_type| may be a defined or undefined frame type.
  bool BeginNewUncheckedFrame(uint8_t raw_frame_type,
                              uint8_t flags,
                              SpdyStreamId stream_id,
                              size_t length);

  // Takes the buffer from the SpdyFrameBuilder.
  SpdySerializedFrame take() {
    SPDY_BUG_IF(spdy_bug_39_1, output_ != nullptr)
        << "ZeroCopyOutputBuffer is used to build "
        << "frames. take() shouldn't be called";
    SPDY_BUG_IF(spdy_bug_39_2, kMaxFrameSizeLimit < length_)
        << "Frame length " << length_
        << " is longer than the maximum possible allowed length.";
    SpdySerializedFrame rv(buffer_.release(), length(), true);
    capacity_ = 0;
    length_ = 0;
    offset_ = 0;
    return rv;
  }

  // Methods for adding to the payload.  These values are appended to the end
  // of the SpdyFrameBuilder payload. Note - binary integers are converted from
  // host to network form.
  bool WriteUInt8(uint8_t value) { return WriteBytes(&value, sizeof(value)); }
  bool WriteUInt16(uint16_t value) {
    value = quiche::QuicheEndian::HostToNet16(value);
    return WriteBytes(&value, sizeof(value));
  }
  bool WriteUInt24(uint32_t value) {
    value = quiche::QuicheEndian::HostToNet32(value);
    return WriteBytes(reinterpret_cast<char*>(&value) + 1, sizeof(value) - 1);
  }
  bool WriteUInt32(uint32_t value) {
    value = quiche::QuicheEndian::HostToNet32(value);
    return WriteBytes(&value, sizeof(value));
  }
  bool WriteUInt64(uint64_t value) {
    uint32_t upper =
        quiche::QuicheEndian::HostToNet32(static_cast<uint32_t>(value >> 32));
    uint32_t lower =
        quiche::QuicheEndian::HostToNet32(static_cast<uint32_t>(value));
    return (WriteBytes(&upper, sizeof(upper)) &&
            WriteBytes(&lower, sizeof(lower)));
  }
  bool WriteStringPiece32(const absl::string_view value);
  bool WriteBytes(const void* data, uint32_t data_len);

 private:
  friend class test::SpdyFrameBuilderPeer;

  // Populates this frame with a HTTP2 frame prefix with type and length
  // information.
  bool BeginNewFrameInternal(uint8_t raw_frame_type,
                             uint8_t flags,
                             SpdyStreamId stream_id,
                             size_t length);

  // Returns a writeable buffer of given size in bytes, to be appended to the
  // currently written frame. Does bounds checking on length but does not
  // increment the underlying iterator. To do so, consumers should subsequently
  // call Seek().
  // In general, consumers should use Write*() calls instead of this.
  // Returns NULL on failure.
  char* GetWritableBuffer(size_t length);
  char* GetWritableOutput(size_t desired_length, size_t* actual_length);

  // Checks to make sure that there is an appropriate amount of space for a
  // write of given size, in bytes.
  bool CanWrite(size_t length) const;

  // A buffer to be created whenever a new frame needs to be written. Used only
  // if |output_| is nullptr.
  std::unique_ptr<char[]> buffer_;
  // A pre-allocated buffer. If not-null, serialized frame data is written to
  // this buffer.
  ZeroCopyOutputBuffer* output_ = nullptr;  // Does not own.

  size_t capacity_;  // Allocation size of payload, set by constructor.
  size_t length_;    // Length of the latest frame in the buffer.
  size_t offset_;    // Position at which the latest frame begins.
};

}  // namespace spdy

#endif  // QUICHE_SPDY_CORE_SPDY_FRAME_BUILDER_H_