quic
Version:
A QUIC server/client implementation in Node.js.
594 lines • 19.3 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", { value: true });
// https://github.com/google/proto-quic/blob/master/src/net/quic/core/quic_error_codes.h
const INVALID_ERROR = { name: 'INVALID_ERROR_CODE', code: 0xffffffff };
const INVALID_RST_STREAM_ERROR = { name: 'INVALID_RST_STREAM_ERROR_CODE', code: 0xffffffff };
const streamErrors = Object.assign(Object.create(null), {
QUIC_STREAM_NO_ERROR: {
code: 0,
message: '',
},
QUIC_ERROR_PROCESSING_STREAM: {
code: 1,
message: 'There was some error which halted stream processing.',
},
QUIC_MULTIPLE_TERMINATION_OFFSETS: {
code: 2,
message: 'We got two fin or reset offsets which did not match.',
},
QUIC_BAD_APPLICATION_PAYLOAD: {
code: 3,
message: 'We got bad payload and can not respond to it at the protocol level.',
},
QUIC_STREAM_CONNECTION_ERROR: {
code: 4,
message: 'Stream closed due to connection error. No reset frame is sent when this happens.',
},
QUIC_STREAM_PEER_GOING_AWAY: {
code: 5,
message: 'GoAway frame sent. No more stream can be created.',
},
QUIC_STREAM_CANCELLED: {
code: 6,
message: 'The stream has been cancelled.',
},
QUIC_RST_ACKNOWLEDGEMENT: {
code: 7,
message: 'Closing stream locally, sending a RST to allow for proper flow control' +
'accounting. Sent in response to a RST from the peer.',
},
QUIC_REFUSED_STREAM: {
code: 8,
message: 'Receiver refused to create the stream (because its limit on open streams' +
' has been reached). The sender should retry the request later (using another stream).',
},
QUIC_INVALID_PROMISE_URL: {
code: 9,
message: 'Invalid URL in PUSH_PROMISE request header.',
},
QUIC_UNAUTHORIZED_PROMISE_URL: {
code: 10,
message: 'Server is not authoritative for this URL.',
},
QUIC_DUPLICATE_PROMISE_URL: {
code: 11,
message: 'Can\'t have more than one active PUSH_PROMISE per URL.',
},
QUIC_PROMISE_VARY_MISMATCH: {
code: 12,
message: 'Vary check failed.',
},
QUIC_INVALID_PROMISE_METHOD: {
code: 13,
message: 'Only GET and HEAD methods allowed.',
},
QUIC_PUSH_STREAM_TIMED_OUT: {
code: 14,
message: 'The push stream is unclaimed and timed out.',
},
QUIC_HEADERS_TOO_LARGE: {
code: 15,
message: 'Received headers were too large.',
},
QUIC_STREAM_LAST_ERROR: {
code: 16,
message: 'No error',
},
});
const errors = Object.assign(Object.create(null), {
QUIC_NO_ERROR: {
code: 0,
message: '',
},
QUIC_INTERNAL_ERROR: {
code: 1,
message: 'Connection has reached an invalid state.',
},
QUIC_STREAM_DATA_AFTER_TERMINATION: {
code: 2,
message: 'There were data frames after the a fin or reset.',
},
QUIC_INVALID_PACKET_HEADER: {
code: 3,
message: 'Control frame is malformed.',
},
QUIC_INVALID_FRAME_DATA: {
code: 4,
message: 'Frame data is malformed.',
},
QUIC_MISSING_PAYLOAD: {
code: 48,
message: 'The packet contained no payload.',
},
QUIC_INVALID_FEC_DATA: {
code: 5,
message: 'FEC data is malformed.',
},
QUIC_INVALID_STREAM_DATA: {
code: 46,
message: 'STREAM frame data is malformed.',
},
QUIC_OVERLAPPING_STREAM_DATA: {
code: 87,
message: 'STREAM frame data overlaps with buffered data.',
},
QUIC_UNENCRYPTED_STREAM_DATA: {
code: 61,
message: 'Received STREAM frame data is not encrypted.',
},
QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA: {
code: 88,
message: 'Attempt to send unencrypted STREAM frame.',
},
QUIC_MAYBE_CORRUPTED_MEMORY: {
code: 89,
message: 'Received a frame which is likely the result of memory corruption.',
},
QUIC_UNENCRYPTED_FEC_DATA: {
code: 77,
message: 'FEC frame data is not encrypted.',
},
QUIC_INVALID_RST_STREAM_DATA: {
code: 6,
message: 'RST_STREAM frame data is malformed.',
},
QUIC_INVALID_CONNECTION_CLOSE_DATA: {
code: 7,
message: 'CONNECTION_CLOSE frame data is malformed.',
},
QUIC_INVALID_GOAWAY_DATA: {
code: 8,
message: 'GOAWAY frame data is malformed.',
},
QUIC_INVALID_WINDOW_UPDATE_DATA: {
code: 57,
message: 'WINDOW_UPDATE frame data is malformed.',
},
QUIC_INVALID_BLOCKED_DATA: {
code: 58,
message: 'BLOCKED frame data is malformed.',
},
QUIC_INVALID_STOP_WAITING_DATA: {
code: 60,
message: 'STOP_WAITING frame data is malformed.',
},
QUIC_INVALID_PATH_CLOSE_DATA: {
code: 78,
message: 'PATH_CLOSE frame data is malformed.',
},
QUIC_INVALID_ACK_DATA: {
code: 9,
message: 'ACK frame data is malformed.',
},
QUIC_INVALID_VERSION_NEGOTIATION_PACKET: {
code: 10,
message: 'Version negotiation packet is malformed.',
},
QUIC_INVALID_PUBLIC_RST_PACKET: {
code: 11,
message: 'Public RST packet is malformed.',
},
QUIC_DECRYPTION_FAILURE: {
code: 12,
message: 'There was an error decrypting.',
},
QUIC_ENCRYPTION_FAILURE: {
code: 13,
message: 'There was an error encrypting.',
},
QUIC_PACKET_TOO_LARGE: {
code: 14,
message: 'The packet exceeded kMaxPacketSize.',
},
QUIC_PEER_GOING_AWAY: {
code: 16,
message: 'The peer is going away. May be a client or server.',
},
QUIC_INVALID_STREAM_ID: {
code: 17,
message: 'A stream ID was invalid.',
},
QUIC_INVALID_PRIORITY: {
code: 49,
message: 'A priority was invalid.',
},
QUIC_TOO_MANY_OPEN_STREAMS: {
code: 18,
message: 'Too many streams already open.',
},
QUIC_TOO_MANY_AVAILABLE_STREAMS: {
code: 76,
message: 'The peer created too many available streams.',
},
QUIC_PUBLIC_RESET: {
code: 19,
message: 'Received public reset for this connection.',
},
QUIC_INVALID_VERSION: {
code: 20,
message: 'Invalid protocol version.',
},
QUIC_INVALID_HEADER_ID: {
code: 22,
message: 'The Header ID for a stream was too far from the previous.',
},
QUIC_INVALID_NEGOTIATED_VALUE: {
code: 23,
message: 'Negotiable parameter received during handshake had invalid value.',
},
QUIC_DECOMPRESSION_FAILURE: {
code: 24,
message: 'There was an error decompressing data.',
},
QUIC_NETWORK_IDLE_TIMEOUT: {
code: 25,
message: 'The connection timed out due to no network activity.',
},
QUIC_HANDSHAKE_TIMEOUT: {
code: 67,
message: 'The connection timed out waiting for the handshake to complete.',
},
QUIC_ERROR_MIGRATING_ADDRESS: {
code: 26,
message: 'There was an error encountered migrating addresses.',
},
QUIC_ERROR_MIGRATING_PORT: {
code: 86,
message: 'There was an error encountered migrating port only.',
},
QUIC_PACKET_WRITE_ERROR: {
code: 27,
message: 'There was an error while writing to the socket.',
},
QUIC_PACKET_READ_ERROR: {
code: 51,
message: 'There was an error while reading from the socket.',
},
QUIC_EMPTY_STREAM_FRAME_NO_FIN: {
code: 50,
message: 'We received a STREAM_FRAME with no data and no fin flag set.',
},
QUIC_INVALID_HEADERS_STREAM_DATA: {
code: 56,
message: 'We received invalid data on the headers stream.',
},
QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE: {
code: 97,
message: 'Invalid data on the headers stream received because of decompression failure.',
},
QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA: {
code: 59,
message: 'The peer received too much data, violating flow control.',
},
QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA: {
code: 63,
message: 'The peer sent too much data, violating flow control.',
},
QUIC_FLOW_CONTROL_INVALID_WINDOW: {
code: 64,
message: 'The peer received an invalid flow control window.',
},
QUIC_CONNECTION_IP_POOLED: {
code: 62,
message: 'The connection has been IP pooled into an existing connection.',
},
QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS: {
code: 68,
message: 'The connection has too many outstanding sent packets.',
},
QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS: {
code: 69,
message: 'The connection has too many outstanding received packets.',
},
QUIC_CONNECTION_CANCELLED: {
code: 70,
message: 'The quic connection has been cancelled.',
},
QUIC_BAD_PACKET_LOSS_RATE: {
code: 71,
message: 'Disabled QUIC because of high packet loss rate.',
},
QUIC_PUBLIC_RESETS_POST_HANDSHAKE: {
code: 73,
message: 'Disabled QUIC because of too many PUBLIC_RESETs post handshake.',
},
QUIC_FAILED_TO_SERIALIZE_PACKET: {
code: 75,
message: 'Closed because we failed to serialize a packet.',
},
QUIC_TOO_MANY_RTOS: {
code: 85,
message: 'QUIC timed out after too many RTOs.',
},
QUIC_HANDSHAKE_FAILED: {
code: 28,
message: 'Hanshake failed.',
},
QUIC_CRYPTO_TAGS_OUT_OF_ORDER: {
code: 29,
message: 'Handshake message contained out of order tags.',
},
QUIC_CRYPTO_TOO_MANY_ENTRIES: {
code: 30,
message: 'Handshake message contained too many entries.',
},
QUIC_CRYPTO_INVALID_VALUE_LENGTH: {
code: 31,
message: 'Handshake message contained an invalid value length.',
},
QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE: {
code: 32,
message: 'A crypto message was received after the handshake was complete.',
},
QUIC_INVALID_CRYPTO_MESSAGE_TYPE: {
code: 33,
message: 'A crypto message was received with an illegal message tag.',
},
QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER: {
code: 34,
message: 'A crypto message was received with an illegal parameter.',
},
QUIC_INVALID_CHANNEL_ID_SIGNATURE: {
code: 52,
message: 'An invalid channel id signature was supplied.',
},
QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND: {
code: 35,
message: 'A crypto message was received with a mandatory parameter missing.',
},
QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP: {
code: 36,
message: 'A crypto message was received with a parameter that has no overlap with the local parameter.',
},
QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND: {
code: 37,
message: 'A crypto message was received that contained a parameter with too few values.',
},
QUIC_UNSUPPORTED_PROOF_DEMAND: {
code: 94,
message: 'A demand for an unsupport proof type was received.',
},
QUIC_CRYPTO_INTERNAL_ERROR: {
code: 38,
message: 'An internal error occured in crypto processing.',
},
QUIC_CRYPTO_VERSION_NOT_SUPPORTED: {
code: 39,
message: 'A crypto handshake message specified an unsupported version.',
},
QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT: {
code: 72,
message: 'A crypto handshake message resulted in a stateless reject.',
},
QUIC_CRYPTO_NO_SUPPORT: {
code: 40,
message: 'There was no intersection between the crypto primitives supported by the peer and ourselves.',
},
QUIC_CRYPTO_TOO_MANY_REJECTS: {
code: 41,
message: 'The server rejected our client hello messages too many times.',
},
QUIC_PROOF_INVALID: {
code: 42,
message: 'The client rejected the server\'s certificate chain or signature.',
},
QUIC_CRYPTO_DUPLICATE_TAG: {
code: 43,
message: 'A crypto message was received with a duplicate tag.',
},
QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT: {
code: 44,
// i.e. it should have been encrypted but was not.
message: 'A crypto message was received with the wrong encryption level.',
},
QUIC_CRYPTO_SERVER_CONFIG_EXPIRED: {
code: 45,
message: 'The server config for a server has expired.',
},
QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED: {
code: 53,
message: 'We failed to setup the symmetric keys for a connection.',
},
QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO: {
code: 54,
message: 'A handshake message arrived, but we are still validating the previous handshake message.',
},
QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE: {
code: 65,
message: 'A server config update arrived before the handshake is complete.',
},
QUIC_CRYPTO_CHLO_TOO_LARGE: {
code: 90,
message: 'CHLO cannot fit in one packet.',
},
QUIC_VERSION_NEGOTIATION_MISMATCH: {
code: 55,
message: 'This connection involved a version negotiation which appears to have been tampered with.',
},
QUIC_BAD_MULTIPATH_FLAG: {
code: 79,
message: 'Multipath is not enabled, but a packet with multipath flag on is received.',
},
QUIC_MULTIPATH_PATH_DOES_NOT_EXIST: {
code: 91,
message: 'A path is supposed to exist but does not.',
},
QUIC_MULTIPATH_PATH_NOT_ACTIVE: {
code: 92,
message: 'A path is supposed to be active but is not.',
},
QUIC_IP_ADDRESS_CHANGED: {
code: 80,
message: 'IP address changed causing connection close.',
},
QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS: {
code: 81,
message: 'Network changed, but connection had no migratable streams.',
},
QUIC_CONNECTION_MIGRATION_TOO_MANY_CHANGES: {
code: 82,
message: 'Connection changed networks too many times.',
},
QUIC_CONNECTION_MIGRATION_NO_NEW_NETWORK: {
code: 83,
message: 'Connection migration was attempted, but there was no new network to migrate to.',
},
QUIC_CONNECTION_MIGRATION_NON_MIGRATABLE_STREAM: {
code: 84,
message: 'Network changed, but connection had one or more non-migratable streams.',
},
QUIC_TOO_MANY_FRAME_GAPS: {
code: 93,
message: 'Stream frames arrived too discontiguously so that stream sequencer buffer maintains too many gaps.',
},
QUIC_STREAM_SEQUENCER_INVALID_STATE: {
code: 95,
message: 'Sequencer buffer get into weird state where continuing read/write will lead to crash.',
},
QUIC_TOO_MANY_SESSIONS_ON_SERVER: {
code: 96,
message: 'Connection closed because of server hits max number of sessions allowed.',
},
QUIC_LAST_ERROR: {
code: 98,
// No error. Used as bound while iterating.
message: 'No error',
},
});
const _errors = errors;
for (const key of Object.keys(errors)) {
const error = _errors[key];
error.name = key;
_errors[error.code] = error;
}
const _streamErrors = streamErrors;
for (const key of Object.keys(streamErrors)) {
const error = _streamErrors[key];
error.name = key;
_streamErrors[error.code] = error;
}
/** QUICError representing a QUIC Error. */
class QUICError extends Error {
static fromError(err = errors.QUIC_NO_ERROR) {
if (err instanceof QUICError) {
return err;
}
switch (typeof err) {
case 'string':
return new QUICError(err);
case 'number':
return new QUICError(err);
}
return new QUICError(err.code >= 0 ? err.code : err.message);
}
static fromBuffer(bufv) {
bufv.walk(4);
if (bufv.isOutside()) {
throw new QUICError('INVALID_ERROR_CODE');
}
const code = bufv.buf.readUInt32BE(bufv.start);
return new QUICError(code);
}
static checkAny(err) {
if (err == null) {
return null;
}
if (err instanceof QUICStreamError) {
return err;
}
return QUICError.fromError(err);
}
constructor(nameOrCode) {
const error = _errors[nameOrCode] == null ? INVALID_ERROR : _errors[nameOrCode];
super(error !== INVALID_ERROR ? error.message : nameOrCode);
this.name = error.name;
this.code = error.code;
Error.captureStackTrace(this, QUICError);
}
get isNoError() {
return this.code === errors.QUIC_NO_ERROR.code;
}
valueOf() {
return {
name: this.name,
code: this.code,
message: this.message,
};
}
byteLen() {
return 4;
}
writeTo(bufv) {
bufv.walk(4);
if (bufv.isOutside()) {
throw new QUICError('INVALID_ERROR_CODE');
}
bufv.buf.writeUInt32BE(this.code, bufv.start);
return bufv;
}
}
exports.QUICError = QUICError;
/** QUICError representing a QUIC Stream Error. */
class QUICStreamError extends Error {
static fromError(err = streamErrors.QUIC_STREAM_NO_ERROR) {
if (err instanceof QUICStreamError) {
return err;
}
switch (typeof err) {
case 'string':
return new QUICStreamError(err);
case 'number':
return new QUICStreamError(err);
}
return new QUICStreamError(err.code >= 0 ? err.code : err.message);
}
static fromBuffer(bufv) {
bufv.walk(4);
if (bufv.isOutside()) {
throw new QUICError('INVALID_ERROR_CODE');
}
const code = bufv.buf.readUInt32BE(bufv.start);
return new QUICStreamError(code);
}
static checkAny(err) {
if (err == null) {
return null;
}
if (err instanceof QUICError) {
return err;
}
return QUICStreamError.fromError(err);
}
constructor(nameOrCode) {
const error = _streamErrors[nameOrCode] == null ? INVALID_RST_STREAM_ERROR : _streamErrors[nameOrCode];
super(error !== INVALID_RST_STREAM_ERROR ? error.message : nameOrCode);
this.name = error.name;
this.code = error.code;
Error.captureStackTrace(this, QUICStreamError);
}
get isNoError() {
return this.code === streamErrors.QUIC_STREAM_NO_ERROR.code;
}
valueOf() {
return {
name: this.name,
code: this.code,
message: this.message,
};
}
byteLen() {
return 4;
}
writeTo(bufv) {
bufv.walk(4);
if (bufv.isOutside()) {
throw new QUICError('INVALID_ERROR_CODE');
}
bufv.buf.writeUInt32BE(this.code, bufv.start);
return bufv;
}
}
exports.QUICStreamError = QUICStreamError;
exports.QuicError = Object.assign(QUICError, errors);
exports.StreamError = Object.assign(QUICStreamError, streamErrors);
//# sourceMappingURL=error.js.map