pluto-http-client
Version:
HTTP client for NodeJS. Inspired in the Java JAX-RS spec so you can expect excellence, versatility and extensibility.
225 lines (224 loc) • 7.92 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.HttpNodeRequest = exports.Http2NodeRequest = exports.NodeRequest = void 0;
const method_1 = require("../method");
const url_1 = require("url");
const https_1 = __importDefault(require("https"));
const http_1 = __importDefault(require("http"));
const header_1 = require("../header");
const http_headers_1 = require("../http-headers");
const collections_1 = require("../../utils/collections");
const stream_1 = require("stream");
const request_context_1 = require("../request-context");
const http2_1 = require("http2");
const node_response_1 = require("./node-response");
const buffer_1 = require("buffer");
class NodeRequest {
constructor(client, url, abortSignal) {
this._transformers = [];
this._url = url;
this._client = client;
this._method = method_1.Method.GET;
this.headers = this._client.headers;
this._abortSignal = abortSignal;
}
getHeaders() {
return (0, http_headers_1.fromMap)(this.headers);
}
setHeader(key, value) {
this.headers.add(new header_1.Header(key, value));
}
accept(mediaType) {
this.setHeader(http_headers_1.HttpHeaders.ACCEPT, mediaType.toString());
return this;
}
acceptEncoding(encoding) {
this.setHeader(encoding.key, encoding.value);
this._client.filters.put(encoding.order(), encoding);
return this;
}
acceptLanguage(locale) {
this.setHeader(http_headers_1.HttpHeaders.ACCEPT_LANGUAGE, locale);
return this;
}
build(method, entity) {
this._method = method;
return this.makeRequest(entity);
}
cacheControl(cacheControl) {
this.setHeader(http_headers_1.HttpHeaders.CACHE_CONTROL, cacheControl.toString());
return this;
}
cookie(cookie) {
this.setHeader(http_headers_1.HttpHeaders.COOKIE, cookie.toString());
return this;
}
delete(entity) {
this._method = method_1.Method.DELETE;
return this.makeRequest(entity);
}
get() {
return this.makeRequest();
}
header(key, value) {
this.setHeader(key, value);
return this;
}
post(entity) {
this._method = method_1.Method.POST;
return this.makeRequest(entity);
}
put(entity) {
this._method = method_1.Method.PUT;
return this.makeRequest(entity);
}
executePreFilters(request) {
for (let filters of this._client.filters.subMap(Number.MIN_SAFE_INTEGER, 0)) {
for (const [_, filter] of filters.entries()) {
filter.filter(request);
}
}
}
executePostFilters(request, response) {
for (let filters of this._client.filters.subMap(0, Number.MAX_SAFE_INTEGER)) {
for (const [_, filter] of filters.entries()) {
filter.filter(request, response);
}
}
}
makeRequest(entity) {
if (entity) {
this.header(http_headers_1.HttpHeaders.CONTENT_TYPE, entity.mediaType.toString());
}
return this.execute(entity);
}
transform(transform) {
this._transformers.push(transform);
}
getUrl() {
return this._url;
}
getMethod() {
return this._method;
}
static writeEntity(entity, sink, transformers, cb) {
return entity
.marshal()
.then((data) => {
let bodyStream;
if (data instanceof stream_1.Readable) {
bodyStream = data;
}
else if (data instanceof buffer_1.Buffer) {
bodyStream = stream_1.Readable.from(data);
}
else {
bodyStream = stream_1.Readable.from(buffer_1.Buffer.from(data));
}
(0, stream_1.pipeline)(bodyStream, ...transformers, sink, (error) => {
if (error) {
cb(error);
}
});
});
}
}
exports.NodeRequest = NodeRequest;
class Http2NodeRequest extends NodeRequest {
constructor(client, url, session, abortSignal, error) {
super(client, url, abortSignal);
this._req = session;
this._responseHeaders = new collections_1.MultiValueMap();
this._error = error;
}
execute(entity) {
if (this._error) {
return Promise.reject(this._error);
}
return new Promise((resolve, reject) => {
const requestContext = new request_context_1.RequestContext(this);
const headers = (0, http_headers_1.fromMap)(this.headers);
headers[http2_1.constants.HTTP2_HEADER_METHOD] = this._method;
headers[http2_1.constants.HTTP2_HEADER_PATH] = this.getPath();
const stream = this._req.request(headers, {
endStream: !entity,
signal: this._abortSignal,
});
stream.on("response", (responseHeaders, _flags) => {
const response = new node_response_1.NodeResponse(responseHeaders, stream, responseHeaders[":status"]);
this.executePostFilters(requestContext, response);
resolve(response);
});
stream.on("error", (error) => {
reject(error);
});
stream.on("timeout", () => {
stream.destroy(new Error("Client Timeout"));
});
this.executePreFilters(requestContext);
if (entity) {
Http2NodeRequest
.writeEntity(entity, stream, this._transformers, reject)
.catch(reject);
}
else {
stream.end();
}
});
}
getPath() {
const urlParts = (0, url_1.urlToHttpOptions)(this._url);
let path = "/";
if (urlParts.path) {
path = urlParts.path;
}
if (urlParts.search) {
path += urlParts.search;
}
if (urlParts.hash) {
path += urlParts.hash;
}
return path;
}
}
exports.Http2NodeRequest = Http2NodeRequest;
class HttpNodeRequest extends NodeRequest {
execute(entity) {
return new Promise((resolve, reject) => {
const requestContext = new request_context_1.RequestContext(this);
const lib = this._url.protocol === 'https:' ? https_1.default : http_1.default;
this.req = lib.request(this._url, {
timeout: this._client.timeout,
headers: (0, http_headers_1.fromMap)(this.headers),
method: this._method,
agent: this._client.agent,
rejectUnauthorized: !this._client.allowInsecure,
signal: this._abortSignal,
}, (response) => {
const nodeResponse = new node_response_1.NodeResponse(response.headers, response, response.statusCode);
this.executePostFilters(requestContext, nodeResponse);
resolve(nodeResponse);
});
this.req.once('timeout', () => {
var _a;
(_a = this.req) === null || _a === void 0 ? void 0 : _a.destroy(new Error("Client timeout"));
});
this.req.once('error', (error) => {
reject(error);
});
this.executePreFilters(requestContext);
if (entity) {
HttpNodeRequest
.writeEntity(entity, this.req, this._transformers, reject)
.catch(reject);
}
else {
this.req.end();
}
});
}
}
exports.HttpNodeRequest = HttpNodeRequest;