"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.error = exports.sendRequest = void 0; const file_request_1 = __importDefault(require("./file-request")); const destination_request_1 = __importDefault(require("./destination-request")); const messages_1 = require("../messages"); const logger_1 = __importDefault(require("../utils/logger")); const http_header_parser_1 = require("./http-header-parser"); // An empty line that indicates the end of the header section // https://tools.ietf.org/html/rfc7230#section-3 const HTTP_BODY_SEPARATOR = '\r\n\r\n'; // Used to calculate the recommended maximum header size // See getRecommendedMaxHeaderSize() below const HEADER_SIZE_MULTIPLIER = 2; const HEADER_SIZE_CALCULATION_PRECISION = 2; // Calculates the HTTP header size in bytes that a customer should specify via the // --max-http-header-size Node option so that the proxy can process the site // https://nodejs.org/api/cli.html#cli_max_http_header_size_size // Example: // (8211 * 2).toPrecision(2) -> 16 * 10^3 -> 16000 function getRecommendedMaxHeaderSize(currentHeaderSize) { return Number((currentHeaderSize * HEADER_SIZE_MULTIPLIER).toPrecision(HEADER_SIZE_CALCULATION_PRECISION)); } function sendRequest(ctx) { return new Promise(resolve => { const req = ctx.isFileProtocol ? new file_request_1.default(ctx.reqOpts.url) : new destination_request_1.default(ctx.reqOpts, ctx.serverInfo.cacheRequests); ctx.goToNextStage = false; req.on('response', (res) => { if (ctx.isWebSocketConnectionReset) { res.destroy(); resolve(); return; } ctx.destRes = res; ctx.goToNextStage = true; ctx.buildContentInfo(); ctx.calculateIsDestResReadableEnded(); ctx.createCacheEntry(res); resolve(); }); req.on('error', err => { // NOTE: Sometimes the underlying socket emits an error event. But if we have a response body, // we can still process such requests. (B234324) if (!ctx.isDestResReadableEnded) { const rawHeadersStr = err.rawPacket ? err.rawPacket.asciiSlice().split(HTTP_BODY_SEPARATOR)[0].split('\n').splice(1).join('\n') : ''; const headerSize = rawHeadersStr.length; error(ctx, (0, messages_1.getText)(messages_1.MESSAGE.destConnectionTerminated, { url: ctx.dest.url, message: messages_1.MESSAGE.nodeError[err.code] || err.toString(), headerSize: headerSize, recommendedMaxHeaderSize: getRecommendedMaxHeaderSize(headerSize).toString(), invalidChars: (0, http_header_parser_1.getFormattedInvalidCharacters)(rawHeadersStr), })); } resolve(); }); req.on('fatalError', err => { if (ctx.isFileProtocol) logger_1.default.destination.onFileReadError(ctx, err); error(ctx, err); resolve(); }); req.on('socketHangUp', () => { ctx.req.socket.end(); resolve(); }); if (req instanceof file_request_1.default) { logger_1.default.destination.onFileRead(ctx); req.init(); } }); } exports.sendRequest = sendRequest; function error(ctx, err) { if (ctx.isPage && !ctx.isIframe) ctx.session.handlePageError(ctx, err); else if (ctx.isAjax) ctx.req.destroy(); else ctx.closeWithError(500, err.toString()); } exports.error = error;