1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.serverAssets = void 0;
|
4 | var tslib_1 = require("tslib");
|
5 | var debug_ = require("debug");
|
6 | var express = require("express");
|
7 | var mime = require("mime-types");
|
8 | var path = require("path");
|
9 | var zipHasEntry_1 = require("r2-shared-js/dist/es5/src/_utils/zipHasEntry");
|
10 | var transformer_1 = require("r2-shared-js/dist/es5/src/transform/transformer");
|
11 | var RangeUtils_1 = require("r2-utils-js/dist/es5/src/_utils/http/RangeUtils");
|
12 | var BufferUtils_1 = require("r2-utils-js/dist/es5/src/_utils/stream/BufferUtils");
|
13 | var request_ext_1 = require("./request-ext");
|
14 | var debug = debug_("r2:streamer#http/server-assets");
|
15 | function serverAssets(server, routerPathBase64) {
|
16 | var _this = this;
|
17 | var routerAssets = express.Router({ strict: false });
|
18 | routerAssets.get("/", function (req, res) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
19 | var reqparams, isShow, isHead, pathBase64Str, publication, err_1, zipInternal, err, zip, pathInZip, err, isDivina, link, findLinkRecursive, relativePath, _i, _a, l, _b, _c, l, _d, _e, l, err, mediaType, isText, isEncrypted, isPartialByteRangeRequest, partialByteBegin, partialByteEnd, ranges, err, zipStream_, _f, err_2, doTransform, sessionInfo, fullUrl, transformedStream, err_3, err, zipData, err_4, partialByteLength, rangeHeader;
|
20 | return tslib_1.__generator(this, function (_g) {
|
21 | switch (_g.label) {
|
22 | case 0:
|
23 | reqparams = req.params;
|
24 | if (!reqparams.pathBase64) {
|
25 | reqparams.pathBase64 = req.pathBase64;
|
26 | }
|
27 | if (!reqparams.asset) {
|
28 | reqparams.asset = req.asset;
|
29 | }
|
30 | if (!reqparams.lcpPass64) {
|
31 | reqparams.lcpPass64 = req.lcpPass64;
|
32 | }
|
33 | isShow = req.query.show;
|
34 | isHead = req.method.toLowerCase() === "head";
|
35 | if (isHead) {
|
36 | debug("HEAD !!!!!!!!!!!!!!!!!!!");
|
37 | }
|
38 | pathBase64Str = Buffer.from(reqparams.pathBase64, "base64").toString("utf8");
|
39 | _g.label = 1;
|
40 | case 1:
|
41 | _g.trys.push([1, 3, , 4]);
|
42 | return [4, server.loadOrGetCachedPublication(pathBase64Str)];
|
43 | case 2:
|
44 | publication = _g.sent();
|
45 | return [3, 4];
|
46 | case 3:
|
47 | err_1 = _g.sent();
|
48 | debug(err_1);
|
49 | res.status(500).send("<html><body><p>Internal Server Error</p><p>"
|
50 | + err_1 + "</p></body></html>");
|
51 | return [2];
|
52 | case 4:
|
53 | zipInternal = publication.findFromInternal("zip");
|
54 | if (!zipInternal) {
|
55 | err = "No publication zip!";
|
56 | debug(err);
|
57 | res.status(500).send("<html><body><p>Internal Server Error</p><p>"
|
58 | + err + "</p></body></html>");
|
59 | return [2];
|
60 | }
|
61 | zip = zipInternal.Value;
|
62 | pathInZip = reqparams.asset;
|
63 | if (!zipHasEntry_1.zipHasEntry(zip, pathInZip, undefined)) {
|
64 | err = "Asset not in zip! " + pathInZip;
|
65 | debug(err);
|
66 | res.status(500).send("<html><body><p>Internal Server Error</p><p>"
|
67 | + err + "</p></body></html>");
|
68 | return [2];
|
69 | }
|
70 | isDivina = publication.Metadata && publication.Metadata.RDFType &&
|
71 | (/http[s]?:\/\/schema\.org\/ComicStory$/.test(publication.Metadata.RDFType) ||
|
72 | /http[s]?:\/\/schema\.org\/VisualNarrative$/.test(publication.Metadata.RDFType));
|
73 | findLinkRecursive = function (relativePath, l) {
|
74 | if (l.Href === relativePath) {
|
75 | return l;
|
76 | }
|
77 | var found;
|
78 | if (l.Children) {
|
79 | for (var _i = 0, _a = l.Children; _i < _a.length; _i++) {
|
80 | var child = _a[_i];
|
81 | found = findLinkRecursive(relativePath, child);
|
82 | if (found) {
|
83 | return found;
|
84 | }
|
85 | }
|
86 | }
|
87 | if (l.Alternate) {
|
88 | for (var _b = 0, _c = l.Alternate; _b < _c.length; _b++) {
|
89 | var alt = _c[_b];
|
90 | found = findLinkRecursive(relativePath, alt);
|
91 | if (found) {
|
92 | return found;
|
93 | }
|
94 | }
|
95 | }
|
96 | return undefined;
|
97 | };
|
98 | if ((publication.Resources || publication.Spine || publication.Links)
|
99 | && pathInZip.indexOf("META-INF/") !== 0
|
100 | && !pathInZip.endsWith(".opf")) {
|
101 | relativePath = pathInZip;
|
102 | if (publication.Resources) {
|
103 | for (_i = 0, _a = publication.Resources; _i < _a.length; _i++) {
|
104 | l = _a[_i];
|
105 | link = findLinkRecursive(relativePath, l);
|
106 | if (link) {
|
107 | break;
|
108 | }
|
109 | }
|
110 | }
|
111 | if (!link) {
|
112 | if (publication.Spine) {
|
113 | for (_b = 0, _c = publication.Spine; _b < _c.length; _b++) {
|
114 | l = _c[_b];
|
115 | link = findLinkRecursive(relativePath, l);
|
116 | if (link) {
|
117 | break;
|
118 | }
|
119 | }
|
120 | }
|
121 | }
|
122 | if (!link) {
|
123 | if (publication.Links) {
|
124 | for (_d = 0, _e = publication.Links; _d < _e.length; _d++) {
|
125 | l = _e[_d];
|
126 | link = findLinkRecursive(relativePath, l);
|
127 | if (link) {
|
128 | break;
|
129 | }
|
130 | }
|
131 | }
|
132 | }
|
133 | if (!link &&
|
134 | !isDivina) {
|
135 | err = "Asset not declared in publication spine/resources!" + relativePath;
|
136 | debug(err);
|
137 | res.status(500).send("<html><body><p>Internal Server Error</p><p>"
|
138 | + err + "</p></body></html>");
|
139 | return [2];
|
140 | }
|
141 | }
|
142 | if (server.isSecured() && !link &&
|
143 | (pathInZip.indexOf("META-INF/") === 0 || pathInZip.endsWith(".opf"))) {
|
144 | res.status(200).send("<html><body></body></html>");
|
145 | return [2];
|
146 | }
|
147 | mediaType = mime.lookup(pathInZip);
|
148 | if (link && link.TypeLink) {
|
149 | mediaType = link.TypeLink;
|
150 | }
|
151 | isText = (typeof mediaType === "string") && (mediaType.indexOf("text/") === 0 ||
|
152 | mediaType.indexOf("application/xhtml") === 0 ||
|
153 | mediaType.indexOf("application/xml") === 0 ||
|
154 | mediaType.indexOf("application/json") === 0 ||
|
155 | mediaType.indexOf("application/svg") === 0 ||
|
156 | mediaType.indexOf("application/smil") === 0 ||
|
157 | mediaType.indexOf("+json") > 0 ||
|
158 | mediaType.indexOf("+smil") > 0 ||
|
159 | mediaType.indexOf("+svg") > 0 ||
|
160 | mediaType.indexOf("+xhtml") > 0 ||
|
161 | mediaType.indexOf("+xml") > 0);
|
162 | isEncrypted = link && link.Properties && link.Properties.Encrypted;
|
163 | isPartialByteRangeRequest = ((req.headers && req.headers.range) ? true : false);
|
164 | partialByteBegin = 0;
|
165 | partialByteEnd = -1;
|
166 | if (isPartialByteRangeRequest) {
|
167 | debug(req.headers.range);
|
168 | ranges = RangeUtils_1.parseRangeHeader(req.headers.range);
|
169 | if (ranges && ranges.length) {
|
170 | if (ranges.length > 1) {
|
171 | err = "Too many HTTP ranges: " + req.headers.range;
|
172 | debug(err);
|
173 | res.status(416).send("<html><body><p>Internal Server Error</p><p>"
|
174 | + err + "</p></body></html>");
|
175 | return [2];
|
176 | }
|
177 | partialByteBegin = ranges[0].begin;
|
178 | partialByteEnd = ranges[0].end;
|
179 | if (partialByteBegin < 0) {
|
180 | partialByteBegin = 0;
|
181 | }
|
182 | }
|
183 | debug(pathInZip + " >> " + partialByteBegin + "-" + partialByteEnd);
|
184 | }
|
185 | _g.label = 5;
|
186 | case 5:
|
187 | _g.trys.push([5, 10, , 11]);
|
188 | if (!(isPartialByteRangeRequest && !isEncrypted)) return [3, 7];
|
189 | return [4, zip.entryStreamRangePromise(pathInZip, partialByteBegin, partialByteEnd)];
|
190 | case 6:
|
191 | _f = _g.sent();
|
192 | return [3, 9];
|
193 | case 7: return [4, zip.entryStreamPromise(pathInZip)];
|
194 | case 8:
|
195 | _f = _g.sent();
|
196 | _g.label = 9;
|
197 | case 9:
|
198 | zipStream_ = _f;
|
199 | return [3, 11];
|
200 | case 10:
|
201 | err_2 = _g.sent();
|
202 | debug(err_2);
|
203 | res.status(500).send("<html><body><p>Internal Server Error</p><p>"
|
204 | + err_2 + "</p></body></html>");
|
205 | return [2];
|
206 | case 11:
|
207 | doTransform = true;
|
208 | sessionInfo = req.query[request_ext_1.URL_PARAM_SESSION_INFO];
|
209 | if (!(doTransform && link)) return [3, 16];
|
210 | fullUrl = "" + server.serverUrl() + req.originalUrl;
|
211 | transformedStream = void 0;
|
212 | _g.label = 12;
|
213 | case 12:
|
214 | _g.trys.push([12, 14, , 15]);
|
215 | return [4, transformer_1.Transformers.tryStream(publication, link, fullUrl, zipStream_, isPartialByteRangeRequest, partialByteBegin, partialByteEnd, sessionInfo)];
|
216 | case 13:
|
217 | transformedStream = _g.sent();
|
218 | return [3, 15];
|
219 | case 14:
|
220 | err_3 = _g.sent();
|
221 | debug(err_3);
|
222 | res.status(500).send("<html><body><p>Internal Server Error</p><p>"
|
223 | + err_3 + "</p></body></html>");
|
224 | return [2];
|
225 | case 15:
|
226 | if (transformedStream) {
|
227 | if (transformedStream !== zipStream_) {
|
228 | debug("Asset transformed ok: " + link.Href);
|
229 | }
|
230 | zipStream_ = transformedStream;
|
231 | }
|
232 | else {
|
233 | err = "Transform fail (encryption scheme not supported?)";
|
234 | debug(err);
|
235 | res.status(500).send("<html><body><p>Internal Server Error</p><p>"
|
236 | + err + "</p></body></html>");
|
237 | return [2];
|
238 | }
|
239 | _g.label = 16;
|
240 | case 16:
|
241 | if (!isShow) return [3, 21];
|
242 | zipData = void 0;
|
243 | _g.label = 17;
|
244 | case 17:
|
245 | _g.trys.push([17, 19, , 20]);
|
246 | return [4, BufferUtils_1.streamToBufferPromise(zipStream_.stream)];
|
247 | case 18:
|
248 | zipData = _g.sent();
|
249 | return [3, 20];
|
250 | case 19:
|
251 | err_4 = _g.sent();
|
252 | debug(err_4);
|
253 | res.status(500).send("<html><body><p>Internal Server Error</p><p>"
|
254 | + err_4 + "</p></body></html>");
|
255 | return [2];
|
256 | case 20:
|
257 | if (zipData) {
|
258 | debug("CHECK: " + zipStream_.length + " ==> " + zipData.length);
|
259 | }
|
260 | res.status(200).send("<html><body>" +
|
261 | "<h1>" + path.basename(pathBase64Str) + "</h1>" +
|
262 | "<h2>" + mediaType + "</h2>" +
|
263 | ((isText && zipData) ?
|
264 | ("<p><pre>" +
|
265 | zipData.toString("utf8").replace(/&/g, "&")
|
266 | .replace(/</g, "<")
|
267 | .replace(/>/g, ">")
|
268 | .replace(/"/g, """)
|
269 | .replace(/'/g, "'") +
|
270 | "</pre></p>")
|
271 | : "<p>BINARY</p>") + "</body></html>");
|
272 | return [2];
|
273 | case 21:
|
274 | server.setResponseCORS(res);
|
275 | if (isPartialByteRangeRequest || isEncrypted) {
|
276 | server.setResponseCacheHeaders(res, false);
|
277 | }
|
278 | else {
|
279 | server.setResponseCacheHeaders(res, true);
|
280 | }
|
281 | if (mediaType) {
|
282 | res.set("Content-Type", mediaType);
|
283 | }
|
284 | res.setHeader("Accept-Ranges", "bytes");
|
285 | if (isPartialByteRangeRequest) {
|
286 | if (partialByteEnd < 0) {
|
287 | partialByteEnd = zipStream_.length - 1;
|
288 | }
|
289 | partialByteLength = isPartialByteRangeRequest ?
|
290 | partialByteEnd - partialByteBegin + 1 :
|
291 | zipStream_.length;
|
292 | res.setHeader("Content-Length", "" + partialByteLength);
|
293 | rangeHeader = "bytes " + partialByteBegin + "-" + partialByteEnd + "/" + zipStream_.length;
|
294 | res.setHeader("Content-Range", rangeHeader);
|
295 | res.status(206);
|
296 | }
|
297 | else {
|
298 | res.setHeader("Content-Length", "" + zipStream_.length);
|
299 | res.status(200);
|
300 | }
|
301 | if (isHead) {
|
302 | res.end();
|
303 | }
|
304 | else {
|
305 | zipStream_.stream
|
306 | .on("error", function f() {
|
307 | debug("ZIP ERROR " + pathInZip);
|
308 | })
|
309 | .pipe(res)
|
310 | .on("error", function f() {
|
311 | debug("RES ERROR " + pathInZip);
|
312 | })
|
313 | .on("close", function f() {
|
314 | res.end();
|
315 | });
|
316 | }
|
317 | return [2];
|
318 | }
|
319 | });
|
320 | }); });
|
321 | routerPathBase64.param("asset", function (req, _res, next, value, _name) {
|
322 | if (value) {
|
323 | value = value.replace(/\/\/+/g, "/");
|
324 | }
|
325 | req.asset = value;
|
326 | next();
|
327 | });
|
328 | routerPathBase64.use("/:" + request_ext_1._pathBase64 + "/:" + request_ext_1._asset + "(*)", routerAssets);
|
329 | }
|
330 | exports.serverAssets = serverAssets;
|
331 |
|
\ | No newline at end of file |