Home | History | Annotate | Download | only in websockets
      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 
     15 namespace net {
     16 
     17 class IOBuffer;
     18 class 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).
     24 struct 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).
     95 struct 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.
    125 struct 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.
    142 struct 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.
    149 NET_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|.
    167 NET_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.
    173 NET_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.
    187 NET_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