UNPKG

@sap-cloud-sdk/core

Version:
208 lines • 8.38 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.isHttpSuccessCode = exports.parseBatchResponse = exports.parseResponseData = exports.parseHttpCode = exports.splitResponse = exports.splitChangeSetResponse = exports.splitBatchResponse = exports.getResponseBody = exports.detectNewLineSymbol = void 0; var util_1 = require("@sap-cloud-sdk/util"); var logger = (0, util_1.createLogger)({ package: 'core', messageContext: 'batch-response-parser' }); /** * Detects the system dependent line break in a string. * @param str - The string to check for line breaks. Should have at least two lines, otherwise an error will be thrown. * @returns The system dependent line break */ function detectNewLineSymbol(str) { if (str.includes(util_1.webEOL)) { return util_1.webEOL; } if (str.includes(util_1.unixEOL)) { return util_1.unixEOL; } throw new Error('Cannot detect line breaks in the batch response body.'); } exports.detectNewLineSymbol = detectNewLineSymbol; /** * Get the response body from the string representation of a response. * @param response - String representation of a response. * @returns The response body as a one line string. */ function getResponseBody(response) { var newLineSymbol = detectNewLineSymbol(response); var lines = response.split(newLineSymbol); // A valid response should contain at least three lines, part id, empty line and response body. if (lines.length >= 3) { return lines[lines.length - 1]; } throw Error("Cannot parse batch subrequest response body. Expected at least three lines in the response, got ".concat(lines.length, ".")); } exports.getResponseBody = getResponseBody; /** * Parse the headers in the string representation of a response headers into an object. This will only look at the highest level of headers. * @param response - String representation of a response * @returns The headers as an object. */ function parseHeaders(response) { var newLineSymbol = detectNewLineSymbol(response); // split on the first empty line var responseHeaders = response.split(newLineSymbol + newLineSymbol)[0]; return responseHeaders.split(newLineSymbol).reduce(function (headers, line) { var _a; var _b = line.split(':'), key = _b[0], value = _b[1]; return __assign(__assign({}, headers), (_a = {}, _a[key] = value === null || value === void 0 ? void 0 : value.trim(), _a)); }, {}); } /** * Get the boundary from the content type header value. Throws an error if no boundary can be found. * @param contentType - Value of the content type header * @returns The boundary. */ function getBoundary(contentType) { var boundary = (contentType === null || contentType === void 0 ? void 0 : contentType.match(/.*boundary=.+/)) ? (0, util_1.last)(contentType.split('boundary=')) : undefined; if (!boundary) { throw new Error('No boundary found.'); } return boundary; } /** * Split a batch response into an array of sub responses for the retrieve requests and changesets. * @param response - The raw HTTP response. * @returns A list of sub responses represented as strings. */ function splitBatchResponse(response) { var body = response.data.trim(); if (!body) { return []; } try { var boundary = getBoundary((0, util_1.pickValueIgnoreCase)(response.headers, 'content-type')); return splitResponse(body, boundary); } catch (err) { throw new util_1.ErrorWithCause('Could not parse batch response.', err); } } exports.splitBatchResponse = splitBatchResponse; /** * Split a changeset (sub) response into an array of sub responses. * @param changeSetResponse - The string representation of a change set response. * @returns A list of sub responses represented as strings. */ function splitChangeSetResponse(changeSetResponse) { var headers = parseHeaders(changeSetResponse); try { var boundary = getBoundary((0, util_1.pickValueIgnoreCase)(headers, 'content-type')); return splitResponse(changeSetResponse, boundary); } catch (err) { throw new util_1.ErrorWithCause('Could not parse change set response.', err); } } exports.splitChangeSetResponse = splitChangeSetResponse; /** * Split a string representation of a response into sub responses given its boundary. * @param response - The string representation of the response to split. * @param boundary - The boundary to split by. * @returns A list of sub responses represented as strings. */ function splitResponse(response, boundary) { var newLineSymbol = detectNewLineSymbol(response); var parts = response.split("--".concat(boundary)).map(function (part) { var trimmedPart = part.trim(); return trimmedPart.includes('204 No Content') || (trimmedPart.includes('200 OK') && trimmedPart.includes('Content-Length: 0')) ? "".concat(trimmedPart).concat(newLineSymbol) : trimmedPart; }); if (parts.length >= 3) { return parts.slice(1, parts.length - 1); } throw new Error('Could not parse batch response body. Expected at least two response boundaries.'); } exports.splitResponse = splitResponse; /** * Parse the HTTP code of response. * @param response - String representation of the response. * @returns The HTTP code. */ function parseHttpCode(response) { var group = response.match(/HTTP\/\d\.\d (\d{3}).*?/); if (group) { return parseInt(group[1].toString()); } throw new Error('Cannot parse http code of the response.'); } exports.parseHttpCode = parseHttpCode; /** * Get the body from the given response and parse it to JSON. * @param response - The string representation of a single response. * @returns The parsed JSON representation of the response body. */ function parseResponseBody(response) { var responseBody = getResponseBody(response); if (responseBody) { try { return JSON.parse(responseBody); } catch (err) { logger.error("Could not parse response body. Invalid JSON. Original Error: ".concat(err)); } } return {}; } /** * Parse the body and http code of a batch sub response. * @param response - A batch sub response. * @returns The parsed response.s */ function parseResponseData(response) { return { body: parseResponseBody(response), httpCode: parseHttpCode(response) }; } exports.parseResponseData = parseResponseData; /** * Parse the complete batch HTTP response. * @param batchResponse - HTTP response of a batch request. * @returns An array of parsed sub responses of the batch response. */ function parseBatchResponse(batchResponse) { return splitBatchResponse(batchResponse).map(function (response) { var contentType = (0, util_1.pickValueIgnoreCase)(parseHeaders(response), 'content-type'); if (isChangeSetContentType(contentType)) { return splitChangeSetResponse(response).map(function (subResponse) { return parseResponseData(subResponse); }); } if (isRetrieveOrErrorContentType(contentType)) { return parseResponseData(response); } throw Error("Cannot parse batch response. Unknown subresponse 'Content-Type' header '".concat(contentType, "'.")); }); } exports.parseBatchResponse = parseBatchResponse; function isChangeSetContentType(contentType) { return contentType === null || contentType === void 0 ? void 0 : contentType.trim().startsWith('multipart/mixed'); } function isRetrieveOrErrorContentType(contentType) { return contentType === null || contentType === void 0 ? void 0 : contentType.trim().startsWith('application/http'); } function isHttpSuccessCode(httpCode) { return httpCode >= 200 && httpCode < 300; } exports.isHttpSuccessCode = isHttpSuccessCode; //# sourceMappingURL=batch-response-parser.js.map