1// Copyright (c) 2012 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#ifndef NET_WEBSOCKETS_WEBSOCKET_FRAME_H_
6#define NET_WEBSOCKETS_WEBSOCKET_FRAME_H_
7
8#include <vector>
9
10#include "base/basictypes.h"
11#include "base/memory/ref_counted.h"
12#include "base/memory/scoped_ptr.h"
13#include "net/base/net_export.h"
14
15namespace net {
16
17class IOBuffer;
18class IOBufferWithSize;
19
20// Represents a WebSocket frame header.
21//
22// Members of this class correspond to each element in WebSocket frame header
23// (see http://tools.ietf.org/html/rfc6455#section-5.2).
24struct NET_EXPORT WebSocketFrameHeader {
25  typedef int OpCode;
26
27  // Originally these constants were static const int, but to make it possible
28  // to use them in a switch statement they were changed to an enum.
29  enum OpCodeEnum {
30    kOpCodeContinuation = 0x0,
31    kOpCodeText = 0x1,
32    kOpCodeBinary = 0x2,
33    kOpCodeDataUnused = 0x3,
34    kOpCodeClose = 0x8,
35    kOpCodePing = 0x9,
36    kOpCodePong = 0xA,
37    kOpCodeControlUnused = 0xB,
38  };
39
40  // Return true if |opcode| is one of the data opcodes known to this
41  // implementation.
42  static bool IsKnownDataOpCode(OpCode opcode) {
43    return opcode == kOpCodeContinuation || opcode == kOpCodeText ||
44           opcode == kOpCodeBinary;
45  }
46
47  // Return true if |opcode| is one of the control opcodes known to this
48  // implementation.
49  static bool IsKnownControlOpCode(OpCode opcode) {
50    return opcode == kOpCodeClose || opcode == kOpCodePing ||
51           opcode == kOpCodePong;
52  }
53
54  // These values must be a compile-time constant. "enum hack" is used here
55  // to make MSVC happy.
56  enum {
57    kBaseHeaderSize = 2,
58    kMaximumExtendedLengthSize = 8,
59    kMaskingKeyLength = 4
60  };
61
62  // Constructor to avoid a lot of repetitive initialisation.
63  explicit WebSocketFrameHeader(OpCode opCode)
64      : final(false),
65        reserved1(false),
66        reserved2(false),
67        reserved3(false),
68        opcode(opCode),
69        masked(false),
70        payload_length(0) {}
71
72  // Create a clone of this object on the heap.
73  scoped_ptr<WebSocketFrameHeader> Clone() const;
74
75  // Overwrite this object with the fields from |source|.
76  void CopyFrom(const WebSocketFrameHeader& source);
77
78  // Members below correspond to each item in WebSocket frame header.
79  // See <http://tools.ietf.org/html/rfc6455#section-5.2> for details.
80  bool final;
81  bool reserved1;
82  bool reserved2;
83  bool reserved3;
84  OpCode opcode;
85  bool masked;
86  uint64 payload_length;
87
88 private:
89  DISALLOW_COPY_AND_ASSIGN(WebSocketFrameHeader);
90};
91
92// Contains an entire WebSocket frame including payload. This is used by APIs
93// that are not concerned about retaining the original frame boundaries (because
94// frames may need to be split in order for the data to fit in memory).
95struct NET_EXPORT_PRIVATE WebSocketFrame {
96  // A frame must always have an opcode, so this parameter is compulsory.
97  explicit WebSocketFrame(WebSocketFrameHeader::OpCode opcode);
98  ~WebSocketFrame();
99
100  // |header| is always present.
101  WebSocketFrameHeader header;
102
103  // |data| is always unmasked even if the frame is masked. The size of |data|
104  // is given by |header.payload_length|.
105  scoped_refptr<IOBuffer> data;
106};
107
108// Structure describing one chunk of a WebSocket frame.
109//
110// The payload of a WebSocket frame may be divided into multiple chunks.
111// You need to look at |final_chunk| member variable to detect the end of a
112// series of chunk objects of a WebSocket frame.
113//
114// Frame dissection is necessary to handle frames that are too large to store in
115// the browser memory without losing information about the frame boundaries. In
116// practice, most code does not need to worry about the original frame
117// boundaries and can use the WebSocketFrame type declared above.
118//
119// Users of this struct should treat WebSocket frames as a data stream; it's
120// important to keep the frame data flowing, especially in the browser process.
121// Users should not let the data stuck somewhere in the pipeline.
122//
123// This struct is used for reading WebSocket frame data (created by
124// WebSocketFrameParser). To construct WebSocket frames, use functions below.
125struct NET_EXPORT WebSocketFrameChunk {
126  WebSocketFrameChunk();
127  ~WebSocketFrameChunk();
128
129  // Non-null |header| is provided only if this chunk is the first part of
130  // a series of chunks.
131  scoped_ptr<WebSocketFrameHeader> header;
132
133  // Indicates this part is the last chunk of a frame.
134  bool final_chunk;
135
136  // |data| is always unmasked even if the frame is masked. |data| might be
137  // null in the first chunk.
138  scoped_refptr<IOBufferWithSize> data;
139};
140
141// Contains four-byte data representing "masking key" of WebSocket frames.
142struct WebSocketMaskingKey {
143  char key[WebSocketFrameHeader::kMaskingKeyLength];
144};
145
146// Returns the size of WebSocket frame header. The size of WebSocket frame
147// header varies from 2 bytes to 14 bytes depending on the payload length
148// and maskedness.
149NET_EXPORT int GetWebSocketFrameHeaderSize(const WebSocketFrameHeader& header);
150
151// Writes wire format of a WebSocket frame header into |output|, and returns
152// the number of bytes written.
153//
154// WebSocket frame format is defined at:
155// <http://tools.ietf.org/html/rfc6455#section-5.2>. This function writes
156// everything but payload data in a WebSocket frame to |buffer|.
157//
158// If |header->masked| is true, |masking_key| must point to a valid
159// WebSocketMaskingKey object containing the masking key for that frame
160// (possibly generated by GenerateWebSocketMaskingKey() function below).
161// Otherwise, |masking_key| must be NULL.
162//
163// |buffer| should have enough size to contain the frame header.
164// GetWebSocketFrameHeaderSize() can be used to know the size of header
165// beforehand. If the size of |buffer| is insufficient, this function returns
166// ERR_INVALID_ARGUMENT and does not write any data to |buffer|.
167NET_EXPORT int WriteWebSocketFrameHeader(const WebSocketFrameHeader& header,
168                                         const WebSocketMaskingKey* masking_key,
169                                         char* buffer,
170                                         int buffer_size);
171
172// Generates a masking key suitable for use in a new WebSocket frame.
173NET_EXPORT WebSocketMaskingKey GenerateWebSocketMaskingKey();
174
175// Masks WebSocket frame payload.
176//
177// A client must mask every WebSocket frame by XOR'ing the frame payload
178// with four-byte random data (masking key). This function applies the masking
179// to the given payload data.
180//
181// This function masks |data| with |masking_key|, assuming |data| is partial
182// data starting from |frame_offset| bytes from the beginning of the payload
183// data.
184//
185// Since frame masking is a reversible operation, this function can also be
186// used for unmasking a WebSocket frame.
187NET_EXPORT void MaskWebSocketFramePayload(
188    const WebSocketMaskingKey& masking_key,
189    uint64 frame_offset,
190    char* data,
191    int data_size);
192
193}  // namespace net
194
195#endif  // NET_WEBSOCKETS_WEBSOCKET_FRAME_H_
196