diff --git a/dist/index.js b/dist/index.js index 933512cd..6c2f069d 100644 --- a/dist/index.js +++ b/dist/index.js @@ -718,7 +718,7 @@ \************************/(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "ArchiveRequest": () => (/* binding */ ArchiveRequest)\n/* harmony export */ });\n/* harmony import */ var warcio__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! warcio */ "./node_modules/warcio/dist/index.js");\n\nconst REPLAY_REGEX = /^(?::([\\w-]+)\\/)?(\\d*)([a-z]+_|[$][a-z0-9:.-]+)?(?:\\/|\\||%7C|%7c)(.+)/;\nclass ArchiveRequest {\n url = "";\n timestamp = "";\n mod = "";\n pageId = "";\n hash = "";\n cookie = "";\n request;\n method;\n mode;\n _postToGetConverted = false;\n constructor(wbUrlStr, request, { isRoot = false, mod = "", ts = "", proxyOrigin = null, localOrigin = null, } = {}) {\n const wbUrl = REPLAY_REGEX.exec(wbUrlStr);\n this.timestamp = ts;\n this.mod = mod;\n this.request = request;\n this.method = request.method;\n this.mode = request.mode;\n if (!wbUrl &&\n (wbUrlStr.startsWith("https:") ||\n wbUrlStr.startsWith("http:") ||\n wbUrlStr.startsWith("blob:"))) {\n this.url = wbUrlStr;\n }\n else if (!wbUrl && isRoot) {\n this.url = "https://" + wbUrlStr;\n }\n else if (!wbUrl) {\n this.url = "";\n return;\n }\n else {\n this.pageId = wbUrl[1] || "";\n this.timestamp = wbUrl[2];\n this.mod = wbUrl[3];\n this.url = wbUrl[4];\n }\n if (proxyOrigin && localOrigin) {\n const url = new URL(this.url);\n if (url.origin === localOrigin) {\n this.url = proxyOrigin + url.pathname + (url.search ? url.search : "");\n }\n }\n const hashIndex = this.url.indexOf("#");\n if (hashIndex > 0) {\n this.hash = this.url.slice(hashIndex);\n this.url = this.url.substring(0, hashIndex);\n }\n }\n get headers() {\n return this.request.headers;\n }\n get destination() {\n return this.request.destination;\n }\n get referrer() {\n return this.request.referrer;\n }\n async convertPostToGet() {\n if (this._postToGetConverted) {\n return this.url;\n }\n const request = this.request;\n if (request.method !== "POST" && request.method !== "PUT") {\n return this.url;\n }\n const data = {\n method: request.method,\n postData: await request.text(),\n headers: request.headers,\n url: this.url,\n };\n if ((0,warcio__WEBPACK_IMPORTED_MODULE_0__.postToGetUrl)(data)) {\n this.url = data.url;\n this.method = "GET";\n this.mode =\n this.request.mode === "navigate" ? "same-origin" : this.request.mode;\n this._postToGetConverted = true;\n }\n return this.url;\n }\n prepareProxyRequest(prefix, isLive = true) {\n let headers;\n let referrer;\n let credentials;\n if (isLive) {\n headers = new Headers(this.request.headers);\n referrer = this.request.referrer;\n const inx = referrer.indexOf("/http", prefix.length - 1);\n if (inx > 0) {\n referrer = referrer.slice(inx + 1);\n headers.set("X-Proxy-Referer", referrer);\n }\n credentials = this.request.credentials;\n if (this.cookie) {\n headers.set("X-Proxy-Cookie", this.cookie);\n }\n }\n else {\n headers = new Headers();\n credentials = "omit";\n }\n let url = this.url;\n if (url.startsWith("//") && referrer) {\n try {\n url = new URL(referrer).protocol + url;\n }\n catch (e) {\n url = "https:" + url;\n }\n }\n return { referrer, headers, credentials, url };\n }\n async getBody() {\n const request = this.request.clone();\n return new Uint8Array(await request.arrayBuffer());\n }\n}\n\n\n//# sourceURL=webpack://@webrecorder/wabac/./src/request.ts?')},"./src/response.ts": /*!*************************!*\ !*** ./src/response.ts ***! - \*************************/(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "ArchiveResponse": () => (/* binding */ ArchiveResponse)\n/* harmony export */ });\n/* harmony import */ var warcio__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! warcio */ "./node_modules/warcio/dist/index.js");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utils */ "./src/utils.ts");\n/* harmony import */ var buffer__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! buffer */ "./node_modules/buffer/index.js");\n\n\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n// ===========================================================================\nclass ArchiveResponse {\n static fromResponse({ url, response, date, noRW, isLive, archivePrefix, }) {\n const payload = response.body\n ? new warcio__WEBPACK_IMPORTED_MODULE_2__.AsyncIterReader(response.body.getReader(), null, false)\n : null;\n const status = Number(response.headers.get("x-redirect-status") || response.status);\n const statusText = response.headers.get("x-redirect-statusText") || response.statusText;\n let headers = new Headers(response.headers);\n let origLoc = headers.get("x-orig-location");\n if (origLoc) {\n if (origLoc.startsWith(self.location.origin)) {\n origLoc = origLoc.slice(self.location.origin.length);\n }\n if (archivePrefix && origLoc.startsWith(archivePrefix)) {\n const inx = origLoc.indexOf("/http");\n if (inx > 0) {\n origLoc = origLoc.slice(inx + 1);\n }\n }\n headers.set("location", origLoc);\n headers.delete("x-orig-location");\n headers.delete("x-redirect-status");\n headers.delete("x-redirect-statusText");\n }\n let updateTS = null;\n const origTs = headers.get("x-orig-ts");\n if (origTs) {\n date = (0,_utils__WEBPACK_IMPORTED_MODULE_0__.tsToDate)(origTs);\n headers.delete("x-orig-ts");\n // force TS update downstream\n if (origTs && origLoc) {\n updateTS = origTs;\n }\n }\n const mementoDt = headers.get("memento-datetime");\n if (mementoDt) {\n date = new Date(mementoDt);\n }\n const cookie = headers.get("x-proxy-set-cookie");\n if (cookie) {\n const cookies = [];\n cookie.split(",").forEach((c) => {\n const cval = c.split(";", 1)[0].trim();\n if (cval.indexOf("=") > 0) {\n cookies.push(cval);\n }\n });\n headers.delete("x-proxy-set-cookie");\n if (cookies.length) {\n headers.set("x-wabac-preset-cookie", cookies.join(";"));\n //console.log("cookies", cookies.join(";"));\n }\n }\n return new ArchiveResponse({\n payload,\n status,\n statusText,\n headers,\n url,\n date,\n noRW,\n isLive,\n updateTS,\n });\n }\n reader;\n buffer;\n status;\n statusText;\n url;\n date;\n extraOpts;\n headers;\n noRW;\n isLive;\n updateTS;\n clonedResponse = null;\n constructor({ payload, status, statusText, headers, url, date, extraOpts = null, noRW = false, isLive = false, updateTS = null, }) {\n this.reader = null;\n this.buffer = null;\n if (payload && payload instanceof warcio__WEBPACK_IMPORTED_MODULE_2__.BaseAsyncIterReader) {\n this.reader = payload;\n }\n else {\n this.buffer = payload;\n }\n this.status = status;\n this.statusText = statusText;\n this.headers = headers;\n this.url = url;\n this.date = date;\n this.extraOpts = extraOpts;\n this.noRW = noRW;\n this.isLive = isLive;\n this.updateTS = updateTS;\n }\n async getText(isUTF8 = false) {\n let buff = await this.getBuffer();\n if (typeof buff === "string") {\n return { bomFound: false, text: buff };\n }\n if (!buff) {\n return { bomFound: false, text: "" };\n }\n // Check for BOMs -- since we\'re removing BOM, set \'bomFound\'\n // to re-encode as UTF-8 without BOM\n // UTF-8\n if (buff[0] === 0xef && buff[1] === 0xbb && buff[2] === 0xbf) {\n return { bomFound: true, text: decoder.decode(buff.slice(3)) };\n // UTF-16BE -- convert to buffer, swap, and decode LE\n }\n else if (buff[0] === 0xfe && buff[1] === 0xff) {\n return {\n bomFound: true,\n text: buffer__WEBPACK_IMPORTED_MODULE_1__.Buffer.from(buff.slice(2)).swap16().toString("utf16le"),\n };\n // UTF-16LE -- convert to buffer, decode LE\n }\n else if (buff[0] === 0xff && buff[1] === 0xfe) {\n return {\n bomFound: true,\n text: buffer__WEBPACK_IMPORTED_MODULE_1__.Buffer.from(buff.slice(2)).toString("utf16le"),\n };\n }\n // if no BOM, go by \'isUTF8\' param\n return {\n bomFound: false,\n text: isUTF8 ? decoder.decode(buff) : (0,_utils__WEBPACK_IMPORTED_MODULE_0__.decodeLatin1)(buff),\n };\n }\n setText(text, encodeUTF8 = false) {\n this.setBuffer(encodeUTF8 ? encoder.encode(text) : (0,_utils__WEBPACK_IMPORTED_MODULE_0__.encodeLatin1)(text));\n }\n async getBuffer() {\n if (this.buffer || !this.reader) {\n return this.buffer;\n }\n this.buffer = await this.reader.readFully();\n return this.buffer;\n }\n setBuffer(buffer) {\n this.buffer = buffer;\n this.reader = null;\n }\n setReader(reader) {\n if (reader instanceof warcio__WEBPACK_IMPORTED_MODULE_2__.BaseAsyncIterReader) {\n this.reader = reader;\n this.buffer = null;\n }\n else if (reader.getReader) {\n this.reader = new warcio__WEBPACK_IMPORTED_MODULE_2__.AsyncIterReader(reader.getReader());\n this.buffer = null;\n }\n }\n expectedLength() {\n if (this.buffer) {\n return this.buffer.length;\n }\n //TODO\n // else if (this.reader && this.reader.reader) {\n // return this.reader.reader.length;\n // }\n return 0;\n }\n createIter() {\n const buffer = this.buffer;\n const reader = this.reader;\n async function* iter() {\n if (buffer) {\n for (let i = 0; i < buffer.length; i += _utils__WEBPACK_IMPORTED_MODULE_0__.MAX_STREAM_CHUNK_SIZE) {\n yield buffer.slice(i, i + _utils__WEBPACK_IMPORTED_MODULE_0__.MAX_STREAM_CHUNK_SIZE);\n }\n }\n else if (reader) {\n yield* reader;\n }\n }\n return iter();\n }\n async *[Symbol.asyncIterator]() {\n yield* this.createIter();\n }\n setRange(range) {\n if (this.status === 206) {\n const currRange = this.headers.get("Content-Range");\n if (currRange && !currRange.startsWith("bytes 0-")) {\n return false;\n }\n }\n const bytes = range.match(/^bytes=(\\d+)-(\\d+)?$/);\n let length = 0;\n if (this.buffer) {\n length = this.buffer.length;\n }\n else if (this.reader) {\n //length = this.reader.length;\n length = Number(this.headers.get("content-length"));\n // if length is not known, keep as 200\n if (!length) {\n return false;\n }\n }\n if (!bytes) {\n this.status = 416;\n this.statusText = "Range Not Satisfiable";\n this.headers.set("Content-Range", `*/${length}`);\n return false;\n }\n const start = Number(bytes[1]);\n const end = Number(bytes[2]) || length - 1;\n if (this.buffer) {\n this.buffer = this.buffer.slice(start, end + 1);\n }\n else if (this.reader) {\n if (!(this.reader instanceof warcio__WEBPACK_IMPORTED_MODULE_2__.LimitReader) || !this.reader.setLimitSkip) {\n return false;\n }\n if (start !== 0 || end !== length - 1) {\n this.reader.setLimitSkip(end - start + 1, start);\n }\n //TODO\n // } else if (this.reader.setRangeAll) {\n // this.reader.setRangeAll(length);\n // }\n }\n this.headers.set("Content-Range", `bytes ${start}-${end}/${length}`);\n this.headers.set("Content-Length", String(end - start + 1));\n this.status = 206;\n this.statusText = "Partial Content";\n return true;\n }\n makeResponse(coHeaders = false, overwriteDisposition = false) {\n let body = null;\n if (!(0,_utils__WEBPACK_IMPORTED_MODULE_0__.isNullBodyStatus)(this.status)) {\n body =\n this.buffer || !this.reader\n ? this.buffer\n : this.reader.getReadableStream();\n }\n const response = new Response(body, {\n status: this.status,\n statusText: this.statusText,\n headers: this.headers,\n });\n // slightly hacky\n response.date = this.date;\n if (coHeaders) {\n response.headers.set("Cross-Origin-Opener-Policy", "same-origin");\n response.headers.set("Cross-Origin-Embedder-Policy", "require-corp");\n }\n if (overwriteDisposition) {\n response.headers.set("content-disposition", "inline");\n }\n return response;\n }\n}\n\n\n\n//# sourceURL=webpack://@webrecorder/wabac/./src/response.ts?')},"./src/rewrite/decoder.ts": + \*************************/(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "ArchiveResponse": () => (/* binding */ ArchiveResponse)\n/* harmony export */ });\n/* harmony import */ var warcio__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! warcio */ "./node_modules/warcio/dist/index.js");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utils */ "./src/utils.ts");\n/* harmony import */ var buffer__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! buffer */ "./node_modules/buffer/index.js");\n\n\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n// ===========================================================================\nclass ArchiveResponse {\n static fromResponse({ url, response, date, noRW, isLive, archivePrefix, }) {\n const payload = response.body\n ? new warcio__WEBPACK_IMPORTED_MODULE_2__.AsyncIterReader(response.body.getReader(), null, false)\n : null;\n const status = Number(response.headers.get("x-redirect-status") || response.status);\n const statusText = response.headers.get("x-redirect-statusText") || response.statusText;\n let headers = new Headers(response.headers);\n let origLoc = headers.get("x-orig-location");\n if (origLoc) {\n if (origLoc.startsWith(self.location.origin)) {\n origLoc = origLoc.slice(self.location.origin.length);\n }\n if (archivePrefix && origLoc.startsWith(archivePrefix)) {\n const inx = origLoc.indexOf("/http");\n if (inx > 0) {\n origLoc = origLoc.slice(inx + 1);\n }\n }\n headers.set("location", origLoc);\n headers.delete("x-orig-location");\n headers.delete("x-redirect-status");\n headers.delete("x-redirect-statusText");\n }\n let updateTS = null;\n const origTs = headers.get("x-orig-ts");\n if (origTs) {\n date = (0,_utils__WEBPACK_IMPORTED_MODULE_0__.tsToDate)(origTs);\n headers.delete("x-orig-ts");\n // force TS update downstream\n if (origTs && origLoc) {\n updateTS = origTs;\n }\n }\n const mementoDt = headers.get("memento-datetime");\n if (mementoDt) {\n date = new Date(mementoDt);\n }\n const cookie = headers.get("x-proxy-set-cookie");\n if (cookie) {\n const cookies = [];\n cookie.split(",").forEach((c) => {\n const cval = c.split(";", 1)[0].trim();\n if (cval.indexOf("=") > 0) {\n cookies.push(cval);\n }\n });\n headers.delete("x-proxy-set-cookie");\n if (cookies.length) {\n headers.set("x-wabac-preset-cookie", cookies.join(";"));\n //console.log("cookies", cookies.join(";"));\n }\n }\n return new ArchiveResponse({\n payload,\n status,\n statusText,\n headers,\n url,\n date,\n noRW,\n isLive,\n updateTS,\n });\n }\n reader;\n buffer;\n status;\n statusText;\n url;\n date;\n extraOpts;\n headers;\n noRW;\n isLive;\n updateTS;\n clonedResponse = null;\n constructor({ payload, status, statusText, headers, url, date, extraOpts = null, noRW = false, isLive = false, updateTS = null, }) {\n this.reader = null;\n this.buffer = null;\n if (payload && payload instanceof warcio__WEBPACK_IMPORTED_MODULE_2__.BaseAsyncIterReader) {\n this.reader = payload;\n }\n else {\n this.buffer = payload;\n }\n this.status = status;\n this.statusText = statusText || (0,_utils__WEBPACK_IMPORTED_MODULE_0__.getStatusText)(status);\n this.headers = headers;\n this.url = url;\n this.date = date;\n this.extraOpts = extraOpts;\n this.noRW = noRW;\n this.isLive = isLive;\n this.updateTS = updateTS;\n }\n async getText(isUTF8 = false) {\n let buff = await this.getBuffer();\n if (typeof buff === "string") {\n return { bomFound: false, text: buff };\n }\n if (!buff) {\n return { bomFound: false, text: "" };\n }\n // Check for BOMs -- since we\'re removing BOM, set \'bomFound\'\n // to re-encode as UTF-8 without BOM\n // UTF-8\n if (buff[0] === 0xef && buff[1] === 0xbb && buff[2] === 0xbf) {\n return { bomFound: true, text: decoder.decode(buff.slice(3)) };\n // UTF-16BE -- convert to buffer, swap, and decode LE\n }\n else if (buff[0] === 0xfe && buff[1] === 0xff) {\n return {\n bomFound: true,\n text: buffer__WEBPACK_IMPORTED_MODULE_1__.Buffer.from(buff.slice(2)).swap16().toString("utf16le"),\n };\n // UTF-16LE -- convert to buffer, decode LE\n }\n else if (buff[0] === 0xff && buff[1] === 0xfe) {\n return {\n bomFound: true,\n text: buffer__WEBPACK_IMPORTED_MODULE_1__.Buffer.from(buff.slice(2)).toString("utf16le"),\n };\n }\n // if no BOM, go by \'isUTF8\' param\n return {\n bomFound: false,\n text: isUTF8 ? decoder.decode(buff) : (0,_utils__WEBPACK_IMPORTED_MODULE_0__.decodeLatin1)(buff),\n };\n }\n setText(text, encodeUTF8 = false) {\n this.setBuffer(encodeUTF8 ? encoder.encode(text) : (0,_utils__WEBPACK_IMPORTED_MODULE_0__.encodeLatin1)(text));\n }\n async getBuffer() {\n if (this.buffer || !this.reader) {\n return this.buffer;\n }\n this.buffer = await this.reader.readFully();\n return this.buffer;\n }\n setBuffer(buffer) {\n this.buffer = buffer;\n this.reader = null;\n }\n setReader(reader) {\n if (reader instanceof warcio__WEBPACK_IMPORTED_MODULE_2__.BaseAsyncIterReader) {\n this.reader = reader;\n this.buffer = null;\n }\n else if (reader.getReader) {\n this.reader = new warcio__WEBPACK_IMPORTED_MODULE_2__.AsyncIterReader(reader.getReader());\n this.buffer = null;\n }\n }\n expectedLength() {\n if (this.buffer) {\n return this.buffer.length;\n }\n //TODO\n // else if (this.reader && this.reader.reader) {\n // return this.reader.reader.length;\n // }\n return 0;\n }\n createIter() {\n const buffer = this.buffer;\n const reader = this.reader;\n async function* iter() {\n if (buffer) {\n for (let i = 0; i < buffer.length; i += _utils__WEBPACK_IMPORTED_MODULE_0__.MAX_STREAM_CHUNK_SIZE) {\n yield buffer.slice(i, i + _utils__WEBPACK_IMPORTED_MODULE_0__.MAX_STREAM_CHUNK_SIZE);\n }\n }\n else if (reader) {\n yield* reader;\n }\n }\n return iter();\n }\n async *[Symbol.asyncIterator]() {\n yield* this.createIter();\n }\n setRange(range) {\n if (this.status === 206) {\n const currRange = this.headers.get("Content-Range");\n if (currRange && !currRange.startsWith("bytes 0-")) {\n return false;\n }\n }\n const bytes = range.match(/^bytes=(\\d+)-(\\d+)?$/);\n let length = 0;\n if (this.buffer) {\n length = this.buffer.length;\n }\n else if (this.reader) {\n //length = this.reader.length;\n length = Number(this.headers.get("content-length"));\n // if length is not known, keep as 200\n if (!length) {\n return false;\n }\n }\n if (!bytes) {\n this.status = 416;\n this.statusText = "Range Not Satisfiable";\n this.headers.set("Content-Range", `*/${length}`);\n return false;\n }\n const start = Number(bytes[1]);\n const end = Number(bytes[2]) || length - 1;\n if (this.buffer) {\n this.buffer = this.buffer.slice(start, end + 1);\n }\n else if (this.reader) {\n if (!(this.reader instanceof warcio__WEBPACK_IMPORTED_MODULE_2__.LimitReader) || !this.reader.setLimitSkip) {\n return false;\n }\n if (start !== 0 || end !== length - 1) {\n this.reader.setLimitSkip(end - start + 1, start);\n }\n //TODO\n // } else if (this.reader.setRangeAll) {\n // this.reader.setRangeAll(length);\n // }\n }\n this.headers.set("Content-Range", `bytes ${start}-${end}/${length}`);\n this.headers.set("Content-Length", String(end - start + 1));\n this.status = 206;\n this.statusText = "Partial Content";\n return true;\n }\n makeResponse(coHeaders = false, overwriteDisposition = false) {\n let body = null;\n if (!(0,_utils__WEBPACK_IMPORTED_MODULE_0__.isNullBodyStatus)(this.status)) {\n body =\n this.buffer || !this.reader\n ? this.buffer\n : this.reader.getReadableStream();\n }\n const response = new Response(body, {\n status: this.status,\n statusText: this.statusText,\n headers: this.headers,\n });\n // slightly hacky\n response.date = this.date;\n if (coHeaders) {\n response.headers.set("Cross-Origin-Opener-Policy", "same-origin");\n response.headers.set("Cross-Origin-Embedder-Policy", "require-corp");\n }\n if (overwriteDisposition) {\n response.headers.set("content-disposition", "inline");\n }\n return response;\n }\n}\n\n\n\n//# sourceURL=webpack://@webrecorder/wabac/./src/response.ts?')},"./src/rewrite/decoder.ts": /*!********************************!*\ !*** ./src/rewrite/decoder.ts ***! \********************************/(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "decodeContent": () => (/* binding */ decodeContent),\n/* harmony export */ "decodeResponse": () => (/* binding */ decodeResponse)\n/* harmony export */ });\n/* harmony import */ var brotli_decompress_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! brotli/decompress.js */ "./node_modules/brotli/decompress.js");\n/* harmony import */ var brotli_decompress_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(brotli_decompress_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var pako__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! pako */ "./node_modules/pako/index.js");\n/* harmony import */ var pako__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(pako__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var warcio__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! warcio */ "./node_modules/warcio/dist/index.js");\n\n\n\n// ===========================================================================\nasync function decodeResponse(response, contentEncoding, transferEncoding, noRW) {\n // use the streaming decoder if gzip only and no rewriting\n if (response.reader &&\n noRW &&\n ((contentEncoding === "gzip" && !transferEncoding) ||\n (!contentEncoding && transferEncoding === "gzip"))) {\n response.setReader(new warcio__WEBPACK_IMPORTED_MODULE_2__.AsyncIterReader(response.reader));\n return response;\n }\n const buffer = (await response.getBuffer()) || [];\n const origContent = new Uint8Array(buffer);\n const content = await decodeContent(origContent, contentEncoding, transferEncoding);\n if (origContent !== content) {\n response.setBuffer(content);\n }\n return response;\n}\n// ===========================================================================\nasync function decodeContent(content, contentEncoding, transferEncoding) {\n const origContent = content;\n try {\n if (transferEncoding === "chunked") {\n content = dechunkArrayBuffer(content);\n }\n }\n catch (e) {\n console.log("Chunk-Encoding Ignored: " + e);\n }\n try {\n if (contentEncoding === "br") {\n content = brotli_decompress_js__WEBPACK_IMPORTED_MODULE_0___default()(content);\n // if ended up with zero-length, probably not valid, just use original\n if (content.length === 0) {\n content = origContent;\n }\n }\n else if (contentEncoding === "gzip" || transferEncoding === "gzip") {\n const inflator = new (pako__WEBPACK_IMPORTED_MODULE_1___default().Inflate)();\n inflator.push(content, true);\n // if error occurs (eg. not gzip), use original arraybuffer\n if (inflator.result && !inflator.err) {\n content = inflator.result;\n }\n }\n }\n catch (e) {\n console.log("Content-Encoding Ignored: " + e);\n }\n return content;\n}\n// ===========================================================================\nfunction dechunkArrayBuffer(data) {\n let readOffset = 0;\n let writeOffset = 0;\n const decoder = new TextDecoder("utf-8");\n while (readOffset < data.length) {\n let i = readOffset;\n // check hex digits, 0-9, A-Z, a-z\n while ((data[i] >= 48 && data[i] <= 57) ||\n (data[i] >= 65 && data[i] <= 70) ||\n (data[i] >= 97 && data[i] <= 102)) {\n i++;\n }\n // doesn\'t start with number, return original\n if (i === 0) {\n return data;\n }\n // ensure \\r\\n\\r\\n\n if (data[i] != 13 || data[i + 1] != 10) {\n return data;\n }\n i += 2;\n var chunkLength = parseInt(decoder.decode(data.subarray(readOffset, i)), 16);\n if (chunkLength == 0) {\n break;\n }\n data.set(data.subarray(i, i + chunkLength), writeOffset);\n i += chunkLength;\n writeOffset += chunkLength;\n if (data[i] == 13 && data[i + 1] == 10) {\n i += 2;\n }\n readOffset = i;\n }\n return data.subarray(0, writeOffset);\n}\n\n\n\n//# sourceURL=webpack://@webrecorder/wabac/./src/rewrite/decoder.ts?')},"./src/rewrite/dsruleset.ts": diff --git a/dist/rewriting.js b/dist/rewriting.js index 053dbc94..9607fd5d 100644 --- a/dist/rewriting.js +++ b/dist/rewriting.js @@ -205,7 +205,7 @@ \************************/(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "ArchiveRequest": () => (/* binding */ ArchiveRequest)\n/* harmony export */ });\n/* harmony import */ var warcio__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! warcio */ "./node_modules/warcio/dist/index.js");\n\nconst REPLAY_REGEX = /^(?::([\\w-]+)\\/)?(\\d*)([a-z]+_|[$][a-z0-9:.-]+)?(?:\\/|\\||%7C|%7c)(.+)/;\nclass ArchiveRequest {\n url = "";\n timestamp = "";\n mod = "";\n pageId = "";\n hash = "";\n cookie = "";\n request;\n method;\n mode;\n _postToGetConverted = false;\n constructor(wbUrlStr, request, { isRoot = false, mod = "", ts = "", proxyOrigin = null, localOrigin = null, } = {}) {\n const wbUrl = REPLAY_REGEX.exec(wbUrlStr);\n this.timestamp = ts;\n this.mod = mod;\n this.request = request;\n this.method = request.method;\n this.mode = request.mode;\n if (!wbUrl &&\n (wbUrlStr.startsWith("https:") ||\n wbUrlStr.startsWith("http:") ||\n wbUrlStr.startsWith("blob:"))) {\n this.url = wbUrlStr;\n }\n else if (!wbUrl && isRoot) {\n this.url = "https://" + wbUrlStr;\n }\n else if (!wbUrl) {\n this.url = "";\n return;\n }\n else {\n this.pageId = wbUrl[1] || "";\n this.timestamp = wbUrl[2];\n this.mod = wbUrl[3];\n this.url = wbUrl[4];\n }\n if (proxyOrigin && localOrigin) {\n const url = new URL(this.url);\n if (url.origin === localOrigin) {\n this.url = proxyOrigin + url.pathname + (url.search ? url.search : "");\n }\n }\n const hashIndex = this.url.indexOf("#");\n if (hashIndex > 0) {\n this.hash = this.url.slice(hashIndex);\n this.url = this.url.substring(0, hashIndex);\n }\n }\n get headers() {\n return this.request.headers;\n }\n get destination() {\n return this.request.destination;\n }\n get referrer() {\n return this.request.referrer;\n }\n async convertPostToGet() {\n if (this._postToGetConverted) {\n return this.url;\n }\n const request = this.request;\n if (request.method !== "POST" && request.method !== "PUT") {\n return this.url;\n }\n const data = {\n method: request.method,\n postData: await request.text(),\n headers: request.headers,\n url: this.url,\n };\n if ((0,warcio__WEBPACK_IMPORTED_MODULE_0__.postToGetUrl)(data)) {\n this.url = data.url;\n this.method = "GET";\n this.mode =\n this.request.mode === "navigate" ? "same-origin" : this.request.mode;\n this._postToGetConverted = true;\n }\n return this.url;\n }\n prepareProxyRequest(prefix, isLive = true) {\n let headers;\n let referrer;\n let credentials;\n if (isLive) {\n headers = new Headers(this.request.headers);\n referrer = this.request.referrer;\n const inx = referrer.indexOf("/http", prefix.length - 1);\n if (inx > 0) {\n referrer = referrer.slice(inx + 1);\n headers.set("X-Proxy-Referer", referrer);\n }\n credentials = this.request.credentials;\n if (this.cookie) {\n headers.set("X-Proxy-Cookie", this.cookie);\n }\n }\n else {\n headers = new Headers();\n credentials = "omit";\n }\n let url = this.url;\n if (url.startsWith("//") && referrer) {\n try {\n url = new URL(referrer).protocol + url;\n }\n catch (e) {\n url = "https:" + url;\n }\n }\n return { referrer, headers, credentials, url };\n }\n async getBody() {\n const request = this.request.clone();\n return new Uint8Array(await request.arrayBuffer());\n }\n}\n\n\n//# sourceURL=webpack://@webrecorder/wabac/./src/request.ts?')},"./src/response.ts": /*!*************************!*\ !*** ./src/response.ts ***! - \*************************/(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "ArchiveResponse": () => (/* binding */ ArchiveResponse)\n/* harmony export */ });\n/* harmony import */ var warcio__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! warcio */ "./node_modules/warcio/dist/index.js");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utils */ "./src/utils.ts");\n/* harmony import */ var buffer__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! buffer */ "./node_modules/buffer/index.js");\n\n\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n// ===========================================================================\nclass ArchiveResponse {\n static fromResponse({ url, response, date, noRW, isLive, archivePrefix, }) {\n const payload = response.body\n ? new warcio__WEBPACK_IMPORTED_MODULE_2__.AsyncIterReader(response.body.getReader(), null, false)\n : null;\n const status = Number(response.headers.get("x-redirect-status") || response.status);\n const statusText = response.headers.get("x-redirect-statusText") || response.statusText;\n let headers = new Headers(response.headers);\n let origLoc = headers.get("x-orig-location");\n if (origLoc) {\n if (origLoc.startsWith(self.location.origin)) {\n origLoc = origLoc.slice(self.location.origin.length);\n }\n if (archivePrefix && origLoc.startsWith(archivePrefix)) {\n const inx = origLoc.indexOf("/http");\n if (inx > 0) {\n origLoc = origLoc.slice(inx + 1);\n }\n }\n headers.set("location", origLoc);\n headers.delete("x-orig-location");\n headers.delete("x-redirect-status");\n headers.delete("x-redirect-statusText");\n }\n let updateTS = null;\n const origTs = headers.get("x-orig-ts");\n if (origTs) {\n date = (0,_utils__WEBPACK_IMPORTED_MODULE_0__.tsToDate)(origTs);\n headers.delete("x-orig-ts");\n // force TS update downstream\n if (origTs && origLoc) {\n updateTS = origTs;\n }\n }\n const mementoDt = headers.get("memento-datetime");\n if (mementoDt) {\n date = new Date(mementoDt);\n }\n const cookie = headers.get("x-proxy-set-cookie");\n if (cookie) {\n const cookies = [];\n cookie.split(",").forEach((c) => {\n const cval = c.split(";", 1)[0].trim();\n if (cval.indexOf("=") > 0) {\n cookies.push(cval);\n }\n });\n headers.delete("x-proxy-set-cookie");\n if (cookies.length) {\n headers.set("x-wabac-preset-cookie", cookies.join(";"));\n //console.log("cookies", cookies.join(";"));\n }\n }\n return new ArchiveResponse({\n payload,\n status,\n statusText,\n headers,\n url,\n date,\n noRW,\n isLive,\n updateTS,\n });\n }\n reader;\n buffer;\n status;\n statusText;\n url;\n date;\n extraOpts;\n headers;\n noRW;\n isLive;\n updateTS;\n clonedResponse = null;\n constructor({ payload, status, statusText, headers, url, date, extraOpts = null, noRW = false, isLive = false, updateTS = null, }) {\n this.reader = null;\n this.buffer = null;\n if (payload && payload instanceof warcio__WEBPACK_IMPORTED_MODULE_2__.BaseAsyncIterReader) {\n this.reader = payload;\n }\n else {\n this.buffer = payload;\n }\n this.status = status;\n this.statusText = statusText;\n this.headers = headers;\n this.url = url;\n this.date = date;\n this.extraOpts = extraOpts;\n this.noRW = noRW;\n this.isLive = isLive;\n this.updateTS = updateTS;\n }\n async getText(isUTF8 = false) {\n let buff = await this.getBuffer();\n if (typeof buff === "string") {\n return { bomFound: false, text: buff };\n }\n if (!buff) {\n return { bomFound: false, text: "" };\n }\n // Check for BOMs -- since we\'re removing BOM, set \'bomFound\'\n // to re-encode as UTF-8 without BOM\n // UTF-8\n if (buff[0] === 0xef && buff[1] === 0xbb && buff[2] === 0xbf) {\n return { bomFound: true, text: decoder.decode(buff.slice(3)) };\n // UTF-16BE -- convert to buffer, swap, and decode LE\n }\n else if (buff[0] === 0xfe && buff[1] === 0xff) {\n return {\n bomFound: true,\n text: buffer__WEBPACK_IMPORTED_MODULE_1__.Buffer.from(buff.slice(2)).swap16().toString("utf16le"),\n };\n // UTF-16LE -- convert to buffer, decode LE\n }\n else if (buff[0] === 0xff && buff[1] === 0xfe) {\n return {\n bomFound: true,\n text: buffer__WEBPACK_IMPORTED_MODULE_1__.Buffer.from(buff.slice(2)).toString("utf16le"),\n };\n }\n // if no BOM, go by \'isUTF8\' param\n return {\n bomFound: false,\n text: isUTF8 ? decoder.decode(buff) : (0,_utils__WEBPACK_IMPORTED_MODULE_0__.decodeLatin1)(buff),\n };\n }\n setText(text, encodeUTF8 = false) {\n this.setBuffer(encodeUTF8 ? encoder.encode(text) : (0,_utils__WEBPACK_IMPORTED_MODULE_0__.encodeLatin1)(text));\n }\n async getBuffer() {\n if (this.buffer || !this.reader) {\n return this.buffer;\n }\n this.buffer = await this.reader.readFully();\n return this.buffer;\n }\n setBuffer(buffer) {\n this.buffer = buffer;\n this.reader = null;\n }\n setReader(reader) {\n if (reader instanceof warcio__WEBPACK_IMPORTED_MODULE_2__.BaseAsyncIterReader) {\n this.reader = reader;\n this.buffer = null;\n }\n else if (reader.getReader) {\n this.reader = new warcio__WEBPACK_IMPORTED_MODULE_2__.AsyncIterReader(reader.getReader());\n this.buffer = null;\n }\n }\n expectedLength() {\n if (this.buffer) {\n return this.buffer.length;\n }\n //TODO\n // else if (this.reader && this.reader.reader) {\n // return this.reader.reader.length;\n // }\n return 0;\n }\n createIter() {\n const buffer = this.buffer;\n const reader = this.reader;\n async function* iter() {\n if (buffer) {\n for (let i = 0; i < buffer.length; i += _utils__WEBPACK_IMPORTED_MODULE_0__.MAX_STREAM_CHUNK_SIZE) {\n yield buffer.slice(i, i + _utils__WEBPACK_IMPORTED_MODULE_0__.MAX_STREAM_CHUNK_SIZE);\n }\n }\n else if (reader) {\n yield* reader;\n }\n }\n return iter();\n }\n async *[Symbol.asyncIterator]() {\n yield* this.createIter();\n }\n setRange(range) {\n if (this.status === 206) {\n const currRange = this.headers.get("Content-Range");\n if (currRange && !currRange.startsWith("bytes 0-")) {\n return false;\n }\n }\n const bytes = range.match(/^bytes=(\\d+)-(\\d+)?$/);\n let length = 0;\n if (this.buffer) {\n length = this.buffer.length;\n }\n else if (this.reader) {\n //length = this.reader.length;\n length = Number(this.headers.get("content-length"));\n // if length is not known, keep as 200\n if (!length) {\n return false;\n }\n }\n if (!bytes) {\n this.status = 416;\n this.statusText = "Range Not Satisfiable";\n this.headers.set("Content-Range", `*/${length}`);\n return false;\n }\n const start = Number(bytes[1]);\n const end = Number(bytes[2]) || length - 1;\n if (this.buffer) {\n this.buffer = this.buffer.slice(start, end + 1);\n }\n else if (this.reader) {\n if (!(this.reader instanceof warcio__WEBPACK_IMPORTED_MODULE_2__.LimitReader) || !this.reader.setLimitSkip) {\n return false;\n }\n if (start !== 0 || end !== length - 1) {\n this.reader.setLimitSkip(end - start + 1, start);\n }\n //TODO\n // } else if (this.reader.setRangeAll) {\n // this.reader.setRangeAll(length);\n // }\n }\n this.headers.set("Content-Range", `bytes ${start}-${end}/${length}`);\n this.headers.set("Content-Length", String(end - start + 1));\n this.status = 206;\n this.statusText = "Partial Content";\n return true;\n }\n makeResponse(coHeaders = false, overwriteDisposition = false) {\n let body = null;\n if (!(0,_utils__WEBPACK_IMPORTED_MODULE_0__.isNullBodyStatus)(this.status)) {\n body =\n this.buffer || !this.reader\n ? this.buffer\n : this.reader.getReadableStream();\n }\n const response = new Response(body, {\n status: this.status,\n statusText: this.statusText,\n headers: this.headers,\n });\n // slightly hacky\n response.date = this.date;\n if (coHeaders) {\n response.headers.set("Cross-Origin-Opener-Policy", "same-origin");\n response.headers.set("Cross-Origin-Embedder-Policy", "require-corp");\n }\n if (overwriteDisposition) {\n response.headers.set("content-disposition", "inline");\n }\n return response;\n }\n}\n\n\n\n//# sourceURL=webpack://@webrecorder/wabac/./src/response.ts?')},"./src/rewrite/decoder.ts": + \*************************/(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "ArchiveResponse": () => (/* binding */ ArchiveResponse)\n/* harmony export */ });\n/* harmony import */ var warcio__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! warcio */ "./node_modules/warcio/dist/index.js");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utils */ "./src/utils.ts");\n/* harmony import */ var buffer__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! buffer */ "./node_modules/buffer/index.js");\n\n\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n// ===========================================================================\nclass ArchiveResponse {\n static fromResponse({ url, response, date, noRW, isLive, archivePrefix, }) {\n const payload = response.body\n ? new warcio__WEBPACK_IMPORTED_MODULE_2__.AsyncIterReader(response.body.getReader(), null, false)\n : null;\n const status = Number(response.headers.get("x-redirect-status") || response.status);\n const statusText = response.headers.get("x-redirect-statusText") || response.statusText;\n let headers = new Headers(response.headers);\n let origLoc = headers.get("x-orig-location");\n if (origLoc) {\n if (origLoc.startsWith(self.location.origin)) {\n origLoc = origLoc.slice(self.location.origin.length);\n }\n if (archivePrefix && origLoc.startsWith(archivePrefix)) {\n const inx = origLoc.indexOf("/http");\n if (inx > 0) {\n origLoc = origLoc.slice(inx + 1);\n }\n }\n headers.set("location", origLoc);\n headers.delete("x-orig-location");\n headers.delete("x-redirect-status");\n headers.delete("x-redirect-statusText");\n }\n let updateTS = null;\n const origTs = headers.get("x-orig-ts");\n if (origTs) {\n date = (0,_utils__WEBPACK_IMPORTED_MODULE_0__.tsToDate)(origTs);\n headers.delete("x-orig-ts");\n // force TS update downstream\n if (origTs && origLoc) {\n updateTS = origTs;\n }\n }\n const mementoDt = headers.get("memento-datetime");\n if (mementoDt) {\n date = new Date(mementoDt);\n }\n const cookie = headers.get("x-proxy-set-cookie");\n if (cookie) {\n const cookies = [];\n cookie.split(",").forEach((c) => {\n const cval = c.split(";", 1)[0].trim();\n if (cval.indexOf("=") > 0) {\n cookies.push(cval);\n }\n });\n headers.delete("x-proxy-set-cookie");\n if (cookies.length) {\n headers.set("x-wabac-preset-cookie", cookies.join(";"));\n //console.log("cookies", cookies.join(";"));\n }\n }\n return new ArchiveResponse({\n payload,\n status,\n statusText,\n headers,\n url,\n date,\n noRW,\n isLive,\n updateTS,\n });\n }\n reader;\n buffer;\n status;\n statusText;\n url;\n date;\n extraOpts;\n headers;\n noRW;\n isLive;\n updateTS;\n clonedResponse = null;\n constructor({ payload, status, statusText, headers, url, date, extraOpts = null, noRW = false, isLive = false, updateTS = null, }) {\n this.reader = null;\n this.buffer = null;\n if (payload && payload instanceof warcio__WEBPACK_IMPORTED_MODULE_2__.BaseAsyncIterReader) {\n this.reader = payload;\n }\n else {\n this.buffer = payload;\n }\n this.status = status;\n this.statusText = statusText || (0,_utils__WEBPACK_IMPORTED_MODULE_0__.getStatusText)(status);\n this.headers = headers;\n this.url = url;\n this.date = date;\n this.extraOpts = extraOpts;\n this.noRW = noRW;\n this.isLive = isLive;\n this.updateTS = updateTS;\n }\n async getText(isUTF8 = false) {\n let buff = await this.getBuffer();\n if (typeof buff === "string") {\n return { bomFound: false, text: buff };\n }\n if (!buff) {\n return { bomFound: false, text: "" };\n }\n // Check for BOMs -- since we\'re removing BOM, set \'bomFound\'\n // to re-encode as UTF-8 without BOM\n // UTF-8\n if (buff[0] === 0xef && buff[1] === 0xbb && buff[2] === 0xbf) {\n return { bomFound: true, text: decoder.decode(buff.slice(3)) };\n // UTF-16BE -- convert to buffer, swap, and decode LE\n }\n else if (buff[0] === 0xfe && buff[1] === 0xff) {\n return {\n bomFound: true,\n text: buffer__WEBPACK_IMPORTED_MODULE_1__.Buffer.from(buff.slice(2)).swap16().toString("utf16le"),\n };\n // UTF-16LE -- convert to buffer, decode LE\n }\n else if (buff[0] === 0xff && buff[1] === 0xfe) {\n return {\n bomFound: true,\n text: buffer__WEBPACK_IMPORTED_MODULE_1__.Buffer.from(buff.slice(2)).toString("utf16le"),\n };\n }\n // if no BOM, go by \'isUTF8\' param\n return {\n bomFound: false,\n text: isUTF8 ? decoder.decode(buff) : (0,_utils__WEBPACK_IMPORTED_MODULE_0__.decodeLatin1)(buff),\n };\n }\n setText(text, encodeUTF8 = false) {\n this.setBuffer(encodeUTF8 ? encoder.encode(text) : (0,_utils__WEBPACK_IMPORTED_MODULE_0__.encodeLatin1)(text));\n }\n async getBuffer() {\n if (this.buffer || !this.reader) {\n return this.buffer;\n }\n this.buffer = await this.reader.readFully();\n return this.buffer;\n }\n setBuffer(buffer) {\n this.buffer = buffer;\n this.reader = null;\n }\n setReader(reader) {\n if (reader instanceof warcio__WEBPACK_IMPORTED_MODULE_2__.BaseAsyncIterReader) {\n this.reader = reader;\n this.buffer = null;\n }\n else if (reader.getReader) {\n this.reader = new warcio__WEBPACK_IMPORTED_MODULE_2__.AsyncIterReader(reader.getReader());\n this.buffer = null;\n }\n }\n expectedLength() {\n if (this.buffer) {\n return this.buffer.length;\n }\n //TODO\n // else if (this.reader && this.reader.reader) {\n // return this.reader.reader.length;\n // }\n return 0;\n }\n createIter() {\n const buffer = this.buffer;\n const reader = this.reader;\n async function* iter() {\n if (buffer) {\n for (let i = 0; i < buffer.length; i += _utils__WEBPACK_IMPORTED_MODULE_0__.MAX_STREAM_CHUNK_SIZE) {\n yield buffer.slice(i, i + _utils__WEBPACK_IMPORTED_MODULE_0__.MAX_STREAM_CHUNK_SIZE);\n }\n }\n else if (reader) {\n yield* reader;\n }\n }\n return iter();\n }\n async *[Symbol.asyncIterator]() {\n yield* this.createIter();\n }\n setRange(range) {\n if (this.status === 206) {\n const currRange = this.headers.get("Content-Range");\n if (currRange && !currRange.startsWith("bytes 0-")) {\n return false;\n }\n }\n const bytes = range.match(/^bytes=(\\d+)-(\\d+)?$/);\n let length = 0;\n if (this.buffer) {\n length = this.buffer.length;\n }\n else if (this.reader) {\n //length = this.reader.length;\n length = Number(this.headers.get("content-length"));\n // if length is not known, keep as 200\n if (!length) {\n return false;\n }\n }\n if (!bytes) {\n this.status = 416;\n this.statusText = "Range Not Satisfiable";\n this.headers.set("Content-Range", `*/${length}`);\n return false;\n }\n const start = Number(bytes[1]);\n const end = Number(bytes[2]) || length - 1;\n if (this.buffer) {\n this.buffer = this.buffer.slice(start, end + 1);\n }\n else if (this.reader) {\n if (!(this.reader instanceof warcio__WEBPACK_IMPORTED_MODULE_2__.LimitReader) || !this.reader.setLimitSkip) {\n return false;\n }\n if (start !== 0 || end !== length - 1) {\n this.reader.setLimitSkip(end - start + 1, start);\n }\n //TODO\n // } else if (this.reader.setRangeAll) {\n // this.reader.setRangeAll(length);\n // }\n }\n this.headers.set("Content-Range", `bytes ${start}-${end}/${length}`);\n this.headers.set("Content-Length", String(end - start + 1));\n this.status = 206;\n this.statusText = "Partial Content";\n return true;\n }\n makeResponse(coHeaders = false, overwriteDisposition = false) {\n let body = null;\n if (!(0,_utils__WEBPACK_IMPORTED_MODULE_0__.isNullBodyStatus)(this.status)) {\n body =\n this.buffer || !this.reader\n ? this.buffer\n : this.reader.getReadableStream();\n }\n const response = new Response(body, {\n status: this.status,\n statusText: this.statusText,\n headers: this.headers,\n });\n // slightly hacky\n response.date = this.date;\n if (coHeaders) {\n response.headers.set("Cross-Origin-Opener-Policy", "same-origin");\n response.headers.set("Cross-Origin-Embedder-Policy", "require-corp");\n }\n if (overwriteDisposition) {\n response.headers.set("content-disposition", "inline");\n }\n return response;\n }\n}\n\n\n\n//# sourceURL=webpack://@webrecorder/wabac/./src/response.ts?')},"./src/rewrite/decoder.ts": /*!********************************!*\ !*** ./src/rewrite/decoder.ts ***! \********************************/(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "decodeContent": () => (/* binding */ decodeContent),\n/* harmony export */ "decodeResponse": () => (/* binding */ decodeResponse)\n/* harmony export */ });\n/* harmony import */ var brotli_decompress_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! brotli/decompress.js */ "./node_modules/brotli/decompress.js");\n/* harmony import */ var brotli_decompress_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(brotli_decompress_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var pako__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! pako */ "./node_modules/pako/index.js");\n/* harmony import */ var pako__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(pako__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var warcio__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! warcio */ "./node_modules/warcio/dist/index.js");\n\n\n\n// ===========================================================================\nasync function decodeResponse(response, contentEncoding, transferEncoding, noRW) {\n // use the streaming decoder if gzip only and no rewriting\n if (response.reader &&\n noRW &&\n ((contentEncoding === "gzip" && !transferEncoding) ||\n (!contentEncoding && transferEncoding === "gzip"))) {\n response.setReader(new warcio__WEBPACK_IMPORTED_MODULE_2__.AsyncIterReader(response.reader));\n return response;\n }\n const buffer = (await response.getBuffer()) || [];\n const origContent = new Uint8Array(buffer);\n const content = await decodeContent(origContent, contentEncoding, transferEncoding);\n if (origContent !== content) {\n response.setBuffer(content);\n }\n return response;\n}\n// ===========================================================================\nasync function decodeContent(content, contentEncoding, transferEncoding) {\n const origContent = content;\n try {\n if (transferEncoding === "chunked") {\n content = dechunkArrayBuffer(content);\n }\n }\n catch (e) {\n console.log("Chunk-Encoding Ignored: " + e);\n }\n try {\n if (contentEncoding === "br") {\n content = brotli_decompress_js__WEBPACK_IMPORTED_MODULE_0___default()(content);\n // if ended up with zero-length, probably not valid, just use original\n if (content.length === 0) {\n content = origContent;\n }\n }\n else if (contentEncoding === "gzip" || transferEncoding === "gzip") {\n const inflator = new (pako__WEBPACK_IMPORTED_MODULE_1___default().Inflate)();\n inflator.push(content, true);\n // if error occurs (eg. not gzip), use original arraybuffer\n if (inflator.result && !inflator.err) {\n content = inflator.result;\n }\n }\n }\n catch (e) {\n console.log("Content-Encoding Ignored: " + e);\n }\n return content;\n}\n// ===========================================================================\nfunction dechunkArrayBuffer(data) {\n let readOffset = 0;\n let writeOffset = 0;\n const decoder = new TextDecoder("utf-8");\n while (readOffset < data.length) {\n let i = readOffset;\n // check hex digits, 0-9, A-Z, a-z\n while ((data[i] >= 48 && data[i] <= 57) ||\n (data[i] >= 65 && data[i] <= 70) ||\n (data[i] >= 97 && data[i] <= 102)) {\n i++;\n }\n // doesn\'t start with number, return original\n if (i === 0) {\n return data;\n }\n // ensure \\r\\n\\r\\n\n if (data[i] != 13 || data[i + 1] != 10) {\n return data;\n }\n i += 2;\n var chunkLength = parseInt(decoder.decode(data.subarray(readOffset, i)), 16);\n if (chunkLength == 0) {\n break;\n }\n data.set(data.subarray(i, i + chunkLength), writeOffset);\n i += chunkLength;\n writeOffset += chunkLength;\n if (data[i] == 13 && data[i + 1] == 10) {\n i += 2;\n }\n readOffset = i;\n }\n return data.subarray(0, writeOffset);\n}\n\n\n\n//# sourceURL=webpack://@webrecorder/wabac/./src/rewrite/decoder.ts?')},"./src/rewrite/dsruleset.ts": diff --git a/dist/sw.js b/dist/sw.js index beb2b084..f7ffab80 100644 --- a/dist/sw.js +++ b/dist/sw.js @@ -715,7 +715,7 @@ \************************/(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "ArchiveRequest": () => (/* binding */ ArchiveRequest)\n/* harmony export */ });\n/* harmony import */ var warcio__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! warcio */ "./node_modules/warcio/dist/index.js");\n\nconst REPLAY_REGEX = /^(?::([\\w-]+)\\/)?(\\d*)([a-z]+_|[$][a-z0-9:.-]+)?(?:\\/|\\||%7C|%7c)(.+)/;\nclass ArchiveRequest {\n url = "";\n timestamp = "";\n mod = "";\n pageId = "";\n hash = "";\n cookie = "";\n request;\n method;\n mode;\n _postToGetConverted = false;\n constructor(wbUrlStr, request, { isRoot = false, mod = "", ts = "", proxyOrigin = null, localOrigin = null, } = {}) {\n const wbUrl = REPLAY_REGEX.exec(wbUrlStr);\n this.timestamp = ts;\n this.mod = mod;\n this.request = request;\n this.method = request.method;\n this.mode = request.mode;\n if (!wbUrl &&\n (wbUrlStr.startsWith("https:") ||\n wbUrlStr.startsWith("http:") ||\n wbUrlStr.startsWith("blob:"))) {\n this.url = wbUrlStr;\n }\n else if (!wbUrl && isRoot) {\n this.url = "https://" + wbUrlStr;\n }\n else if (!wbUrl) {\n this.url = "";\n return;\n }\n else {\n this.pageId = wbUrl[1] || "";\n this.timestamp = wbUrl[2];\n this.mod = wbUrl[3];\n this.url = wbUrl[4];\n }\n if (proxyOrigin && localOrigin) {\n const url = new URL(this.url);\n if (url.origin === localOrigin) {\n this.url = proxyOrigin + url.pathname + (url.search ? url.search : "");\n }\n }\n const hashIndex = this.url.indexOf("#");\n if (hashIndex > 0) {\n this.hash = this.url.slice(hashIndex);\n this.url = this.url.substring(0, hashIndex);\n }\n }\n get headers() {\n return this.request.headers;\n }\n get destination() {\n return this.request.destination;\n }\n get referrer() {\n return this.request.referrer;\n }\n async convertPostToGet() {\n if (this._postToGetConverted) {\n return this.url;\n }\n const request = this.request;\n if (request.method !== "POST" && request.method !== "PUT") {\n return this.url;\n }\n const data = {\n method: request.method,\n postData: await request.text(),\n headers: request.headers,\n url: this.url,\n };\n if ((0,warcio__WEBPACK_IMPORTED_MODULE_0__.postToGetUrl)(data)) {\n this.url = data.url;\n this.method = "GET";\n this.mode =\n this.request.mode === "navigate" ? "same-origin" : this.request.mode;\n this._postToGetConverted = true;\n }\n return this.url;\n }\n prepareProxyRequest(prefix, isLive = true) {\n let headers;\n let referrer;\n let credentials;\n if (isLive) {\n headers = new Headers(this.request.headers);\n referrer = this.request.referrer;\n const inx = referrer.indexOf("/http", prefix.length - 1);\n if (inx > 0) {\n referrer = referrer.slice(inx + 1);\n headers.set("X-Proxy-Referer", referrer);\n }\n credentials = this.request.credentials;\n if (this.cookie) {\n headers.set("X-Proxy-Cookie", this.cookie);\n }\n }\n else {\n headers = new Headers();\n credentials = "omit";\n }\n let url = this.url;\n if (url.startsWith("//") && referrer) {\n try {\n url = new URL(referrer).protocol + url;\n }\n catch (e) {\n url = "https:" + url;\n }\n }\n return { referrer, headers, credentials, url };\n }\n async getBody() {\n const request = this.request.clone();\n return new Uint8Array(await request.arrayBuffer());\n }\n}\n\n\n//# sourceURL=webpack://@webrecorder/wabac/./src/request.ts?')},"./src/response.ts": /*!*************************!*\ !*** ./src/response.ts ***! - \*************************/(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "ArchiveResponse": () => (/* binding */ ArchiveResponse)\n/* harmony export */ });\n/* harmony import */ var warcio__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! warcio */ "./node_modules/warcio/dist/index.js");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utils */ "./src/utils.ts");\n/* harmony import */ var buffer__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! buffer */ "./node_modules/buffer/index.js");\n\n\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n// ===========================================================================\nclass ArchiveResponse {\n static fromResponse({ url, response, date, noRW, isLive, archivePrefix, }) {\n const payload = response.body\n ? new warcio__WEBPACK_IMPORTED_MODULE_2__.AsyncIterReader(response.body.getReader(), null, false)\n : null;\n const status = Number(response.headers.get("x-redirect-status") || response.status);\n const statusText = response.headers.get("x-redirect-statusText") || response.statusText;\n let headers = new Headers(response.headers);\n let origLoc = headers.get("x-orig-location");\n if (origLoc) {\n if (origLoc.startsWith(self.location.origin)) {\n origLoc = origLoc.slice(self.location.origin.length);\n }\n if (archivePrefix && origLoc.startsWith(archivePrefix)) {\n const inx = origLoc.indexOf("/http");\n if (inx > 0) {\n origLoc = origLoc.slice(inx + 1);\n }\n }\n headers.set("location", origLoc);\n headers.delete("x-orig-location");\n headers.delete("x-redirect-status");\n headers.delete("x-redirect-statusText");\n }\n let updateTS = null;\n const origTs = headers.get("x-orig-ts");\n if (origTs) {\n date = (0,_utils__WEBPACK_IMPORTED_MODULE_0__.tsToDate)(origTs);\n headers.delete("x-orig-ts");\n // force TS update downstream\n if (origTs && origLoc) {\n updateTS = origTs;\n }\n }\n const mementoDt = headers.get("memento-datetime");\n if (mementoDt) {\n date = new Date(mementoDt);\n }\n const cookie = headers.get("x-proxy-set-cookie");\n if (cookie) {\n const cookies = [];\n cookie.split(",").forEach((c) => {\n const cval = c.split(";", 1)[0].trim();\n if (cval.indexOf("=") > 0) {\n cookies.push(cval);\n }\n });\n headers.delete("x-proxy-set-cookie");\n if (cookies.length) {\n headers.set("x-wabac-preset-cookie", cookies.join(";"));\n //console.log("cookies", cookies.join(";"));\n }\n }\n return new ArchiveResponse({\n payload,\n status,\n statusText,\n headers,\n url,\n date,\n noRW,\n isLive,\n updateTS,\n });\n }\n reader;\n buffer;\n status;\n statusText;\n url;\n date;\n extraOpts;\n headers;\n noRW;\n isLive;\n updateTS;\n clonedResponse = null;\n constructor({ payload, status, statusText, headers, url, date, extraOpts = null, noRW = false, isLive = false, updateTS = null, }) {\n this.reader = null;\n this.buffer = null;\n if (payload && payload instanceof warcio__WEBPACK_IMPORTED_MODULE_2__.BaseAsyncIterReader) {\n this.reader = payload;\n }\n else {\n this.buffer = payload;\n }\n this.status = status;\n this.statusText = statusText;\n this.headers = headers;\n this.url = url;\n this.date = date;\n this.extraOpts = extraOpts;\n this.noRW = noRW;\n this.isLive = isLive;\n this.updateTS = updateTS;\n }\n async getText(isUTF8 = false) {\n let buff = await this.getBuffer();\n if (typeof buff === "string") {\n return { bomFound: false, text: buff };\n }\n if (!buff) {\n return { bomFound: false, text: "" };\n }\n // Check for BOMs -- since we\'re removing BOM, set \'bomFound\'\n // to re-encode as UTF-8 without BOM\n // UTF-8\n if (buff[0] === 0xef && buff[1] === 0xbb && buff[2] === 0xbf) {\n return { bomFound: true, text: decoder.decode(buff.slice(3)) };\n // UTF-16BE -- convert to buffer, swap, and decode LE\n }\n else if (buff[0] === 0xfe && buff[1] === 0xff) {\n return {\n bomFound: true,\n text: buffer__WEBPACK_IMPORTED_MODULE_1__.Buffer.from(buff.slice(2)).swap16().toString("utf16le"),\n };\n // UTF-16LE -- convert to buffer, decode LE\n }\n else if (buff[0] === 0xff && buff[1] === 0xfe) {\n return {\n bomFound: true,\n text: buffer__WEBPACK_IMPORTED_MODULE_1__.Buffer.from(buff.slice(2)).toString("utf16le"),\n };\n }\n // if no BOM, go by \'isUTF8\' param\n return {\n bomFound: false,\n text: isUTF8 ? decoder.decode(buff) : (0,_utils__WEBPACK_IMPORTED_MODULE_0__.decodeLatin1)(buff),\n };\n }\n setText(text, encodeUTF8 = false) {\n this.setBuffer(encodeUTF8 ? encoder.encode(text) : (0,_utils__WEBPACK_IMPORTED_MODULE_0__.encodeLatin1)(text));\n }\n async getBuffer() {\n if (this.buffer || !this.reader) {\n return this.buffer;\n }\n this.buffer = await this.reader.readFully();\n return this.buffer;\n }\n setBuffer(buffer) {\n this.buffer = buffer;\n this.reader = null;\n }\n setReader(reader) {\n if (reader instanceof warcio__WEBPACK_IMPORTED_MODULE_2__.BaseAsyncIterReader) {\n this.reader = reader;\n this.buffer = null;\n }\n else if (reader.getReader) {\n this.reader = new warcio__WEBPACK_IMPORTED_MODULE_2__.AsyncIterReader(reader.getReader());\n this.buffer = null;\n }\n }\n expectedLength() {\n if (this.buffer) {\n return this.buffer.length;\n }\n //TODO\n // else if (this.reader && this.reader.reader) {\n // return this.reader.reader.length;\n // }\n return 0;\n }\n createIter() {\n const buffer = this.buffer;\n const reader = this.reader;\n async function* iter() {\n if (buffer) {\n for (let i = 0; i < buffer.length; i += _utils__WEBPACK_IMPORTED_MODULE_0__.MAX_STREAM_CHUNK_SIZE) {\n yield buffer.slice(i, i + _utils__WEBPACK_IMPORTED_MODULE_0__.MAX_STREAM_CHUNK_SIZE);\n }\n }\n else if (reader) {\n yield* reader;\n }\n }\n return iter();\n }\n async *[Symbol.asyncIterator]() {\n yield* this.createIter();\n }\n setRange(range) {\n if (this.status === 206) {\n const currRange = this.headers.get("Content-Range");\n if (currRange && !currRange.startsWith("bytes 0-")) {\n return false;\n }\n }\n const bytes = range.match(/^bytes=(\\d+)-(\\d+)?$/);\n let length = 0;\n if (this.buffer) {\n length = this.buffer.length;\n }\n else if (this.reader) {\n //length = this.reader.length;\n length = Number(this.headers.get("content-length"));\n // if length is not known, keep as 200\n if (!length) {\n return false;\n }\n }\n if (!bytes) {\n this.status = 416;\n this.statusText = "Range Not Satisfiable";\n this.headers.set("Content-Range", `*/${length}`);\n return false;\n }\n const start = Number(bytes[1]);\n const end = Number(bytes[2]) || length - 1;\n if (this.buffer) {\n this.buffer = this.buffer.slice(start, end + 1);\n }\n else if (this.reader) {\n if (!(this.reader instanceof warcio__WEBPACK_IMPORTED_MODULE_2__.LimitReader) || !this.reader.setLimitSkip) {\n return false;\n }\n if (start !== 0 || end !== length - 1) {\n this.reader.setLimitSkip(end - start + 1, start);\n }\n //TODO\n // } else if (this.reader.setRangeAll) {\n // this.reader.setRangeAll(length);\n // }\n }\n this.headers.set("Content-Range", `bytes ${start}-${end}/${length}`);\n this.headers.set("Content-Length", String(end - start + 1));\n this.status = 206;\n this.statusText = "Partial Content";\n return true;\n }\n makeResponse(coHeaders = false, overwriteDisposition = false) {\n let body = null;\n if (!(0,_utils__WEBPACK_IMPORTED_MODULE_0__.isNullBodyStatus)(this.status)) {\n body =\n this.buffer || !this.reader\n ? this.buffer\n : this.reader.getReadableStream();\n }\n const response = new Response(body, {\n status: this.status,\n statusText: this.statusText,\n headers: this.headers,\n });\n // slightly hacky\n response.date = this.date;\n if (coHeaders) {\n response.headers.set("Cross-Origin-Opener-Policy", "same-origin");\n response.headers.set("Cross-Origin-Embedder-Policy", "require-corp");\n }\n if (overwriteDisposition) {\n response.headers.set("content-disposition", "inline");\n }\n return response;\n }\n}\n\n\n\n//# sourceURL=webpack://@webrecorder/wabac/./src/response.ts?')},"./src/rewrite/decoder.ts": + \*************************/(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "ArchiveResponse": () => (/* binding */ ArchiveResponse)\n/* harmony export */ });\n/* harmony import */ var warcio__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! warcio */ "./node_modules/warcio/dist/index.js");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utils */ "./src/utils.ts");\n/* harmony import */ var buffer__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! buffer */ "./node_modules/buffer/index.js");\n\n\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n// ===========================================================================\nclass ArchiveResponse {\n static fromResponse({ url, response, date, noRW, isLive, archivePrefix, }) {\n const payload = response.body\n ? new warcio__WEBPACK_IMPORTED_MODULE_2__.AsyncIterReader(response.body.getReader(), null, false)\n : null;\n const status = Number(response.headers.get("x-redirect-status") || response.status);\n const statusText = response.headers.get("x-redirect-statusText") || response.statusText;\n let headers = new Headers(response.headers);\n let origLoc = headers.get("x-orig-location");\n if (origLoc) {\n if (origLoc.startsWith(self.location.origin)) {\n origLoc = origLoc.slice(self.location.origin.length);\n }\n if (archivePrefix && origLoc.startsWith(archivePrefix)) {\n const inx = origLoc.indexOf("/http");\n if (inx > 0) {\n origLoc = origLoc.slice(inx + 1);\n }\n }\n headers.set("location", origLoc);\n headers.delete("x-orig-location");\n headers.delete("x-redirect-status");\n headers.delete("x-redirect-statusText");\n }\n let updateTS = null;\n const origTs = headers.get("x-orig-ts");\n if (origTs) {\n date = (0,_utils__WEBPACK_IMPORTED_MODULE_0__.tsToDate)(origTs);\n headers.delete("x-orig-ts");\n // force TS update downstream\n if (origTs && origLoc) {\n updateTS = origTs;\n }\n }\n const mementoDt = headers.get("memento-datetime");\n if (mementoDt) {\n date = new Date(mementoDt);\n }\n const cookie = headers.get("x-proxy-set-cookie");\n if (cookie) {\n const cookies = [];\n cookie.split(",").forEach((c) => {\n const cval = c.split(";", 1)[0].trim();\n if (cval.indexOf("=") > 0) {\n cookies.push(cval);\n }\n });\n headers.delete("x-proxy-set-cookie");\n if (cookies.length) {\n headers.set("x-wabac-preset-cookie", cookies.join(";"));\n //console.log("cookies", cookies.join(";"));\n }\n }\n return new ArchiveResponse({\n payload,\n status,\n statusText,\n headers,\n url,\n date,\n noRW,\n isLive,\n updateTS,\n });\n }\n reader;\n buffer;\n status;\n statusText;\n url;\n date;\n extraOpts;\n headers;\n noRW;\n isLive;\n updateTS;\n clonedResponse = null;\n constructor({ payload, status, statusText, headers, url, date, extraOpts = null, noRW = false, isLive = false, updateTS = null, }) {\n this.reader = null;\n this.buffer = null;\n if (payload && payload instanceof warcio__WEBPACK_IMPORTED_MODULE_2__.BaseAsyncIterReader) {\n this.reader = payload;\n }\n else {\n this.buffer = payload;\n }\n this.status = status;\n this.statusText = statusText || (0,_utils__WEBPACK_IMPORTED_MODULE_0__.getStatusText)(status);\n this.headers = headers;\n this.url = url;\n this.date = date;\n this.extraOpts = extraOpts;\n this.noRW = noRW;\n this.isLive = isLive;\n this.updateTS = updateTS;\n }\n async getText(isUTF8 = false) {\n let buff = await this.getBuffer();\n if (typeof buff === "string") {\n return { bomFound: false, text: buff };\n }\n if (!buff) {\n return { bomFound: false, text: "" };\n }\n // Check for BOMs -- since we\'re removing BOM, set \'bomFound\'\n // to re-encode as UTF-8 without BOM\n // UTF-8\n if (buff[0] === 0xef && buff[1] === 0xbb && buff[2] === 0xbf) {\n return { bomFound: true, text: decoder.decode(buff.slice(3)) };\n // UTF-16BE -- convert to buffer, swap, and decode LE\n }\n else if (buff[0] === 0xfe && buff[1] === 0xff) {\n return {\n bomFound: true,\n text: buffer__WEBPACK_IMPORTED_MODULE_1__.Buffer.from(buff.slice(2)).swap16().toString("utf16le"),\n };\n // UTF-16LE -- convert to buffer, decode LE\n }\n else if (buff[0] === 0xff && buff[1] === 0xfe) {\n return {\n bomFound: true,\n text: buffer__WEBPACK_IMPORTED_MODULE_1__.Buffer.from(buff.slice(2)).toString("utf16le"),\n };\n }\n // if no BOM, go by \'isUTF8\' param\n return {\n bomFound: false,\n text: isUTF8 ? decoder.decode(buff) : (0,_utils__WEBPACK_IMPORTED_MODULE_0__.decodeLatin1)(buff),\n };\n }\n setText(text, encodeUTF8 = false) {\n this.setBuffer(encodeUTF8 ? encoder.encode(text) : (0,_utils__WEBPACK_IMPORTED_MODULE_0__.encodeLatin1)(text));\n }\n async getBuffer() {\n if (this.buffer || !this.reader) {\n return this.buffer;\n }\n this.buffer = await this.reader.readFully();\n return this.buffer;\n }\n setBuffer(buffer) {\n this.buffer = buffer;\n this.reader = null;\n }\n setReader(reader) {\n if (reader instanceof warcio__WEBPACK_IMPORTED_MODULE_2__.BaseAsyncIterReader) {\n this.reader = reader;\n this.buffer = null;\n }\n else if (reader.getReader) {\n this.reader = new warcio__WEBPACK_IMPORTED_MODULE_2__.AsyncIterReader(reader.getReader());\n this.buffer = null;\n }\n }\n expectedLength() {\n if (this.buffer) {\n return this.buffer.length;\n }\n //TODO\n // else if (this.reader && this.reader.reader) {\n // return this.reader.reader.length;\n // }\n return 0;\n }\n createIter() {\n const buffer = this.buffer;\n const reader = this.reader;\n async function* iter() {\n if (buffer) {\n for (let i = 0; i < buffer.length; i += _utils__WEBPACK_IMPORTED_MODULE_0__.MAX_STREAM_CHUNK_SIZE) {\n yield buffer.slice(i, i + _utils__WEBPACK_IMPORTED_MODULE_0__.MAX_STREAM_CHUNK_SIZE);\n }\n }\n else if (reader) {\n yield* reader;\n }\n }\n return iter();\n }\n async *[Symbol.asyncIterator]() {\n yield* this.createIter();\n }\n setRange(range) {\n if (this.status === 206) {\n const currRange = this.headers.get("Content-Range");\n if (currRange && !currRange.startsWith("bytes 0-")) {\n return false;\n }\n }\n const bytes = range.match(/^bytes=(\\d+)-(\\d+)?$/);\n let length = 0;\n if (this.buffer) {\n length = this.buffer.length;\n }\n else if (this.reader) {\n //length = this.reader.length;\n length = Number(this.headers.get("content-length"));\n // if length is not known, keep as 200\n if (!length) {\n return false;\n }\n }\n if (!bytes) {\n this.status = 416;\n this.statusText = "Range Not Satisfiable";\n this.headers.set("Content-Range", `*/${length}`);\n return false;\n }\n const start = Number(bytes[1]);\n const end = Number(bytes[2]) || length - 1;\n if (this.buffer) {\n this.buffer = this.buffer.slice(start, end + 1);\n }\n else if (this.reader) {\n if (!(this.reader instanceof warcio__WEBPACK_IMPORTED_MODULE_2__.LimitReader) || !this.reader.setLimitSkip) {\n return false;\n }\n if (start !== 0 || end !== length - 1) {\n this.reader.setLimitSkip(end - start + 1, start);\n }\n //TODO\n // } else if (this.reader.setRangeAll) {\n // this.reader.setRangeAll(length);\n // }\n }\n this.headers.set("Content-Range", `bytes ${start}-${end}/${length}`);\n this.headers.set("Content-Length", String(end - start + 1));\n this.status = 206;\n this.statusText = "Partial Content";\n return true;\n }\n makeResponse(coHeaders = false, overwriteDisposition = false) {\n let body = null;\n if (!(0,_utils__WEBPACK_IMPORTED_MODULE_0__.isNullBodyStatus)(this.status)) {\n body =\n this.buffer || !this.reader\n ? this.buffer\n : this.reader.getReadableStream();\n }\n const response = new Response(body, {\n status: this.status,\n statusText: this.statusText,\n headers: this.headers,\n });\n // slightly hacky\n response.date = this.date;\n if (coHeaders) {\n response.headers.set("Cross-Origin-Opener-Policy", "same-origin");\n response.headers.set("Cross-Origin-Embedder-Policy", "require-corp");\n }\n if (overwriteDisposition) {\n response.headers.set("content-disposition", "inline");\n }\n return response;\n }\n}\n\n\n\n//# sourceURL=webpack://@webrecorder/wabac/./src/response.ts?')},"./src/rewrite/decoder.ts": /*!********************************!*\ !*** ./src/rewrite/decoder.ts ***! \********************************/(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "decodeContent": () => (/* binding */ decodeContent),\n/* harmony export */ "decodeResponse": () => (/* binding */ decodeResponse)\n/* harmony export */ });\n/* harmony import */ var brotli_decompress_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! brotli/decompress.js */ "./node_modules/brotli/decompress.js");\n/* harmony import */ var brotli_decompress_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(brotli_decompress_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var pako__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! pako */ "./node_modules/pako/index.js");\n/* harmony import */ var pako__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(pako__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var warcio__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! warcio */ "./node_modules/warcio/dist/index.js");\n\n\n\n// ===========================================================================\nasync function decodeResponse(response, contentEncoding, transferEncoding, noRW) {\n // use the streaming decoder if gzip only and no rewriting\n if (response.reader &&\n noRW &&\n ((contentEncoding === "gzip" && !transferEncoding) ||\n (!contentEncoding && transferEncoding === "gzip"))) {\n response.setReader(new warcio__WEBPACK_IMPORTED_MODULE_2__.AsyncIterReader(response.reader));\n return response;\n }\n const buffer = (await response.getBuffer()) || [];\n const origContent = new Uint8Array(buffer);\n const content = await decodeContent(origContent, contentEncoding, transferEncoding);\n if (origContent !== content) {\n response.setBuffer(content);\n }\n return response;\n}\n// ===========================================================================\nasync function decodeContent(content, contentEncoding, transferEncoding) {\n const origContent = content;\n try {\n if (transferEncoding === "chunked") {\n content = dechunkArrayBuffer(content);\n }\n }\n catch (e) {\n console.log("Chunk-Encoding Ignored: " + e);\n }\n try {\n if (contentEncoding === "br") {\n content = brotli_decompress_js__WEBPACK_IMPORTED_MODULE_0___default()(content);\n // if ended up with zero-length, probably not valid, just use original\n if (content.length === 0) {\n content = origContent;\n }\n }\n else if (contentEncoding === "gzip" || transferEncoding === "gzip") {\n const inflator = new (pako__WEBPACK_IMPORTED_MODULE_1___default().Inflate)();\n inflator.push(content, true);\n // if error occurs (eg. not gzip), use original arraybuffer\n if (inflator.result && !inflator.err) {\n content = inflator.result;\n }\n }\n }\n catch (e) {\n console.log("Content-Encoding Ignored: " + e);\n }\n return content;\n}\n// ===========================================================================\nfunction dechunkArrayBuffer(data) {\n let readOffset = 0;\n let writeOffset = 0;\n const decoder = new TextDecoder("utf-8");\n while (readOffset < data.length) {\n let i = readOffset;\n // check hex digits, 0-9, A-Z, a-z\n while ((data[i] >= 48 && data[i] <= 57) ||\n (data[i] >= 65 && data[i] <= 70) ||\n (data[i] >= 97 && data[i] <= 102)) {\n i++;\n }\n // doesn\'t start with number, return original\n if (i === 0) {\n return data;\n }\n // ensure \\r\\n\\r\\n\n if (data[i] != 13 || data[i + 1] != 10) {\n return data;\n }\n i += 2;\n var chunkLength = parseInt(decoder.decode(data.subarray(readOffset, i)), 16);\n if (chunkLength == 0) {\n break;\n }\n data.set(data.subarray(i, i + chunkLength), writeOffset);\n i += chunkLength;\n writeOffset += chunkLength;\n if (data[i] == 13 && data[i + 1] == 10) {\n i += 2;\n }\n readOffset = i;\n }\n return data.subarray(0, writeOffset);\n}\n\n\n\n//# sourceURL=webpack://@webrecorder/wabac/./src/rewrite/decoder.ts?')},"./src/rewrite/dsruleset.ts": diff --git a/dist/types/response.d.ts b/dist/types/response.d.ts index afd75a41..07aef291 100644 --- a/dist/types/response.d.ts +++ b/dist/types/response.d.ts @@ -2,7 +2,7 @@ import { AsyncIterReader } from "warcio"; type ArchiveResponseOpts = { payload: AsyncIterReader | Uint8Array | null; status: number; - statusText: string; + statusText?: string; headers: Headers; url: string; date: Date; diff --git a/dist/types/response.d.ts.map b/dist/types/response.d.ts.map index 4419f9dd..32b4c003 100644 --- a/dist/types/response.d.ts.map +++ b/dist/types/response.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"response.d.ts","sourceRoot":"","sources":["../../src/response.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,eAAe,EAAe,MAAM,QAAQ,CAAC;AAa3E,KAAK,mBAAmB,GAAG;IACzB,OAAO,EAAE,eAAe,GAAG,UAAU,GAAG,IAAI,CAAC;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,IAAI,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;IACvC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,CAAC;AAGF,cAAM,eAAe;IACnB,MAAM,CAAC,YAAY,CAAC,EAClB,GAAG,EACH,QAAQ,EACR,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,aAAa,GACd,EAAE;QACD,GAAG,EAAE,MAAM,CAAC;QACZ,QAAQ,EAAE,QAAQ,CAAC;QACnB,IAAI,EAAE,IAAI,CAAC;QACX,IAAI,CAAC,EAAE,OAAO,CAAC;QACf,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB;IA4ED,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;IAC/B,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;IAE1B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,IAAI,CAAC;IACX,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAExB,cAAc,EAAE,QAAQ,GAAG,IAAI,CAAQ;gBAE3B,EACV,OAAO,EACP,MAAM,EACN,UAAU,EACV,OAAO,EACP,GAAG,EACH,IAAI,EACJ,SAAgB,EAChB,IAAY,EACZ,MAAc,EACd,QAAe,GAChB,EAAE,mBAAmB;IAqBhB,OAAO,CAAC,MAAM,UAAQ,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAmC3E,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,UAAQ;IAIlC,SAAS;IASf,SAAS,CAAC,MAAM,EAAE,UAAU;IAK5B,SAAS,CAAC,MAAM,EAAE,eAAe,GAAG,cAAc;IAUlD,cAAc;IAWd,UAAU;IAiBH,CAAC,MAAM,CAAC,aAAa,CAAC;IAI7B,QAAQ,CAAC,KAAK,EAAE,MAAM;IA0DtB,YAAY,CAAC,SAAS,UAAQ,EAAE,oBAAoB,UAAQ;CAyB7D;AAED,OAAO,EAAE,eAAe,EAAE,CAAC"} \ No newline at end of file +{"version":3,"file":"response.d.ts","sourceRoot":"","sources":["../../src/response.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,eAAe,EAAe,MAAM,QAAQ,CAAC;AAc3E,KAAK,mBAAmB,GAAG;IACzB,OAAO,EAAE,eAAe,GAAG,UAAU,GAAG,IAAI,CAAC;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,IAAI,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;IACvC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,CAAC;AAGF,cAAM,eAAe;IACnB,MAAM,CAAC,YAAY,CAAC,EAClB,GAAG,EACH,QAAQ,EACR,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,aAAa,GACd,EAAE;QACD,GAAG,EAAE,MAAM,CAAC;QACZ,QAAQ,EAAE,QAAQ,CAAC;QACnB,IAAI,EAAE,IAAI,CAAC;QACX,IAAI,CAAC,EAAE,OAAO,CAAC;QACf,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB;IA4ED,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;IAC/B,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;IAE1B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,IAAI,CAAC;IACX,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAExB,cAAc,EAAE,QAAQ,GAAG,IAAI,CAAQ;gBAE3B,EACV,OAAO,EACP,MAAM,EACN,UAAU,EACV,OAAO,EACP,GAAG,EACH,IAAI,EACJ,SAAgB,EAChB,IAAY,EACZ,MAAc,EACd,QAAe,GAChB,EAAE,mBAAmB;IAqBhB,OAAO,CAAC,MAAM,UAAQ,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAmC3E,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,UAAQ;IAIlC,SAAS;IASf,SAAS,CAAC,MAAM,EAAE,UAAU;IAK5B,SAAS,CAAC,MAAM,EAAE,eAAe,GAAG,cAAc;IAUlD,cAAc;IAWd,UAAU;IAiBH,CAAC,MAAM,CAAC,aAAa,CAAC;IAI7B,QAAQ,CAAC,KAAK,EAAE,MAAM;IA0DtB,YAAY,CAAC,SAAS,UAAQ,EAAE,oBAAoB,UAAQ;CAyB7D;AAED,OAAO,EAAE,eAAe,EAAE,CAAC"} \ No newline at end of file diff --git a/package.json b/package.json index 267fb8ce..cb7d4085 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,6 @@ { "name": "@webrecorder/wabac", "version": "2.20.0-beta.0", - "main": "index.js", "type": "module", "exports": { ".": { diff --git a/src/response.ts b/src/response.ts index 9bf58eaa..7fe9ba2b 100644 --- a/src/response.ts +++ b/src/response.ts @@ -5,6 +5,7 @@ import { encodeLatin1, MAX_STREAM_CHUNK_SIZE, tsToDate, + getStatusText, } from "./utils"; import { Buffer } from "buffer"; @@ -14,7 +15,7 @@ const decoder = new TextDecoder(); type ArchiveResponseOpts = { payload: AsyncIterReader | Uint8Array | null; status: number; - statusText: string; + statusText?: string; headers: Headers; url: string; date: Date; @@ -153,7 +154,7 @@ class ArchiveResponse { } this.status = status; - this.statusText = statusText; + this.statusText = statusText || getStatusText(status); this.headers = headers; this.url = url; this.date = date;