testing/xpcshell/node-http2/node_modules/http2-protocol/lib/framer.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 // The framer consists of two [Transform Stream][1] subclasses that operate in [object mode][2]:
     2 // the Serializer and the Deserializer
     3 // [1]: http://nodejs.org/api/stream.html#stream_class_stream_transform
     4 // [2]: http://nodejs.org/api/stream.html#stream_new_stream_readable_options
     5 var assert = require('assert');
     7 var Transform = require('stream').Transform;
     9 exports.Serializer = Serializer;
    10 exports.Deserializer = Deserializer;
    12 var logData = Boolean(process.env.HTTP2_LOG_DATA);
    14 var MAX_PAYLOAD_SIZE = 16383;
    16 // Serializer
    17 // ----------
    18 //
    19 //     Frame Objects
    20 //     * * * * * * * --+---------------------------
    21 //                     |                          |
    22 //                     v                          v           Buffers
    23 //      [] -----> Payload Ser. --[buffers]--> Header Ser. --> * * * *
    24 //     empty      adds payload                adds header
    25 //     array        buffers                     buffer
    27 function Serializer(log, sizeLimit) {
    28   this._log = log.child({ component: 'serializer' });
    29   this._sizeLimit = sizeLimit || MAX_PAYLOAD_SIZE;
    30   Transform.call(this, { objectMode: true });
    31 }
    32 Serializer.prototype = Object.create(Transform.prototype, { constructor: { value: Serializer } });
    34 // When there's an incoming frame object, it first generates the frame type specific part of the
    35 // frame (payload), and then then adds the header part which holds fields that are common to all
    36 // frame types (like the length of the payload).
    37 Serializer.prototype._transform = function _transform(frame, encoding, done) {
    38   this._log.trace({ frame: frame }, 'Outgoing frame');
    40   assert(frame.type in Serializer, 'Unknown frame type: ' + frame.type);
    42   var buffers = [];
    43   Serializer[frame.type](frame, buffers);
    44   Serializer.commonHeader(frame, buffers);
    46   assert(buffers[0].readUInt16BE(0) <= this._sizeLimit, 'Frame too large!');
    48   for (var i = 0; i < buffers.length; i++) {
    49     if (logData) {
    50       this._log.trace({ data: buffers[i] }, 'Outgoing data');
    51     }
    52     this.push(buffers[i]);
    53   }
    55   done();
    56 };
    58 // Deserializer
    59 // ------------
    60 //
    61 //     Buffers
    62 //     * * * * --------+-------------------------
    63 //                     |                        |
    64 //                     v                        v           Frame Objects
    65 //      {} -----> Header Des. --{frame}--> Payload Des. --> * * * * * * *
    66 //     empty      adds parsed              adds parsed
    67 //     object  header properties        payload properties
    69 function Deserializer(log, sizeLimit, role) {
    70   this._role = role;
    71   this._log = log.child({ component: 'deserializer' });
    72   this._sizeLimit = sizeLimit || MAX_PAYLOAD_SIZE;
    73   Transform.call(this, { objectMode: true });
    74   this._next(COMMON_HEADER_SIZE);
    75 }
    76 Deserializer.prototype = Object.create(Transform.prototype, { constructor: { value: Deserializer } });
    78 // The Deserializer is stateful, and it's two main alternating states are: *waiting for header* and
    79 // *waiting for payload*. The state is stored in the boolean property `_waitingForHeader`.
    80 //
    81 // When entering a new state, a `_buffer` is created that will hold the accumulated data (header or
    82 // payload). The `_cursor` is used to track the progress.
    83 Deserializer.prototype._next = function(size) {
    84   this._cursor = 0;
    85   this._buffer = new Buffer(size);
    86   this._waitingForHeader = !this._waitingForHeader;
    87   if (this._waitingForHeader) {
    88     this._frame = {};
    89   }
    90 };
    92 // Parsing an incoming buffer is an iterative process because it can hold multiple frames if it's
    93 // large enough. A `cursor` is used to track the progress in parsing the incoming `chunk`.
    94 Deserializer.prototype._transform = function _transform(chunk, encoding, done) {
    95   var cursor = 0;
    97   if (logData) {
    98     this._log.trace({ data: chunk }, 'Incoming data');
    99   }
   101   while(cursor < chunk.length) {
   102     // The content of an incoming buffer is first copied to `_buffer`. If it can't hold the full
   103     // chunk, then only a part of it is copied.
   104     var toCopy = Math.min(chunk.length - cursor, this._buffer.length - this._cursor);
   105     chunk.copy(this._buffer, this._cursor, cursor, cursor + toCopy);
   106     this._cursor += toCopy;
   107     cursor += toCopy;
   109     // When `_buffer` is full, it's content gets parsed either as header or payload depending on
   110     // the actual state.
   112     // If it's header then the parsed data is stored in a temporary variable and then the
   113     // deserializer waits for the specified length payload.
   114     if ((this._cursor === this._buffer.length) && this._waitingForHeader) {
   115       var payloadSize = Deserializer.commonHeader(this._buffer, this._frame);
   116       if (payloadSize <= this._sizeLimit) {
   117         this._next(payloadSize);
   118       } else {
   119         this.emit('error', 'FRAME_SIZE_ERROR');
   120         return;
   121       }
   122     }
   124     // If it's payload then the the frame object is finalized and then gets pushed out.
   125     // Unknown frame types are ignored.
   126     //
   127     // Note: If we just finished the parsing of a header and the payload length is 0, this branch
   128     // will also run.
   129     if ((this._cursor === this._buffer.length) && !this._waitingForHeader) {
   130       if (this._frame.type) {
   131         var error = Deserializer[this._frame.type](this._buffer, this._frame, this._role);
   132         if (error) {
   133           this._log.error('Incoming frame parsing error: ' + error);
   134           this.emit('error', 'PROTOCOL_ERROR');
   135         } else {
   136           this._log.trace({ frame: this._frame }, 'Incoming frame');
   137           this.push(this._frame);
   138         }
   139       } else {
   140         this._log.error('Unknown type incoming frame');
   141         this.emit('error', 'PROTOCOL_ERROR');
   142       }
   143       this._next(COMMON_HEADER_SIZE);
   144     }
   145   }
   147   done();
   148 };
   150 // [Frame Header](http://tools.ietf.org/html/draft-ietf-httpbis-http2-10#section-4.1)
   151 // --------------------------------------------------------------
   152 //
   153 // HTTP/2.0 frames share a common base format consisting of an 8-byte header followed by 0 to 65535
   154 // bytes of data.
   155 //
   156 // Additional size limits can be set by specific application uses. HTTP limits the frame size to
   157 // 16,383 octets.
   158 //
   159 //      0                   1                   2                   3
   160 //      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   161 //     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   162 //     | R |     Length (14)           |   Type (8)    |   Flags (8)   |
   163 //     +-+-+---------------------------+---------------+---------------+
   164 //     |R|                 Stream Identifier (31)                      |
   165 //     +-+-------------------------------------------------------------+
   166 //     |                     Frame Data (0...)                       ...
   167 //     +---------------------------------------------------------------+
   168 //
   169 // The fields of the frame header are defined as:
   170 //
   171 // * R:
   172 //   A reserved 2-bit field. The semantics of these bits are undefined and the bits MUST remain
   173 //   unset (0) when sending and MUST be ignored when receiving.
   174 //
   175 // * Length:
   176 //   The length of the frame data expressed as an unsigned 14-bit integer. The 8 bytes of the frame
   177 //   header are not included in this value.
   178 //
   179 // * Type:
   180 //   The 8-bit type of the frame. The frame type determines how the remainder of the frame header
   181 //   and data are interpreted. Implementations MUST ignore unsupported and unrecognized frame types.
   182 //
   183 // * Flags:
   184 //   An 8-bit field reserved for frame-type specific boolean flags.
   185 //
   186 //   Flags are assigned semantics specific to the indicated frame type. Flags that have no defined
   187 //   semantics for a particular frame type MUST be ignored, and MUST be left unset (0) when sending.
   188 //
   189 // * R:
   190 //   A reserved 1-bit field. The semantics of this bit are undefined and the bit MUST remain unset
   191 //   (0) when sending and MUST be ignored when receiving.
   192 //
   193 // * Stream Identifier:
   194 //   A 31-bit stream identifier. The value 0 is reserved for frames that are associated with the
   195 //   connection as a whole as opposed to an individual stream.
   196 //
   197 // The structure and content of the remaining frame data is dependent entirely on the frame type.
   199 var COMMON_HEADER_SIZE = 8;
   201 var frameTypes = [];
   203 var frameFlags = {};
   205 var genericAttributes = ['type', 'flags', 'stream'];
   207 var typeSpecificAttributes = {};
   209 Serializer.commonHeader = function writeCommonHeader(frame, buffers) {
   210   var headerBuffer = new Buffer(COMMON_HEADER_SIZE);
   212   var size = 0;
   213   for (var i = 0; i < buffers.length; i++) {
   214     size += buffers[i].length;
   215   }
   216   headerBuffer.writeUInt16BE(size, 0);
   218   var typeId = frameTypes.indexOf(frame.type);  // If we are here then the type is valid for sure
   219   headerBuffer.writeUInt8(typeId, 2);
   221   var flagByte = 0;
   222   for (var flag in frame.flags) {
   223     var position = frameFlags[frame.type].indexOf(flag);
   224     assert(position !== -1, 'Unknown flag for frame type ' + frame.type + ': ' + flag);
   225     if (frame.flags[flag]) {
   226       flagByte |= (1 << position);
   227     }
   228   }
   229   headerBuffer.writeUInt8(flagByte, 3);
   231   assert((0 <= frame.stream) && (frame.stream < 0x7fffffff), frame.stream);
   232   headerBuffer.writeUInt32BE(frame.stream || 0, 4);
   234   buffers.unshift(headerBuffer);
   235 };
   237 Deserializer.commonHeader = function readCommonHeader(buffer, frame) {
   238   var length = buffer.readUInt16BE(0);
   240   frame.type = frameTypes[buffer.readUInt8(2)];
   242   frame.flags = {};
   243   var flagByte = buffer.readUInt8(3);
   244   var definedFlags = frameFlags[frame.type];
   245   for (var i = 0; i < definedFlags.length; i++) {
   246     frame.flags[definedFlags[i]] = Boolean(flagByte & (1 << i));
   247   }
   249   frame.stream = buffer.readUInt32BE(4) & 0x7fffffff;
   251   return length;
   252 };
   254 // Frame types
   255 // ===========
   257 // Every frame type is registered in the following places:
   258 //
   259 // * `frameTypes`: a register of frame type codes (used by `commonHeader()`)
   260 // * `frameFlags`: a register of valid flags for frame types (used by `commonHeader()`)
   261 // * `typeSpecificAttributes`: a register of frame specific frame object attributes (used by
   262 //   logging code and also serves as documentation for frame objects)
   264 // [DATA Frames](http://tools.ietf.org/html/draft-ietf-httpbis-http2-10#section-6.1)
   265 // ------------------------------------------------------------
   266 //
   267 // DATA frames (type=0x0) convey arbitrary, variable-length sequences of octets associated with a
   268 // stream.
   269 //
   270 // The DATA frame defines the following flags:
   271 //
   272 // * END_STREAM (0x1):
   273 //   Bit 1 being set indicates that this frame is the last that the endpoint will send for the
   274 //   identified stream.
   275 // * END_SEGMENT (0x2):
   276 //   Bit 2 being set indicates that this frame is the last for the current segment. Intermediaries
   277 //   MUST NOT coalesce frames across a segment boundary and MUST preserve segment boundaries when
   278 //   forwarding frames.
   279 // * PAD_LOW (0x10):
   280 //   Bit 5 being set indicates that the Pad Low field is present.
   281 // * PAD_HIGH (0x20):
   282 //   Bit 6 being set indicates that the Pad High field is present. This bit MUST NOT be set unless
   283 //   the PAD_LOW flag is also set. Endpoints that receive a frame with PAD_HIGH set and PAD_LOW
   284 //   cleared MUST treat this as a connection error of type PROTOCOL_ERROR.
   286 frameTypes[0x0] = 'DATA';
   288 frameFlags.DATA = ['END_STREAM', 'END_SEGMENT', 'RESERVED4', 'RESERVED8', 'PAD_LOW', 'PAD_HIGH'];
   290 typeSpecificAttributes.DATA = ['data'];
   292 Serializer.DATA = function writeData(frame, buffers) {
   293   buffers.push(frame.data);
   294 };
   296 Deserializer.DATA = function readData(buffer, frame) {
   297   var dataOffset = 0;
   298   var paddingLength = 0;
   299   if (frame.flags.PAD_LOW) {
   300     if (frame.flags.PAD_HIGH) {
   301       paddingLength = (buffer.readUInt8(dataOffset) & 0xff) * 256;
   302       dataOffset += 1;
   303     }
   304     paddingLength += (buffer.readUInt8(dataOffset) & 0xff);
   305     dataOffset += 1;
   306   } else if (frame.flags.PAD_HIGH) {
   307     return 'DATA frame got PAD_HIGH without PAD_LOW';
   308   }
   309   if (paddingLength) {
   310     frame.data = buffer.slice(dataOffset, -1 * paddingLength);
   311   } else {
   312     frame.data = buffer.slice(dataOffset);
   313   }
   314 };
   316 // [HEADERS](http://tools.ietf.org/html/draft-ietf-httpbis-http2-10#section-6.2)
   317 // --------------------------------------------------------------
   318 //
   319 // The HEADERS frame (type=0x1) allows the sender to create a stream.
   320 //
   321 // The HEADERS frame defines the following flags:
   322 //
   323 // * END_STREAM (0x1):
   324 //   Bit 1 being set indicates that this frame is the last that the endpoint will send for the
   325 //   identified stream.
   326 // * END_SEGMENT (0x2):
   327 //   Bit 2 being set indicates that this frame is the last for the current segment. Intermediaries
   328 //   MUST NOT coalesce frames across a segment boundary and MUST preserve segment boundaries when
   329 //   forwarding frames.
   330 // * END_HEADERS (0x4):
   331 //   The END_HEADERS bit indicates that this frame contains the entire payload necessary to provide
   332 //   a complete set of headers.
   333 // * PRIORITY (0x8):
   334 //   Bit 4 being set indicates that the first four octets of this frame contain a single reserved
   335 //   bit and a 31-bit priority.
   336 // * PAD_LOW (0x10):
   337 //   Bit 5 being set indicates that the Pad Low field is present.
   338 // * PAD_HIGH (0x20):
   339 //   Bit 6 being set indicates that the Pad High field is present. This bit MUST NOT be set unless
   340 //   the PAD_LOW flag is also set. Endpoints that receive a frame with PAD_HIGH set and PAD_LOW
   341 //   cleared MUST treat this as a connection error of type PROTOCOL_ERROR.
   343 frameTypes[0x1] = 'HEADERS';
   345 frameFlags.HEADERS = ['END_STREAM', 'END_SEGMENT', 'END_HEADERS', 'PRIORITY', 'PAD_LOW', 'PAD_HIGH'];
   347 typeSpecificAttributes.HEADERS = ['priority', 'headers', 'data'];
   349 //      0                   1                   2                   3
   350 //      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   351 //     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   352 //     |X|               (Optional) Priority (31)                      |
   353 //     +-+-------------------------------------------------------------+
   354 //     |                    Header Block (*)                         ...
   355 //     +---------------------------------------------------------------+
   356 //
   357 // The payload of a HEADERS frame contains a Headers Block
   359 Serializer.HEADERS = function writeHeadersPriority(frame, buffers) {
   360   if (frame.flags.PRIORITY) {
   361     var buffer = new Buffer(4);
   362     assert((0 <= frame.priority) && (frame.priority <= 0xffffffff), frame.priority);
   363     buffer.writeUInt32BE(frame.priority, 0);
   364     buffers.push(buffer);
   365   }
   366   buffers.push(frame.data);
   367 };
   369 Deserializer.HEADERS = function readHeadersPriority(buffer, frame) {
   370   var dataOffset = 0;
   371   var paddingLength = 0;
   372   if (frame.flags.PAD_LOW) {
   373     if (frame.flags.PAD_HIGH) {
   374       paddingLength = (buffer.readUInt8(dataOffset) & 0xff) * 256;
   375       dataOffset += 1;
   376     }
   377     paddingLength += (buffer.readUInt8(dataOffset) & 0xff);
   378     dataOffset += 1;
   379   } else if (frame.flags.PAD_HIGH) {
   380     return 'HEADERS frame got PAD_HIGH without PAD_LOW';
   381   }
   382   if (frame.flags.PRIORITY) {
   383     frame.priority = buffer.readUInt32BE(dataOffset) & 0x7fffffff;
   384     dataOffset += 4;
   385   }
   386   if (paddingLength) {
   387     frame.data = buffer.slice(dataOffset, -1 * paddingLength);
   388   } else {
   389     frame.data = buffer.slice(dataOffset);
   390   }
   391 };
   393 // [PRIORITY](http://tools.ietf.org/html/draft-ietf-httpbis-http2-10#section-6.3)
   394 // -------------------------------------------------------
   395 //
   396 // The PRIORITY frame (type=0x2) specifies the sender-advised priority of a stream.
   397 //
   398 // The PRIORITY frame does not define any flags.
   400 frameTypes[0x2] = 'PRIORITY';
   402 frameFlags.PRIORITY = [];
   404 typeSpecificAttributes.PRIORITY = ['priority'];
   406 //      0                   1                   2                   3
   407 //      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   408 //     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   409 //     |X|                   Priority (31)                             |
   410 //     +-+-------------------------------------------------------------+
   411 //
   412 // The payload of a PRIORITY frame contains a single reserved bit and a 31-bit priority.
   414 Serializer.PRIORITY = function writePriority(frame, buffers) {
   415   var buffer = new Buffer(4);
   416   buffer.writeUInt32BE(frame.priority, 0);
   417   buffers.push(buffer);
   418 };
   420 Deserializer.PRIORITY = function readPriority(buffer, frame) {
   421   frame.priority = buffer.readUInt32BE(0);
   422 };
   424 // [RST_STREAM](http://tools.ietf.org/html/draft-ietf-httpbis-http2-10#section-6.4)
   425 // -----------------------------------------------------------
   426 //
   427 // The RST_STREAM frame (type=0x3) allows for abnormal termination of a stream.
   428 //
   429 // No type-flags are defined.
   431 frameTypes[0x3] = 'RST_STREAM';
   433 frameFlags.RST_STREAM = [];
   435 typeSpecificAttributes.RST_STREAM = ['error'];
   437 //      0                   1                   2                   3
   438 //      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   439 //     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   440 //     |                         Error Code (32)                       |
   441 //     +---------------------------------------------------------------+
   442 //
   443 // The RST_STREAM frame contains a single unsigned, 32-bit integer identifying the error
   444 // code (see Error Codes). The error code indicates why the stream is being terminated.
   446 Serializer.RST_STREAM = function writeRstStream(frame, buffers) {
   447   var buffer = new Buffer(4);
   448   var code = errorCodes.indexOf(frame.error);
   449   assert((0 <= code) && (code <= 0xffffffff), code);
   450   buffer.writeUInt32BE(code, 0);
   451   buffers.push(buffer);
   452 };
   454 Deserializer.RST_STREAM = function readRstStream(buffer, frame) {
   455   frame.error = errorCodes[buffer.readUInt32BE(0)];
   456 };
   458 // [SETTINGS](http://tools.ietf.org/html/draft-ietf-httpbis-http2-10#section-6.5)
   459 // -------------------------------------------------------
   460 //
   461 // The SETTINGS frame (type=0x4) conveys configuration parameters that affect how endpoints
   462 // communicate.
   463 //
   464 // The SETTINGS frame defines the following flag:
   466 // * ACK (0x1):
   467 //   Bit 1 being set indicates that this frame acknowledges receipt and application of the peer's
   468 //   SETTINGS frame.
   469 frameTypes[0x4] = 'SETTINGS';
   471 frameFlags.SETTINGS = ['ACK'];
   473 typeSpecificAttributes.SETTINGS = ['settings'];
   475 // The payload of a SETTINGS frame consists of zero or more settings. Each setting consists of an
   476 // 8-bit identifier, and an unsigned 32-bit value.
   477 //
   478 //      0                   1                   2                   3
   479 //      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   480 //     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   481 //     |  Identifier(8)  |                  Value (32)                 |
   482 //     +-----------------+---------------------------------------------+
   483 //     ...Value          |
   484 //     +-----------------+
   485 //
   486 // Each setting in a SETTINGS frame replaces the existing value for that setting.  Settings are
   487 // processed in the order in which they appear, and a receiver of a SETTINGS frame does not need to
   488 // maintain any state other than the current value of settings.  Therefore, the value of a setting
   489 // is the last value that is seen by a receiver. This permits the inclusion of the same settings
   490 // multiple times in the same SETTINGS frame, though doing so does nothing other than waste
   491 // connection capacity.
   493 Serializer.SETTINGS = function writeSettings(frame, buffers) {
   494   var settings = [], settingsLeft = Object.keys(frame.settings);
   495   definedSettings.forEach(function(setting, id) {
   496     if (setting.name in frame.settings) {
   497       settingsLeft.splice(settingsLeft.indexOf(setting.name), 1);
   498       var value = frame.settings[setting.name];
   499       settings.push({ id: id, value: setting.flag ? Boolean(value) : value });
   500     }
   501   });
   502   assert(settingsLeft.length === 0, 'Unknown settings: ' + settingsLeft.join(', '));
   504   var buffer = new Buffer(settings.length * 5);
   505   for (var i = 0; i < settings.length; i++) {
   506     buffer.writeUInt8(settings[i].id & 0xff, i*5);
   507     buffer.writeUInt32BE(settings[i].value, i*5 + 1);
   508   }
   510   buffers.push(buffer);
   511 };
   513 Deserializer.SETTINGS = function readSettings(buffer, frame, role) {
   514   frame.settings = {};
   516   if (buffer.length % 5 !== 0) {
   517     return 'Invalid SETTINGS frame';
   518   }
   519   for (var i = 0; i < buffer.length / 5; i++) {
   520     var id = buffer.readUInt8(i*5) & 0xff;
   521     var setting = definedSettings[id];
   522     if (setting) {
   523       if (role == 'CLIENT' && setting.name == 'SETTINGS_ENABLE_PUSH') {
   524         return 'SETTINGS frame on client got SETTINGS_ENABLE_PUSH';
   525       }
   526       var value = buffer.readUInt32BE(i*5 + 1);
   527       frame.settings[setting.name] = setting.flag ? Boolean(value & 0x1) : value;
   528     } else {
   529       /* Unknown setting, protocol error */
   530       return 'SETTINGS frame got unknown setting type';
   531     }
   532   }
   533 };
   535 // The following settings are defined:
   536 var definedSettings = [];
   538 // * SETTINGS_HEADER_TABLE_SIZE (1):
   539 //   Allows the sender to inform the remote endpoint of the size of the header compression table
   540 //   used to decode header blocks.
   541 definedSettings[1] = { name: 'SETTINGS_HEADER_TABLE_SIZE', flag: false };
   543 // * SETTINGS_ENABLE_PUSH (2):
   544 //   This setting can be use to disable server push. An endpoint MUST NOT send a PUSH_PROMISE frame
   545 //   if it receives this setting set to a value of 0. The default value is 1, which indicates that
   546 //   push is permitted.
   547 definedSettings[2] = { name: 'SETTINGS_ENABLE_PUSH', flag: true };
   549 // * SETTINGS_MAX_CONCURRENT_STREAMS (4):
   550 //   indicates the maximum number of concurrent streams that the sender will allow.
   551 definedSettings[3] = { name: 'SETTINGS_MAX_CONCURRENT_STREAMS', flag: false };
   553 // * SETTINGS_INITIAL_WINDOW_SIZE (7):
   554 //   indicates the sender's initial stream window size (in bytes) for new streams.
   555 definedSettings[4] = { name: 'SETTINGS_INITIAL_WINDOW_SIZE', flag: false };
   557 // [PUSH_PROMISE](http://tools.ietf.org/html/draft-ietf-httpbis-http2-10#section-6.6)
   558 // ---------------------------------------------------------------
   559 //
   560 // The PUSH_PROMISE frame (type=0x5) is used to notify the peer endpoint in advance of streams the
   561 // sender intends to initiate.
   562 //
   563 // The PUSH_PROMISE frame defines the following flags:
   564 //
   565 // * END_PUSH_PROMISE (0x4):
   566 //   The END_PUSH_PROMISE bit indicates that this frame contains the entire payload necessary to
   567 //   provide a complete set of headers.
   569 frameTypes[0x5] = 'PUSH_PROMISE';
   571 frameFlags.PUSH_PROMISE = ['RESERVED1', 'RESERVED2', 'END_PUSH_PROMISE'];
   573 typeSpecificAttributes.PUSH_PROMISE = ['promised_stream', 'headers', 'data'];
   575 //      0                   1                   2                   3
   576 //      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   577 //     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   578 //     |X|                Promised-Stream-ID (31)                      |
   579 //     +-+-------------------------------------------------------------+
   580 //     |                    Header Block (*)                         ...
   581 //     +---------------------------------------------------------------+
   582 //
   583 // The PUSH_PROMISE frame includes the unsigned 31-bit identifier of
   584 // the stream the endpoint plans to create along with a minimal set of headers that provide
   585 // additional context for the stream.
   587 Serializer.PUSH_PROMISE = function writePushPromise(frame, buffers) {
   588   var buffer = new Buffer(4);
   590   var promised_stream = frame.promised_stream;
   591   assert((0 <= promised_stream) && (promised_stream <= 0x7fffffff), promised_stream);
   592   buffer.writeUInt32BE(promised_stream, 0);
   594   buffers.push(buffer);
   595   buffers.push(frame.data);
   596 };
   598 Deserializer.PUSH_PROMISE = function readPushPromise(buffer, frame) {
   599   frame.promised_stream = buffer.readUInt32BE(0) & 0x7fffffff;
   600   frame.data = buffer.slice(4);
   601 };
   603 // [PING](http://tools.ietf.org/html/draft-ietf-httpbis-http2-10#section-6.7)
   604 // -----------------------------------------------
   605 //
   606 // The PING frame (type=0x6) is a mechanism for measuring a minimal round-trip time from the
   607 // sender, as well as determining whether an idle connection is still functional.
   608 //
   609 // The PING frame defines one type-specific flag:
   610 //
   611 // * ACK (0x1):
   612 //   Bit 1 being set indicates that this PING frame is a PING response.
   614 frameTypes[0x6] = 'PING';
   616 frameFlags.PING = ['ACK'];
   618 typeSpecificAttributes.PING = ['data'];
   620 // In addition to the frame header, PING frames MUST contain 8 additional octets of opaque data.
   622 Serializer.PING = function writePing(frame, buffers) {
   623   buffers.push(frame.data);
   624 };
   626 Deserializer.PING = function readPing(buffer, frame) {
   627   if (buffer.length !== 8) {
   628     return 'Invalid size PING frame';
   629   }
   630   frame.data = buffer;
   631 };
   633 // [GOAWAY](http://tools.ietf.org/html/draft-ietf-httpbis-http2-10#section-6.8)
   634 // ---------------------------------------------------
   635 //
   636 // The GOAWAY frame (type=0x7) informs the remote peer to stop creating streams on this connection.
   637 //
   638 // The GOAWAY frame does not define any flags.
   640 frameTypes[0x7] = 'GOAWAY';
   642 frameFlags.GOAWAY = [];
   644 typeSpecificAttributes.GOAWAY = ['last_stream', 'error'];
   646 //      0                   1                   2                   3
   647 //      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   648 //     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   649 //     |X|                  Last-Stream-ID (31)                        |
   650 //     +-+-------------------------------------------------------------+
   651 //     |                      Error Code (32)                          |
   652 //     +---------------------------------------------------------------+
   653 //
   654 // The last stream identifier in the GOAWAY frame contains the highest numbered stream identifier
   655 // for which the sender of the GOAWAY frame has received frames on and might have taken some action
   656 // on.
   657 //
   658 // The GOAWAY frame also contains a 32-bit error code (see Error Codes) that contains the reason for
   659 // closing the connection.
   661 Serializer.GOAWAY = function writeGoaway(frame, buffers) {
   662   var buffer = new Buffer(8);
   664   var last_stream = frame.last_stream;
   665   assert((0 <= last_stream) && (last_stream <= 0x7fffffff), last_stream);
   666   buffer.writeUInt32BE(last_stream, 0);
   668   var code = errorCodes.indexOf(frame.error);
   669   assert((0 <= code) && (code <= 0xffffffff), code);
   670   buffer.writeUInt32BE(code, 4);
   672   buffers.push(buffer);
   673 };
   675 Deserializer.GOAWAY = function readGoaway(buffer, frame) {
   676   frame.last_stream = buffer.readUInt32BE(0) & 0x7fffffff;
   677   frame.error = errorCodes[buffer.readUInt32BE(4)];
   678 };
   680 // [WINDOW_UPDATE](http://tools.ietf.org/html/draft-ietf-httpbis-http2-10#section-6.9)
   681 // -----------------------------------------------------------------
   682 //
   683 // The WINDOW_UPDATE frame (type=0x8) is used to implement flow control.
   684 //
   685 // The WINDOW_UPDATE frame does not define any flags.
   687 frameTypes[0x8] = 'WINDOW_UPDATE';
   689 frameFlags.WINDOW_UPDATE = [];
   691 typeSpecificAttributes.WINDOW_UPDATE = ['window_size'];
   693 // The payload of a WINDOW_UPDATE frame is a 32-bit value indicating the additional number of bytes
   694 // that the sender can transmit in addition to the existing flow control window. The legal range
   695 // for this field is 1 to 2^31 - 1 (0x7fffffff) bytes; the most significant bit of this value is
   696 // reserved.
   698 Serializer.WINDOW_UPDATE = function writeWindowUpdate(frame, buffers) {
   699   var buffer = new Buffer(4);
   701   var window_size = frame.window_size;
   702   assert((0 <= window_size) && (window_size <= 0x7fffffff), window_size);
   703   buffer.writeUInt32BE(window_size, 0);
   705   buffers.push(buffer);
   706 };
   708 Deserializer.WINDOW_UPDATE = function readWindowUpdate(buffer, frame) {
   709   frame.window_size = buffer.readUInt32BE(0) & 0x7fffffff;
   710 };
   712 // [CONTINUATION](http://tools.ietf.org/html/draft-ietf-httpbis-http2-10#section-6.10)
   713 // ------------------------------------------------------------
   714 //
   715 // The CONTINUATION frame (type=0xA) is used to continue a sequence of header block fragments.
   716 //
   717 // The CONTINUATION frame defines the following flag:
   718 //
   719 // * END_HEADERS (0x4):
   720 //   The END_HEADERS bit indicates that this frame ends the sequence of header block fragments
   721 //   necessary to provide a complete set of headers.
   722 // * PAD_LOW (0x10):
   723 //   Bit 5 being set indicates that the Pad Low field is present.
   724 // * PAD_HIGH (0x20):
   725 //   Bit 6 being set indicates that the Pad High field is present. This bit MUST NOT be set unless
   726 //   the PAD_LOW flag is also set. Endpoints that receive a frame with PAD_HIGH set and PAD_LOW
   727 //   cleared MUST treat this as a connection error of type PROTOCOL_ERROR.
   729 frameTypes[0x9] = 'CONTINUATION';
   731 frameFlags.CONTINUATION = ['RESERVED1', 'RESERVED2', 'END_HEADERS', 'RESERVED8', 'PAD_LOW', 'PAD_HIGH'];
   733 typeSpecificAttributes.CONTINUATION = ['headers', 'data'];
   735 Serializer.CONTINUATION = function writeContinuation(frame, buffers) {
   736   buffers.push(frame.data);
   737 };
   739 Deserializer.CONTINUATION = function readContinuation(buffer, frame) {
   740   var dataOffset = 0;
   741   var paddingLength = 0;
   742   if (frame.flags.PAD_LOW) {
   743     if (frame.flags.PAD_HIGH) {
   744       paddingLength = (buffer.readUInt8(dataOffset) & 0xff) * 256;
   745       dataOffset += 1;
   746     }
   747     paddingLength += (buffer.readUInt8(dataOffset) & 0xff);
   748     dataOffset += 1;
   749   } else if (frame.flags.PAD_HIGH) {
   750     return 'CONTINUATION frame got PAD_HIGH without PAD_LOW';
   751   }
   752   if (paddingLength) {
   753     frame.data = buffer.slice(dataOffset, -1 * paddingLength);
   754   } else {
   755     frame.data = buffer.slice(dataOffset);
   756   }
   757 };
   759 // [Error Codes](http://tools.ietf.org/html/draft-ietf-httpbis-http2-10#section-7)
   760 // ------------------------------------------------------------
   762 var errorCodes = [
   763   'NO_ERROR',
   764   'PROTOCOL_ERROR',
   765   'INTERNAL_ERROR',
   766   'FLOW_CONTROL_ERROR',
   767   'SETTINGS_TIMEOUT',
   768   'STREAM_CLOSED',
   769   'FRAME_SIZE_ERROR',
   770   'REFUSED_STREAM',
   771   'CANCEL',
   772   'COMPRESSION_ERROR',
   773   'CONNECT_ERROR'
   774 ];
   775 errorCodes[420] = 'ENHANCE_YOUR_CALM';
   777 // Logging
   778 // -------
   780 // [Bunyan serializers](https://github.com/trentm/node-bunyan#serializers) to improve logging output
   781 // for debug messages emitted in this component.
   782 exports.serializers = {};
   784 // * `frame` serializer: it transforms data attributes from Buffers to hex strings and filters out
   785 //   flags that are not present.
   786 var frameCounter = 0;
   787 exports.serializers.frame = function(frame) {
   788   if (!frame) {
   789     return null;
   790   }
   792   if ('id' in frame) {
   793     return frame.id;
   794   }
   796   frame.id = frameCounter;
   797   frameCounter += 1;
   799   var logEntry = { id: frame.id };
   800   genericAttributes.concat(typeSpecificAttributes[frame.type]).forEach(function(name) {
   801     logEntry[name] = frame[name];
   802   });
   804   if (frame.data instanceof Buffer) {
   805     if (logEntry.data.length > 50) {
   806       logEntry.data = frame.data.slice(0, 47).toString('hex') + '...';
   807     } else {
   808       logEntry.data = frame.data.toString('hex');
   809     }
   811     if (!('length' in logEntry)) {
   812       logEntry.length = frame.data.length;
   813     }
   814   }
   816   if (frame.promised_stream instanceof Object) {
   817     logEntry.promised_stream = 'stream-' + frame.promised_stream.id;
   818   }
   820   logEntry.flags = Object.keys(frame.flags || {}).filter(function(name) {
   821     return frame.flags[name] === true;
   822   });
   824   return logEntry;
   825 };
   827 // * `data` serializer: it simply transforms a buffer to a hex string.
   828 exports.serializers.data = function(data) {
   829   return data.toString('hex');
   830 };

mercurial