framer.js (39565B)
1 // The framer consists of two [Transform Stream][1] subclasses that operate in [object mode][2]: 2 // the Serializer and the Deserializer 3 // [1]: https://nodejs.org/api/stream.html#stream_class_stream_transform 4 // [2]: https://nodejs.org/api/stream.html#stream_new_stream_readable_options 5 var assert = require('assert'); 6 7 var Transform = require('stream').Transform; 8 9 exports.Serializer = Serializer; 10 exports.Deserializer = Deserializer; 11 12 var logData = Boolean(process.env.HTTP2_LOG_DATA); 13 14 var MAX_PAYLOAD_SIZE = 16384; 15 var WINDOW_UPDATE_PAYLOAD_SIZE = 4; 16 17 // Serializer 18 // ---------- 19 // 20 // Frame Objects 21 // * * * * * * * --+--------------------------- 22 // | | 23 // v v Buffers 24 // [] -----> Payload Ser. --[buffers]--> Header Ser. --> * * * * 25 // empty adds payload adds header 26 // array buffers buffer 27 28 function Serializer(log) { 29 this._log = log.child({ component: 'serializer' }); 30 Transform.call(this, { objectMode: true }); 31 } 32 Serializer.prototype = Object.create(Transform.prototype, { constructor: { value: Serializer } }); 33 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'); 39 40 assert(frame.type in Serializer, 'Unknown frame type: ' + frame.type); 41 42 var buffers = []; 43 Serializer[frame.type](frame, buffers); 44 var length = Serializer.commonHeader(frame, buffers); 45 46 assert(length <= MAX_PAYLOAD_SIZE, 'Frame too large!'); 47 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 } 54 55 done(); 56 }; 57 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 68 69 function Deserializer(log, role) { 70 this._role = role; 71 this._log = log.child({ component: 'deserializer' }); 72 Transform.call(this, { objectMode: true }); 73 this._next(COMMON_HEADER_SIZE); 74 } 75 Deserializer.prototype = Object.create(Transform.prototype, { constructor: { value: Deserializer } }); 76 77 // The Deserializer is stateful, and it's two main alternating states are: *waiting for header* and 78 // *waiting for payload*. The state is stored in the boolean property `_waitingForHeader`. 79 // 80 // When entering a new state, a `_buffer` is created that will hold the accumulated data (header or 81 // payload). The `_cursor` is used to track the progress. 82 Deserializer.prototype._next = function(size) { 83 this._cursor = 0; 84 this._buffer = Buffer.alloc(size); 85 this._waitingForHeader = !this._waitingForHeader; 86 if (this._waitingForHeader) { 87 this._frame = {}; 88 } 89 }; 90 91 // Parsing an incoming buffer is an iterative process because it can hold multiple frames if it's 92 // large enough. A `cursor` is used to track the progress in parsing the incoming `chunk`. 93 Deserializer.prototype._transform = function _transform(chunk, encoding, done) { 94 var cursor = 0; 95 96 if (logData) { 97 this._log.trace({ data: chunk }, 'Incoming data'); 98 } 99 100 while(cursor < chunk.length) { 101 // The content of an incoming buffer is first copied to `_buffer`. If it can't hold the full 102 // chunk, then only a part of it is copied. 103 var toCopy = Math.min(chunk.length - cursor, this._buffer.length - this._cursor); 104 chunk.copy(this._buffer, this._cursor, cursor, cursor + toCopy); 105 this._cursor += toCopy; 106 cursor += toCopy; 107 108 // When `_buffer` is full, it's content gets parsed either as header or payload depending on 109 // the actual state. 110 111 // If it's header then the parsed data is stored in a temporary variable and then the 112 // deserializer waits for the specified length payload. 113 if ((this._cursor === this._buffer.length) && this._waitingForHeader) { 114 var payloadSize = Deserializer.commonHeader(this._buffer, this._frame); 115 if (payloadSize <= MAX_PAYLOAD_SIZE) { 116 this._next(payloadSize); 117 } else { 118 this.emit('error', 'FRAME_SIZE_ERROR'); 119 return; 120 } 121 } 122 123 // If it's payload then the the frame object is finalized and then gets pushed out. 124 // Unknown frame types are ignored. 125 // 126 // Note: If we just finished the parsing of a header and the payload length is 0, this branch 127 // will also run. 128 if ((this._cursor === this._buffer.length) && !this._waitingForHeader) { 129 if (this._frame.type) { 130 var error = Deserializer[this._frame.type](this._buffer, this._frame, this._role); 131 if (error) { 132 this._log.error('Incoming frame parsing error: ' + error); 133 this.emit('error', error); 134 } else { 135 this._log.trace({ frame: this._frame }, 'Incoming frame'); 136 this.push(this._frame); 137 } 138 } else { 139 this._log.error('Unknown type incoming frame'); 140 // Ignore it other than logging 141 } 142 this._next(COMMON_HEADER_SIZE); 143 } 144 } 145 146 done(); 147 }; 148 149 // [Frame Header](https://tools.ietf.org/html/rfc7540#section-4.1) 150 // -------------------------------------------------------------- 151 // 152 // HTTP/2 frames share a common base format consisting of a 9-byte header followed by 0 to 2^24 - 1 153 // bytes of data. 154 // 155 // Additional size limits can be set by specific application uses. HTTP limits the frame size to 156 // 16,384 octets by default, though this can be increased by a receiver. 157 // 158 // 0 1 2 3 159 // 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 160 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 161 // | Length (24) | 162 // +---------------+---------------+---------------+ 163 // | Type (8) | Flags (8) | 164 // +-+-----------------------------+---------------+---------------+ 165 // |R| Stream Identifier (31) | 166 // +-+-------------------------------------------------------------+ 167 // | Frame Data (0...) ... 168 // +---------------------------------------------------------------+ 169 // 170 // The fields of the frame header are defined as: 171 // 172 // * Length: 173 // The length of the frame data expressed as an unsigned 24-bit integer. The 9 bytes of the frame 174 // header are not included in this value. 175 // 176 // * Type: 177 // The 8-bit type of the frame. The frame type determines how the remainder of the frame header 178 // and data are interpreted. Implementations MUST ignore unsupported and unrecognized frame types. 179 // 180 // * Flags: 181 // An 8-bit field reserved for frame-type specific boolean flags. 182 // 183 // Flags are assigned semantics specific to the indicated frame type. Flags that have no defined 184 // semantics for a particular frame type MUST be ignored, and MUST be left unset (0) when sending. 185 // 186 // * R: 187 // A reserved 1-bit field. The semantics of this bit are undefined and the bit MUST remain unset 188 // (0) when sending and MUST be ignored when receiving. 189 // 190 // * Stream Identifier: 191 // A 31-bit stream identifier. The value 0 is reserved for frames that are associated with the 192 // connection as a whole as opposed to an individual stream. 193 // 194 // The structure and content of the remaining frame data is dependent entirely on the frame type. 195 196 var COMMON_HEADER_SIZE = 9; 197 198 var frameTypes = []; 199 200 var frameFlags = {}; 201 202 var genericAttributes = ['type', 'flags', 'stream']; 203 204 var typeSpecificAttributes = {}; 205 206 Serializer.commonHeader = function writeCommonHeader(frame, buffers) { 207 var headerBuffer = Buffer.alloc(COMMON_HEADER_SIZE); 208 209 var size = 0; 210 for (var i = 0; i < buffers.length; i++) { 211 size += buffers[i].length; 212 } 213 headerBuffer.writeUInt8(0, 0); 214 headerBuffer.writeUInt16BE(size, 1); 215 216 var typeId = frameTypes.indexOf(frame.type); // If we are here then the type is valid for sure 217 headerBuffer.writeUInt8(typeId, 3); 218 219 var flagByte = 0; 220 for (var flag in frame.flags) { 221 var position = frameFlags[frame.type].indexOf(flag); 222 assert(position !== -1, 'Unknown flag for frame type ' + frame.type + ': ' + flag); 223 if (frame.flags[flag]) { 224 flagByte |= (1 << position); 225 } 226 } 227 headerBuffer.writeUInt8(flagByte, 4); 228 229 assert((0 <= frame.stream) && (frame.stream < 0x7fffffff), frame.stream); 230 headerBuffer.writeUInt32BE(frame.stream || 0, 5); 231 232 buffers.unshift(headerBuffer); 233 234 return size; 235 }; 236 237 Deserializer.commonHeader = function readCommonHeader(buffer, frame) { 238 if (buffer.length < 9) { 239 return 'FRAME_SIZE_ERROR'; 240 } 241 242 var totallyWastedByte = buffer.readUInt8(0); 243 var length = buffer.readUInt16BE(1); 244 // We do this just for sanity checking later on, to make sure no one sent us a 245 // frame that's super large. 246 length += totallyWastedByte << 16; 247 248 frame.type = frameTypes[buffer.readUInt8(3)]; 249 if (!frame.type) { 250 // We are required to ignore unknown frame types 251 return length; 252 } 253 254 frame.flags = {}; 255 var flagByte = buffer.readUInt8(4); 256 var definedFlags = frameFlags[frame.type]; 257 for (var i = 0; i < definedFlags.length; i++) { 258 frame.flags[definedFlags[i]] = Boolean(flagByte & (1 << i)); 259 } 260 261 frame.stream = buffer.readUInt32BE(5) & 0x7fffffff; 262 263 return length; 264 }; 265 266 // Frame types 267 // =========== 268 269 // Every frame type is registered in the following places: 270 // 271 // * `frameTypes`: a register of frame type codes (used by `commonHeader()`) 272 // * `frameFlags`: a register of valid flags for frame types (used by `commonHeader()`) 273 // * `typeSpecificAttributes`: a register of frame specific frame object attributes (used by 274 // logging code and also serves as documentation for frame objects) 275 276 // [DATA Frames](https://tools.ietf.org/html/rfc7540#section-6.1) 277 // ------------------------------------------------------------ 278 // 279 // DATA frames (type=0x0) convey arbitrary, variable-length sequences of octets associated with a 280 // stream. 281 // 282 // The DATA frame defines the following flags: 283 // 284 // * END_STREAM (0x1): 285 // Bit 1 being set indicates that this frame is the last that the endpoint will send for the 286 // identified stream. 287 // * PADDED (0x08): 288 // Bit 4 being set indicates that the Pad Length field is present. 289 290 frameTypes[0x0] = 'DATA'; 291 292 frameFlags.DATA = ['END_STREAM', 'RESERVED2', 'RESERVED4', 'PADDED']; 293 294 typeSpecificAttributes.DATA = ['data']; 295 296 Serializer.DATA = function writeData(frame, buffers) { 297 buffers.push(frame.data); 298 }; 299 300 Deserializer.DATA = function readData(buffer, frame) { 301 var dataOffset = 0; 302 var paddingLength = 0; 303 if (frame.flags.PADDED) { 304 if (buffer.length < 1) { 305 // We must have at least one byte for padding control, but we don't. Bad peer! 306 return 'FRAME_SIZE_ERROR'; 307 } 308 paddingLength = (buffer.readUInt8(dataOffset) & 0xff); 309 dataOffset = 1; 310 } 311 312 if (paddingLength) { 313 if (paddingLength >= (buffer.length - 1)) { 314 // We don't have enough room for the padding advertised - bad peer! 315 return 'FRAME_SIZE_ERROR'; 316 } 317 frame.data = buffer.slice(dataOffset, -1 * paddingLength); 318 } else { 319 frame.data = buffer.slice(dataOffset); 320 } 321 }; 322 323 // [HEADERS](https://tools.ietf.org/html/rfc7540#section-6.2) 324 // -------------------------------------------------------------- 325 // 326 // The HEADERS frame (type=0x1) allows the sender to create a stream. 327 // 328 // The HEADERS frame defines the following flags: 329 // 330 // * END_STREAM (0x1): 331 // Bit 1 being set indicates that this frame is the last that the endpoint will send for the 332 // identified stream. 333 // * END_HEADERS (0x4): 334 // The END_HEADERS bit indicates that this frame contains the entire payload necessary to provide 335 // a complete set of headers. 336 // * PADDED (0x08): 337 // Bit 4 being set indicates that the Pad Length field is present. 338 // * PRIORITY (0x20): 339 // Bit 6 being set indicates that the Exlusive Flag (E), Stream Dependency, and Weight fields are 340 // present. 341 342 frameTypes[0x1] = 'HEADERS'; 343 344 frameFlags.HEADERS = ['END_STREAM', 'RESERVED2', 'END_HEADERS', 'PADDED', 'RESERVED5', 'PRIORITY']; 345 346 typeSpecificAttributes.HEADERS = ['priorityDependency', 'priorityWeight', 'exclusiveDependency', 'headers', 'data']; 347 348 // 0 1 2 3 349 // 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 350 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 351 // |Pad Length? (8)| 352 // +-+-------------+---------------+-------------------------------+ 353 // |E| Stream Dependency? (31) | 354 // +-+-------------+-----------------------------------------------+ 355 // | Weight? (8) | 356 // +-+-------------+-----------------------------------------------+ 357 // | Header Block Fragment (*) ... 358 // +---------------------------------------------------------------+ 359 // | Padding (*) ... 360 // +---------------------------------------------------------------+ 361 // 362 // The payload of a HEADERS frame contains a Headers Block 363 364 Serializer.HEADERS = function writeHeadersPriority(frame, buffers) { 365 if (frame.flags.PRIORITY) { 366 var buffer = Buffer.alloc(5); 367 assert((0 <= frame.priorityDependency) && (frame.priorityDependency <= 0x7fffffff), frame.priorityDependency); 368 buffer.writeUInt32BE(frame.priorityDependency, 0); 369 if (frame.exclusiveDependency) { 370 buffer[0] |= 0x80; 371 } 372 assert((0 <= frame.priorityWeight) && (frame.priorityWeight <= 0xff), frame.priorityWeight); 373 buffer.writeUInt8(frame.priorityWeight, 4); 374 buffers.push(buffer); 375 } 376 buffers.push(frame.data); 377 }; 378 379 Deserializer.HEADERS = function readHeadersPriority(buffer, frame) { 380 var minFrameLength = 0; 381 if (frame.flags.PADDED) { 382 minFrameLength += 1; 383 } 384 if (frame.flags.PRIORITY) { 385 minFrameLength += 5; 386 } 387 if (buffer.length < minFrameLength) { 388 // Peer didn't send enough data - bad peer! 389 return 'FRAME_SIZE_ERROR'; 390 } 391 392 var dataOffset = 0; 393 var paddingLength = 0; 394 if (frame.flags.PADDED) { 395 paddingLength = (buffer.readUInt8(dataOffset) & 0xff); 396 dataOffset = 1; 397 } 398 399 if (frame.flags.PRIORITY) { 400 var dependencyData = Buffer.alloc(4); 401 buffer.copy(dependencyData, 0, dataOffset, dataOffset + 4); 402 dataOffset += 4; 403 frame.exclusiveDependency = !!(dependencyData[0] & 0x80); 404 dependencyData[0] &= 0x7f; 405 frame.priorityDependency = dependencyData.readUInt32BE(0); 406 frame.priorityWeight = buffer.readUInt8(dataOffset); 407 dataOffset += 1; 408 } 409 410 if (paddingLength) { 411 if ((buffer.length - dataOffset) < paddingLength) { 412 // Not enough data left to satisfy the advertised padding - bad peer! 413 return 'FRAME_SIZE_ERROR'; 414 } 415 frame.data = buffer.slice(dataOffset, -1 * paddingLength); 416 } else { 417 frame.data = buffer.slice(dataOffset); 418 } 419 }; 420 421 // [PRIORITY](https://tools.ietf.org/html/rfc7540#section-6.3) 422 // ------------------------------------------------------- 423 // 424 // The PRIORITY frame (type=0x2) specifies the sender-advised priority of a stream. 425 // 426 // The PRIORITY frame does not define any flags. 427 428 frameTypes[0x2] = 'PRIORITY'; 429 430 frameFlags.PRIORITY = []; 431 432 typeSpecificAttributes.PRIORITY = ['priorityDependency', 'priorityWeight', 'exclusiveDependency']; 433 434 // 0 1 2 3 435 // 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 436 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 437 // |E| Stream Dependency? (31) | 438 // +-+-------------+-----------------------------------------------+ 439 // | Weight? (8) | 440 // +-+-------------+ 441 // 442 // The payload of a PRIORITY frame contains an exclusive bit, a 31-bit dependency, and an 8-bit weight 443 444 Serializer.PRIORITY = function writePriority(frame, buffers) { 445 var buffer = Buffer.alloc(5); 446 assert((0 <= frame.priorityDependency) && (frame.priorityDependency <= 0x7fffffff), frame.priorityDependency); 447 buffer.writeUInt32BE(frame.priorityDependency, 0); 448 if (frame.exclusiveDependency) { 449 buffer[0] |= 0x80; 450 } 451 assert((0 <= frame.priorityWeight) && (frame.priorityWeight <= 0xff), frame.priorityWeight); 452 buffer.writeUInt8(frame.priorityWeight, 4); 453 454 buffers.push(buffer); 455 }; 456 457 Deserializer.PRIORITY = function readPriority(buffer, frame) { 458 if (buffer.length < 5) { 459 // PRIORITY frames are 5 bytes long. Bad peer! 460 return 'FRAME_SIZE_ERROR'; 461 } 462 var dependencyData = Buffer.alloc(4); 463 buffer.copy(dependencyData, 0, 0, 4); 464 frame.exclusiveDependency = !!(dependencyData[0] & 0x80); 465 dependencyData[0] &= 0x7f; 466 frame.priorityDependency = dependencyData.readUInt32BE(0); 467 frame.priorityWeight = buffer.readUInt8(4); 468 }; 469 470 // [RST_STREAM](https://tools.ietf.org/html/rfc7540#section-6.4) 471 // ----------------------------------------------------------- 472 // 473 // The RST_STREAM frame (type=0x3) allows for abnormal termination of a stream. 474 // 475 // No type-flags are defined. 476 477 frameTypes[0x3] = 'RST_STREAM'; 478 479 frameFlags.RST_STREAM = []; 480 481 typeSpecificAttributes.RST_STREAM = ['error']; 482 483 // 0 1 2 3 484 // 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 485 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 486 // | Error Code (32) | 487 // +---------------------------------------------------------------+ 488 // 489 // The RST_STREAM frame contains a single unsigned, 32-bit integer identifying the error 490 // code (see Error Codes). The error code indicates why the stream is being terminated. 491 492 Serializer.RST_STREAM = function writeRstStream(frame, buffers) { 493 var buffer = Buffer.alloc(4); 494 var code = errorCodes.indexOf(frame.error); 495 assert((0 <= code) && (code <= 0xffffffff), code); 496 buffer.writeUInt32BE(code, 0); 497 buffers.push(buffer); 498 }; 499 500 Deserializer.RST_STREAM = function readRstStream(buffer, frame) { 501 if (buffer.length < 4) { 502 // RST_STREAM is 4 bytes long. Bad peer! 503 return 'FRAME_SIZE_ERROR'; 504 } 505 frame.error = errorCodes[buffer.readUInt32BE(0)]; 506 if (!frame.error) { 507 // Unknown error codes are considered equivalent to INTERNAL_ERROR 508 frame.error = 'INTERNAL_ERROR'; 509 } 510 }; 511 512 // [SETTINGS](https://tools.ietf.org/html/rfc7540#section-6.5) 513 // ------------------------------------------------------- 514 // 515 // The SETTINGS frame (type=0x4) conveys configuration parameters that affect how endpoints 516 // communicate. 517 // 518 // The SETTINGS frame defines the following flag: 519 520 // * ACK (0x1): 521 // Bit 1 being set indicates that this frame acknowledges receipt and application of the peer's 522 // SETTINGS frame. 523 frameTypes[0x4] = 'SETTINGS'; 524 525 frameFlags.SETTINGS = ['ACK']; 526 527 typeSpecificAttributes.SETTINGS = ['settings']; 528 529 // The payload of a SETTINGS frame consists of zero or more settings. Each setting consists of a 530 // 16-bit identifier, and an unsigned 32-bit value. 531 // 532 // 0 1 2 3 533 // 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 534 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 535 // | Identifier(16) | Value (32) | 536 // +-----------------+---------------------------------------------+ 537 // ...Value | 538 // +---------------------------------+ 539 // 540 // Each setting in a SETTINGS frame replaces the existing value for that setting. Settings are 541 // processed in the order in which they appear, and a receiver of a SETTINGS frame does not need to 542 // maintain any state other than the current value of settings. Therefore, the value of a setting 543 // is the last value that is seen by a receiver. This permits the inclusion of the same settings 544 // multiple times in the same SETTINGS frame, though doing so does nothing other than waste 545 // connection capacity. 546 547 Serializer.SETTINGS = function writeSettings(frame, buffers) { 548 var settings = [], settingsLeft = Object.keys(frame.settings); 549 definedSettings.forEach(function(setting, id) { 550 if (setting.name in frame.settings) { 551 settingsLeft.splice(settingsLeft.indexOf(setting.name), 1); 552 var value = frame.settings[setting.name]; 553 settings.push({ id: id, value: setting.flag ? Boolean(value) : value }); 554 } 555 }); 556 assert(settingsLeft.length === 0, 'Unknown settings: ' + settingsLeft.join(', ')); 557 558 var buffer = Buffer.alloc(settings.length * 6); 559 for (var i = 0; i < settings.length; i++) { 560 buffer.writeUInt16BE(settings[i].id & 0xffff, i*6); 561 buffer.writeUInt32BE(settings[i].value, i*6 + 2); 562 } 563 564 buffers.push(buffer); 565 }; 566 567 Deserializer.SETTINGS = function readSettings(buffer, frame, role) { 568 frame.settings = {}; 569 570 // Receipt of a SETTINGS frame with the ACK flag set and a length 571 // field value other than 0 MUST be treated as a connection error 572 // (Section 5.4.1) of type FRAME_SIZE_ERROR. 573 if(frame.flags.ACK && buffer.length != 0) { 574 return 'FRAME_SIZE_ERROR'; 575 } 576 577 if (buffer.length % 6 !== 0) { 578 return 'PROTOCOL_ERROR'; 579 } 580 for (var i = 0; i < buffer.length / 6; i++) { 581 var id = buffer.readUInt16BE(i*6) & 0xffff; 582 var setting = definedSettings[id]; 583 if (setting) { 584 if (role == 'CLIENT' && setting.name == 'SETTINGS_ENABLE_PUSH') { 585 return 'SETTINGS frame on client got SETTINGS_ENABLE_PUSH'; 586 } 587 var value = buffer.readUInt32BE(i*6 + 2); 588 frame.settings[setting.name] = setting.flag ? Boolean(value & 0x1) : value; 589 } 590 } 591 }; 592 593 // The following settings are defined: 594 var definedSettings = []; 595 596 // * SETTINGS_HEADER_TABLE_SIZE (1): 597 // Allows the sender to inform the remote endpoint of the size of the header compression table 598 // used to decode header blocks. 599 definedSettings[1] = { name: 'SETTINGS_HEADER_TABLE_SIZE', flag: false }; 600 601 // * SETTINGS_ENABLE_PUSH (2): 602 // This setting can be use to disable server push. An endpoint MUST NOT send a PUSH_PROMISE frame 603 // if it receives this setting set to a value of 0. The default value is 1, which indicates that 604 // push is permitted. 605 definedSettings[2] = { name: 'SETTINGS_ENABLE_PUSH', flag: true }; 606 607 // * SETTINGS_MAX_CONCURRENT_STREAMS (3): 608 // indicates the maximum number of concurrent streams that the sender will allow. 609 definedSettings[3] = { name: 'SETTINGS_MAX_CONCURRENT_STREAMS', flag: false }; 610 611 // * SETTINGS_INITIAL_WINDOW_SIZE (4): 612 // indicates the sender's initial stream window size (in bytes) for new streams. 613 definedSettings[4] = { name: 'SETTINGS_INITIAL_WINDOW_SIZE', flag: false }; 614 615 // * SETTINGS_MAX_FRAME_SIZE (5): 616 // indicates the maximum size of a frame the receiver will allow. 617 definedSettings[5] = { name: 'SETTINGS_MAX_FRAME_SIZE', flag: false }; 618 619 // [PUSH_PROMISE](https://tools.ietf.org/html/rfc7540#section-6.6) 620 // --------------------------------------------------------------- 621 // 622 // The PUSH_PROMISE frame (type=0x5) is used to notify the peer endpoint in advance of streams the 623 // sender intends to initiate. 624 // 625 // The PUSH_PROMISE frame defines the following flags: 626 // 627 // * END_PUSH_PROMISE (0x4): 628 // The END_PUSH_PROMISE bit indicates that this frame contains the entire payload necessary to 629 // provide a complete set of headers. 630 631 frameTypes[0x5] = 'PUSH_PROMISE'; 632 633 frameFlags.PUSH_PROMISE = ['RESERVED1', 'RESERVED2', 'END_PUSH_PROMISE', 'PADDED']; 634 635 typeSpecificAttributes.PUSH_PROMISE = ['promised_stream', 'headers', 'data']; 636 637 // 0 1 2 3 638 // 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 639 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 640 // |Pad Length? (8)| 641 // +-+-------------+-----------------------------------------------+ 642 // |X| Promised-Stream-ID (31) | 643 // +-+-------------------------------------------------------------+ 644 // | Header Block Fragment (*) ... 645 // +---------------------------------------------------------------+ 646 // | Padding (*) ... 647 // +---------------------------------------------------------------+ 648 // 649 // The PUSH_PROMISE frame includes the unsigned 31-bit identifier of 650 // the stream the endpoint plans to create along with a minimal set of headers that provide 651 // additional context for the stream. 652 653 Serializer.PUSH_PROMISE = function writePushPromise(frame, buffers) { 654 var buffer = Buffer.alloc(4); 655 656 var promised_stream = frame.promised_stream; 657 assert((0 <= promised_stream) && (promised_stream <= 0x7fffffff), promised_stream); 658 buffer.writeUInt32BE(promised_stream, 0); 659 660 buffers.push(buffer); 661 buffers.push(frame.data); 662 }; 663 664 Deserializer.PUSH_PROMISE = function readPushPromise(buffer, frame) { 665 if (buffer.length < 4) { 666 return 'FRAME_SIZE_ERROR'; 667 } 668 var dataOffset = 0; 669 var paddingLength = 0; 670 if (frame.flags.PADDED) { 671 if (buffer.length < 5) { 672 return 'FRAME_SIZE_ERROR'; 673 } 674 paddingLength = (buffer.readUInt8(dataOffset) & 0xff); 675 dataOffset = 1; 676 } 677 frame.promised_stream = buffer.readUInt32BE(dataOffset) & 0x7fffffff; 678 dataOffset += 4; 679 if (paddingLength) { 680 if ((buffer.length - dataOffset) < paddingLength) { 681 return 'FRAME_SIZE_ERROR'; 682 } 683 frame.data = buffer.slice(dataOffset, -1 * paddingLength); 684 } else { 685 frame.data = buffer.slice(dataOffset); 686 } 687 }; 688 689 // [PING](https://tools.ietf.org/html/rfc7540#section-6.7) 690 // ----------------------------------------------- 691 // 692 // The PING frame (type=0x6) is a mechanism for measuring a minimal round-trip time from the 693 // sender, as well as determining whether an idle connection is still functional. 694 // 695 // The PING frame defines one type-specific flag: 696 // 697 // * ACK (0x1): 698 // Bit 1 being set indicates that this PING frame is a PING response. 699 700 frameTypes[0x6] = 'PING'; 701 702 frameFlags.PING = ['ACK']; 703 704 typeSpecificAttributes.PING = ['data']; 705 706 // In addition to the frame header, PING frames MUST contain 8 additional octets of opaque data. 707 708 Serializer.PING = function writePing(frame, buffers) { 709 buffers.push(frame.data); 710 }; 711 712 Deserializer.PING = function readPing(buffer, frame) { 713 if (buffer.length !== 8) { 714 return 'FRAME_SIZE_ERROR'; 715 } 716 frame.data = buffer; 717 }; 718 719 // [GOAWAY](https://tools.ietf.org/html/rfc7540#section-6.8) 720 // --------------------------------------------------- 721 // 722 // The GOAWAY frame (type=0x7) informs the remote peer to stop creating streams on this connection. 723 // 724 // The GOAWAY frame does not define any flags. 725 726 frameTypes[0x7] = 'GOAWAY'; 727 728 frameFlags.GOAWAY = []; 729 730 typeSpecificAttributes.GOAWAY = ['last_stream', 'error']; 731 732 // 0 1 2 3 733 // 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 734 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 735 // |X| Last-Stream-ID (31) | 736 // +-+-------------------------------------------------------------+ 737 // | Error Code (32) | 738 // +---------------------------------------------------------------+ 739 // 740 // The last stream identifier in the GOAWAY frame contains the highest numbered stream identifier 741 // for which the sender of the GOAWAY frame has received frames on and might have taken some action 742 // on. 743 // 744 // The GOAWAY frame also contains a 32-bit error code (see Error Codes) that contains the reason for 745 // closing the connection. 746 747 Serializer.GOAWAY = function writeGoaway(frame, buffers) { 748 var buffer = Buffer.alloc(8); 749 750 var last_stream = frame.last_stream; 751 assert((0 <= last_stream) && (last_stream <= 0x7fffffff), last_stream); 752 buffer.writeUInt32BE(last_stream, 0); 753 754 var code = errorCodes.indexOf(frame.error); 755 assert((0 <= code) && (code <= 0xffffffff), code); 756 buffer.writeUInt32BE(code, 4); 757 758 buffers.push(buffer); 759 }; 760 761 Deserializer.GOAWAY = function readGoaway(buffer, frame) { 762 if (buffer.length !== 8) { 763 // GOAWAY must have 8 bytes 764 return 'FRAME_SIZE_ERROR'; 765 } 766 frame.last_stream = buffer.readUInt32BE(0) & 0x7fffffff; 767 frame.error = errorCodes[buffer.readUInt32BE(4)]; 768 if (!frame.error) { 769 // Unknown error types are to be considered equivalent to INTERNAL ERROR 770 frame.error = 'INTERNAL_ERROR'; 771 } 772 }; 773 774 // [WINDOW_UPDATE](https://tools.ietf.org/html/rfc7540#section-6.9) 775 // ----------------------------------------------------------------- 776 // 777 // The WINDOW_UPDATE frame (type=0x8) is used to implement flow control. 778 // 779 // The WINDOW_UPDATE frame does not define any flags. 780 781 frameTypes[0x8] = 'WINDOW_UPDATE'; 782 783 frameFlags.WINDOW_UPDATE = []; 784 785 typeSpecificAttributes.WINDOW_UPDATE = ['window_size']; 786 787 // The payload of a WINDOW_UPDATE frame is a 32-bit value indicating the additional number of bytes 788 // that the sender can transmit in addition to the existing flow control window. The legal range 789 // for this field is 1 to 2^31 - 1 (0x7fffffff) bytes; the most significant bit of this value is 790 // reserved. 791 792 Serializer.WINDOW_UPDATE = function writeWindowUpdate(frame, buffers) { 793 var buffer = Buffer.alloc(4); 794 795 var window_size = frame.window_size; 796 assert((0 < window_size) && (window_size <= 0x7fffffff), window_size); 797 buffer.writeUInt32BE(window_size, 0); 798 799 buffers.push(buffer); 800 }; 801 802 Deserializer.WINDOW_UPDATE = function readWindowUpdate(buffer, frame) { 803 if (buffer.length !== WINDOW_UPDATE_PAYLOAD_SIZE) { 804 return 'FRAME_SIZE_ERROR'; 805 } 806 frame.window_size = buffer.readUInt32BE(0) & 0x7fffffff; 807 if (frame.window_size === 0) { 808 return 'PROTOCOL_ERROR'; 809 } 810 }; 811 812 // [CONTINUATION](https://tools.ietf.org/html/rfc7540#section-6.10) 813 // ------------------------------------------------------------ 814 // 815 // The CONTINUATION frame (type=0x9) is used to continue a sequence of header block fragments. 816 // 817 // The CONTINUATION frame defines the following flag: 818 // 819 // * END_HEADERS (0x4): 820 // The END_HEADERS bit indicates that this frame ends the sequence of header block fragments 821 // necessary to provide a complete set of headers. 822 823 frameTypes[0x9] = 'CONTINUATION'; 824 825 frameFlags.CONTINUATION = ['RESERVED1', 'RESERVED2', 'END_HEADERS']; 826 827 typeSpecificAttributes.CONTINUATION = ['headers', 'data']; 828 829 Serializer.CONTINUATION = function writeContinuation(frame, buffers) { 830 buffers.push(frame.data); 831 }; 832 833 Deserializer.CONTINUATION = function readContinuation(buffer, frame) { 834 frame.data = buffer; 835 }; 836 837 // [ALTSVC](https://tools.ietf.org/html/rfc7838#section-4) 838 // ------------------------------------------------------------ 839 // 840 // The ALTSVC frame (type=0xA) advertises the availability of an alternative service to the client. 841 // 842 // The ALTSVC frame does not define any flags. 843 844 frameTypes[0xA] = 'ALTSVC'; 845 846 frameFlags.ALTSVC = []; 847 848 // 0 1 2 3 849 // 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 850 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 851 // | Origin-Len (16) | Origin? (*) ... 852 // +-------------------------------+----------------+--------------+ 853 // | Alt-Svc-Field-Value (*) ... 854 // +---------------------------------------------------------------+ 855 // 856 // The ALTSVC frame contains the following fields: 857 // 858 // Origin-Len: An unsigned, 16-bit integer indicating the length, in 859 // octets, of the Origin field. 860 // 861 // Origin: An OPTIONAL sequence of characters containing ASCII 862 // serialisation of an origin ([RFC6454](https://tools.ietf.org/html/rfc6454), 863 // Section 6.2) that the alternate service is applicable to. 864 // 865 // Alt-Svc-Field-Value: A sequence of octets (length determined by 866 // subtracting the length of all preceding fields from the frame 867 // length) containing a value identical to the Alt-Svc field value 868 // defined in (Section 3)[https://tools.ietf.org/html/rfc7838#section-3] 869 // (ABNF production "Alt-Svc"). 870 871 typeSpecificAttributes.ALTSVC = ['maxAge', 'port', 'protocolID', 'host', 872 'origin']; 873 874 function istchar(c) { 875 return ('!#$&\'*+-.^_`|~1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.indexOf(c) > -1); 876 } 877 878 function hexencode(s) { 879 var t = ''; 880 for (var i = 0; i < s.length; i++) { 881 if (!istchar(s[i])) { 882 t += '%'; 883 t += Buffer.from(s[i]).toString('hex'); 884 } else { 885 t += s[i]; 886 } 887 } 888 return t; 889 } 890 891 Serializer.ALTSVC = function writeAltSvc(frame, buffers) { 892 var buffer = Buffer.alloc(2); 893 buffer.writeUInt16BE(frame.origin.length, 0); 894 buffers.push(buffer); 895 buffers.push(Buffer.from(frame.origin, 'ascii')); 896 897 var fieldValue = hexencode(frame.protocolID) + '="' + frame.host + ':' + frame.port + '"'; 898 if (frame.maxAge !== 86400) { // 86400 is the default 899 fieldValue += "; ma=" + frame.maxAge; 900 } 901 902 buffers.push(Buffer.from(fieldValue, 'ascii')); 903 }; 904 905 function stripquotes(s) { 906 var start = 0; 907 var end = s.length; 908 while ((start < end) && (s[start] === '"')) { 909 start++; 910 } 911 while ((end > start) && (s[end - 1] === '"')) { 912 end--; 913 } 914 if (start >= end) { 915 return ""; 916 } 917 return s.substring(start, end); 918 } 919 920 function splitNameValue(nvpair) { 921 var eq = -1; 922 var inQuotes = false; 923 924 for (var i = 0; i < nvpair.length; i++) { 925 if (nvpair[i] === '"') { 926 inQuotes = !inQuotes; 927 continue; 928 } 929 if (inQuotes) { 930 continue; 931 } 932 if (nvpair[i] === '=') { 933 eq = i; 934 break; 935 } 936 } 937 938 if (eq === -1) { 939 return {'name': nvpair, 'value': null}; 940 } 941 942 var name = stripquotes(nvpair.substring(0, eq).trim()); 943 var value = stripquotes(nvpair.substring(eq + 1).trim()); 944 return {'name': name, 'value': value}; 945 } 946 947 function splitHeaderParameters(hv) { 948 return parseHeaderValue(hv, ';', splitNameValue); 949 } 950 951 function parseHeaderValue(hv, separator, callback) { 952 var start = 0; 953 var inQuotes = false; 954 var values = []; 955 956 for (var i = 0; i < hv.length; i++) { 957 if (hv[i] === '"') { 958 inQuotes = !inQuotes; 959 continue; 960 } 961 if (inQuotes) { 962 // Just skip this 963 continue; 964 } 965 if (hv[i] === separator) { 966 var newValue = hv.substring(start, i).trim(); 967 if (newValue.length > 0) { 968 newValue = callback(newValue); 969 values.push(newValue); 970 } 971 start = i + 1; 972 } 973 } 974 975 var newValue = hv.substring(start).trim(); 976 if (newValue.length > 0) { 977 newValue = callback(newValue); 978 values.push(newValue); 979 } 980 981 return values; 982 } 983 984 function rsplit(s, delim, count) { 985 var nsplits = 0; 986 var end = s.length; 987 var rval = []; 988 for (var i = s.length - 1; i >= 0; i--) { 989 if (s[i] === delim) { 990 var t = s.substring(i + 1, end); 991 end = i; 992 rval.unshift(t); 993 nsplits++; 994 if (nsplits === count) { 995 break; 996 } 997 } 998 } 999 if (end !== 0) { 1000 rval.unshift(s.substring(0, end)); 1001 } 1002 return rval; 1003 } 1004 1005 function ishex(c) { 1006 return ('0123456789ABCDEFabcdef'.indexOf(c) > -1); 1007 } 1008 1009 function unescape(s) { 1010 var i = 0; 1011 var t = ''; 1012 while (i < s.length) { 1013 if (s[i] != '%' || !ishex(s[i + 1]) || !ishex(s[i + 2])) { 1014 t += s[i]; 1015 } else { 1016 ++i; 1017 var hexvalue = ''; 1018 if (i < s.length) { 1019 hexvalue += s[i]; 1020 ++i; 1021 } 1022 if (i < s.length) { 1023 hexvalue += s[i]; 1024 } 1025 if (hexvalue.length > 0) { 1026 t += Buffer.from(hexvalue, 'hex').toString(); 1027 } else { 1028 t += '%'; 1029 } 1030 } 1031 1032 ++i; 1033 } 1034 return t; 1035 } 1036 1037 Deserializer.ALTSVC = function readAltSvc(buffer, frame) { 1038 if (buffer.length < 2) { 1039 return 'FRAME_SIZE_ERROR'; 1040 } 1041 var originLength = buffer.readUInt16BE(0); 1042 if ((buffer.length - 2) < originLength) { 1043 return 'FRAME_SIZE_ERROR'; 1044 } 1045 frame.origin = buffer.toString('ascii', 2, 2 + originLength); 1046 var fieldValue = buffer.toString('ascii', 2 + originLength); 1047 var values = parseHeaderValue(fieldValue, ',', splitHeaderParameters); 1048 if (values.length > 1) { 1049 // TODO - warn that we only use one here 1050 } 1051 if (values.length === 0) { 1052 // Well that's a malformed frame. Just ignore it. 1053 return; 1054 } 1055 1056 var chosenAltSvc = values[0]; 1057 frame.maxAge = 86400; // Default 1058 for (var i = 0; i < chosenAltSvc.length; i++) { 1059 if (i === 0) { 1060 // This corresponds to the protocolID="<host>:<port>" item 1061 frame.protocolID = unescape(chosenAltSvc[i].name); 1062 var hostport = rsplit(chosenAltSvc[i].value, ':', 1); 1063 frame.host = hostport[0]; 1064 frame.port = parseInt(hostport[1], 10); 1065 } else if (chosenAltSvc[i].name == 'ma') { 1066 frame.maxAge = parseInt(chosenAltSvc[i].value, 10); 1067 } 1068 // Otherwise, we just ignore this 1069 } 1070 }; 1071 1072 // frame 0xB was BLOCKED and some versions of chrome will 1073 // throw PROTOCOL_ERROR upon seeing it with non 0 payload 1074 1075 frameTypes[0xC] = 'ORIGIN'; 1076 frameFlags.ORIGIN = []; 1077 typeSpecificAttributes.ORIGIN = ['originList']; 1078 1079 Serializer.ORIGIN = function writeOrigin(frame, buffers) { 1080 for (var i = 0; i < frame.originList.length; i++) { 1081 var buffer = Buffer.alloc(2); 1082 buffer.writeUInt16BE(frame.originList[i].length, 0); 1083 buffers.push(buffer); 1084 buffers.push(Buffer.from(frame.originList[i], 'ascii')); 1085 } 1086 }; 1087 1088 Deserializer.ORIGIN = function readOrigin(buffer, frame) { 1089 // ignored 1090 }; 1091 1092 1093 // [Error Codes](https://tools.ietf.org/html/rfc7540#section-7) 1094 // ------------------------------------------------------------ 1095 1096 var errorCodes = [ 1097 'NO_ERROR', 1098 'PROTOCOL_ERROR', 1099 'INTERNAL_ERROR', 1100 'FLOW_CONTROL_ERROR', 1101 'SETTINGS_TIMEOUT', 1102 'STREAM_CLOSED', 1103 'FRAME_SIZE_ERROR', 1104 'REFUSED_STREAM', 1105 'CANCEL', 1106 'COMPRESSION_ERROR', 1107 'CONNECT_ERROR', 1108 'ENHANCE_YOUR_CALM', 1109 'INADEQUATE_SECURITY', 1110 'HTTP_1_1_REQUIRED' 1111 ]; 1112 1113 // Logging 1114 // ------- 1115 1116 // [Bunyan serializers](https://github.com/trentm/node-bunyan#serializers) to improve logging output 1117 // for debug messages emitted in this component. 1118 exports.serializers = {}; 1119 1120 // * `frame` serializer: it transforms data attributes from Buffers to hex strings and filters out 1121 // flags that are not present. 1122 var frameCounter = 0; 1123 exports.serializers.frame = function(frame) { 1124 if (!frame) { 1125 return null; 1126 } 1127 1128 if ('id' in frame) { 1129 return frame.id; 1130 } 1131 1132 frame.id = frameCounter; 1133 frameCounter += 1; 1134 1135 var logEntry = { id: frame.id }; 1136 genericAttributes.concat(typeSpecificAttributes[frame.type]).forEach(function(name) { 1137 logEntry[name] = frame[name]; 1138 }); 1139 1140 if (frame.data instanceof Buffer) { 1141 if (logEntry.data.length > 50) { 1142 logEntry.data = frame.data.slice(0, 47).toString('hex') + '...'; 1143 } else { 1144 logEntry.data = frame.data.toString('hex'); 1145 } 1146 1147 if (!('length' in logEntry)) { 1148 logEntry.length = frame.data.length; 1149 } 1150 } 1151 1152 if (frame.promised_stream instanceof Object) { 1153 logEntry.promised_stream = 'stream-' + frame.promised_stream.id; 1154 } 1155 1156 logEntry.flags = Object.keys(frame.flags || {}).filter(function(name) { 1157 return frame.flags[name] === true; 1158 }); 1159 1160 return logEntry; 1161 }; 1162 1163 // * `data` serializer: it simply transforms a buffer to a hex string. 1164 exports.serializers.data = function(data) { 1165 return data.toString('hex'); 1166 };