UNPKG

@cucumber/cucumber

Version:

The official JavaScript implementation of Cucumber.

117 lines 4.45 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const node_stream_1 = require("node:stream"); const node_fs_1 = __importDefault(require("node:fs")); const node_http_1 = __importDefault(require("node:http")); const node_https_1 = __importDefault(require("node:https")); const tmp_1 = __importDefault(require("tmp")); const value_checker_1 = require("../value_checker"); /** * This Writable writes data to a HTTP/HTTPS URL. * * It has special handling for https://reports.cucumber.io/ * which uses an API where the first request is a `GET`, * and if the response is 202 with a Location header, issues * a PUT request to that URL. * * 3xx redirects are not currently followed. */ class HttpStream extends node_stream_1.Transform { url; method; headers; tempFilePath; tempFile; constructor(url, method, headers) { super({ readableObjectMode: true, }); this.url = url; this.method = method; this.headers = headers; } _write(chunk, encoding, callback) { if (this.tempFile === undefined) { tmp_1.default.file((err, name, fd) => { if ((0, value_checker_1.doesHaveValue)(err)) return callback(err); this.tempFilePath = name; this.tempFile = node_fs_1.default.createWriteStream(name, { fd }); this.tempFile.write(chunk, encoding, callback); }); } else { this.tempFile.write(chunk, encoding, callback); } } _final(callback) { this.tempFile.end(() => { this.sendHttpRequest(this.url, this.method, this.headers, (err1, res1) => { if ((0, value_checker_1.doesHaveValue)(err1)) return callback(err1); this.pushResponseBody(res1, () => { this.emitErrorUnlessHttp2xx(res1, this.url, this.method); if (res1.statusCode === 202 && res1.headers.location !== undefined) { this.sendHttpRequest(res1.headers.location, 'PUT', {}, (err2, res2) => { if ((0, value_checker_1.doesHaveValue)(err2)) return callback(err2); this.emitErrorUnlessHttp2xx(res2, res1.headers.location, 'PUT'); callback(); }); } else { callback(); } }); }); }); } pushResponseBody(res, done) { let body = Buffer.alloc(0); res.on('data', (chunk) => { body = Buffer.concat([body, chunk]); }); res.on('end', () => { this.push(body.toString('utf-8')); done(); }); } emitErrorUnlessHttp2xx(res, url, method) { if (res.statusCode >= 300) this.emit('error', new Error(`Unexpected http status ${res.statusCode} from ${method} ${url}`)); } sendHttpRequest(url, method, headers, callback) { const httpx = (0, value_checker_1.doesHaveValue)(url.match(/^https:/)) ? node_https_1.default : node_http_1.default; const additionalHttpHeaders = {}; const upload = method === 'PUT' || method === 'POST'; if (upload) { additionalHttpHeaders['Content-Length'] = node_fs_1.default.statSync(this.tempFilePath).size; } const allHeaders = { ...headers, ...additionalHttpHeaders }; const req = httpx.request(url, { method, headers: allHeaders, }); req.on('error', (err) => this.emit('error', err)); req.on('response', (res) => { res.on('error', (err) => this.emit('error', err)); callback(null, res); }); if (upload) { (0, node_stream_1.pipeline)(node_fs_1.default.createReadStream(this.tempFilePath), req, (err) => { if ((0, value_checker_1.doesHaveValue)(err)) { this.emit('error', err); } }); } else { req.end(); } } } exports.default = HttpStream; //# sourceMappingURL=http_stream.js.map