UNPKG

aws-crt

Version:

NodeJS bindings to the aws-c-* libraries

230 lines 9.48 kB
"use strict"; /* * Copyright 2010-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. * A copy of the License is located at * * http://aws.amazon.com/apache2.0 * * or in the "license" file accompanying this file. This file is distributed * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language governing * permissions and limitations under the License. */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const binding_1 = __importDefault(require("./binding")); const native_resource_1 = require("./native_resource"); const error_1 = require("./error"); const http_1 = require("../common/http"); var http_2 = require("../common/http"); exports.HttpProxyAuthenticationType = http_2.HttpProxyAuthenticationType; const event_1 = require("../common/event"); exports.HttpHeaders = binding_1.default.HttpHeaders; exports.HttpRequest = binding_1.default.HttpRequest; /** Base class for HTTP connections */ class HttpConnection extends native_resource_1.NativeResourceMixin(event_1.BufferedEventEmitter) { constructor(native_handle) { super(); this._super(native_handle); } close() { binding_1.default.http_connection_close(this.native_handle()); } // Override to allow uncorking on ready on(event, listener) { super.on(event, listener); if (event == 'connect') { process.nextTick(() => { this.uncork(); }); } return this; } } exports.HttpConnection = HttpConnection; class HttpProxyOptions extends http_1.HttpProxyOptions { constructor(host_name, port, auth_method = http_1.HttpProxyAuthenticationType.None, auth_username, auth_password, tls_opts) { super(host_name, port, auth_method, auth_username, auth_password); this.tls_opts = tls_opts; } create_native_handle() { return binding_1.default.http_proxy_options_new(this.host_name, this.port, this.auth_method, this.auth_username, this.auth_password, this.tls_opts ? this.tls_opts.native_handle() : undefined); } } exports.HttpProxyOptions = HttpProxyOptions; /** Represents an HTTP connection from a client to a server */ class HttpClientConnection extends HttpConnection { constructor(bootstrap, host_name, port, socket_options, tls_opts, proxy_options, handle) { super(handle ? handle : binding_1.default.http_connection_new(bootstrap.native_handle(), (handle, error_code) => { this._on_setup(handle, error_code); }, (handle, error_code) => { this._on_shutdown(handle, error_code); }, host_name, port, socket_options.native_handle(), tls_opts ? tls_opts.native_handle() : undefined, proxy_options ? proxy_options.create_native_handle() : undefined)); this.bootstrap = bootstrap; this.socket_options = socket_options; this.tls_opts = tls_opts; } _on_setup(native_handle, error_code) { if (error_code) { this.emit('error', new error_1.CrtError(error_code)); return; } this.emit('connect'); } _on_shutdown(native_handle, error_code) { if (error_code) { this.emit('error', new error_1.CrtError(error_code)); return; } this.emit('close'); } /** * Make a client initiated request to this connection. * @param request - The HttpRequest to attempt on this connection * @returns A new stream that will deliver events for the request */ request(request) { let stream; const on_response_impl = (status_code, headers) => { stream._on_response(status_code, headers); }; const on_body_impl = (data) => { stream._on_body(data); }; const on_complete_impl = (error_code) => { stream._on_complete(error_code); }; const native_handle = binding_1.default.http_stream_new(this.native_handle(), request, on_complete_impl, on_response_impl, on_body_impl); return stream = new HttpClientStream(native_handle, this, request); } } exports.HttpClientConnection = HttpClientConnection; /** * Represents a single http message exchange (request/response) in HTTP/1.1. In H2, it may * also represent a PUSH_PROMISE followed by the accompanying response. * * NOTE: Binding either the ready or response event will uncork any buffered events and start * event delivery */ class HttpStream extends native_resource_1.NativeResourceMixin(event_1.BufferedEventEmitter) { constructor(native_handle, connection) { super(); this.connection = connection; this._super(native_handle); this.cork(); } /** * Closes and ends all communication on this stream. Called automatically after the 'end' * event is delivered. Calling this manually is only necessary if you wish to terminate * communication mid-request/response. */ close() { binding_1.default.http_stream_close(this.native_handle()); } _on_body(data) { this.emit('data', data); } _on_complete(error_code) { if (error_code) { this.emit('error', new error_1.CrtError(error_code)); this.close(); return; } // schedule death after end is delivered this.on('end', () => { this.close(); }); this.emit('end'); } } /** Represents a stream created on a client HTTP connection. {@see HttpStream} */ class HttpClientStream extends HttpStream { constructor(native_handle, connection, request) { super(native_handle, connection); this.request = request; } /** * HTTP status code returned from the server. * @return Either the status code, or undefined if the server response has not arrived yet. */ status_code() { return this.response_status_code; } // Override to allow uncorking on ready and response on(event, listener) { super.on(event, listener); if (event == 'response') { process.nextTick(() => { this.uncork(); }); } return this; } _on_response(status_code, header_array) { this.response_status_code = status_code; let headers = new exports.HttpHeaders(header_array); this.emit('response', status_code, headers); } } exports.HttpClientStream = HttpClientStream; /** Creates, manages, and vends connections to a given host/port endpoint */ class HttpClientConnectionManager extends native_resource_1.NativeResource { constructor(bootstrap, host, port, max_connections, initial_window_size, socket_options, tls_opts, proxy_options) { super(binding_1.default.http_connection_manager_new(bootstrap.native_handle(), host, port, max_connections, initial_window_size, socket_options.native_handle(), tls_opts ? tls_opts.native_handle() : undefined, proxy_options ? proxy_options.create_native_handle() : undefined, undefined /* on_shutdown */)); this.bootstrap = bootstrap; this.host = host; this.port = port; this.max_connections = max_connections; this.initial_window_size = initial_window_size; this.socket_options = socket_options; this.tls_opts = tls_opts; this.proxy_options = proxy_options; this.connections = new Map(); } /** * Vends a connection from the pool * @returns A promise that results in an HttpClientConnection. When done with the connection, return * it via {@link release} */ acquire() { return new Promise((resolve, reject) => { // Only create 1 connection in JS/TS from each native connection const on_acquired = (handle, error_code) => { if (error_code) { reject(new error_1.CrtError(error_code)); return; } let connection = this.connections.get(handle); if (!connection) { connection = new HttpClientConnection(this.bootstrap, this.host, this.port, this.socket_options, this.tls_opts, this.proxy_options, handle); this.connections.set(handle, connection); connection.on('close', () => { this.connections.delete(handle); }); } resolve(connection); }; binding_1.default.http_connection_manager_acquire(this.native_handle(), on_acquired); }); } /** * Returns an unused connection to the pool * @param connection - The connection to return */ release(connection) { binding_1.default.http_connection_manager_release(this.native_handle(), connection.native_handle()); } /** Closes all connections and rejects all pending requests */ close() { binding_1.default.http_connection_manager_close(this.native_handle()); } } exports.HttpClientConnectionManager = HttpClientConnectionManager; //# sourceMappingURL=http.js.map