| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355 | 
							- /*
 
-  * Copyright 2014 Mozilla Foundation
 
-  *
 
-  * Licensed under the Apache License, Version 2.0 (the "License");
 
-  * you may not use this file except in compliance with the License.
 
-  * You may obtain a copy of the License at
 
-  *
 
-  *     http://www.apache.org/licenses/LICENSE-2.0
 
-  *
 
-  * Unless required by applicable law or agreed to in writing, software
 
-  * distributed under the License is distributed on an "AS IS" BASIS,
 
-  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
-  * See the License for the specific language governing permissions and
 
-  * limitations under the License.
 
-  */
 
- /* eslint-disable no-var */
 
- "use strict";
 
- var http = require("http");
 
- var path = require("path");
 
- var fs = require("fs");
 
- var mimeTypes = {
 
-   ".css": "text/css",
 
-   ".html": "text/html",
 
-   ".js": "application/javascript",
 
-   ".json": "application/json",
 
-   ".svg": "image/svg+xml",
 
-   ".pdf": "application/pdf",
 
-   ".xhtml": "application/xhtml+xml",
 
-   ".gif": "image/gif",
 
-   ".ico": "image/x-icon",
 
-   ".png": "image/png",
 
-   ".log": "text/plain",
 
-   ".bcmap": "application/octet-stream",
 
-   ".properties": "text/plain",
 
- };
 
- var defaultMimeType = "application/octet-stream";
 
- function WebServer() {
 
-   this.root = ".";
 
-   this.host = "localhost";
 
-   this.port = 0;
 
-   this.server = null;
 
-   this.verbose = false;
 
-   this.cacheExpirationTime = 0;
 
-   this.disableRangeRequests = false;
 
-   this.hooks = {
 
-     GET: [crossOriginHandler],
 
-     POST: [],
 
-   };
 
- }
 
- WebServer.prototype = {
 
-   start(callback) {
 
-     this._ensureNonZeroPort();
 
-     this.server = http.createServer(this._handler.bind(this));
 
-     this.server.listen(this.port, this.host, callback);
 
-     console.log(
 
-       "Server running at http://" + this.host + ":" + this.port + "/"
 
-     );
 
-   },
 
-   stop(callback) {
 
-     this.server.close(callback);
 
-     this.server = null;
 
-   },
 
-   _ensureNonZeroPort() {
 
-     if (!this.port) {
 
-       // If port is 0, a random port will be chosen instead. Do not set a host
 
-       // name to make sure that the port is synchronously set by .listen().
 
-       var server = http.createServer().listen(0);
 
-       var address = server.address();
 
-       // .address().port being available synchronously is merely an
 
-       // implementation detail. So we are defensive here and fall back to some
 
-       // fixed port when the address is not available yet.
 
-       this.port = address ? address.port : 8000;
 
-       server.close();
 
-     }
 
-   },
 
-   _handler(req, res) {
 
-     var url = req.url.replace(/\/\//g, "/");
 
-     var urlParts = /([^?]*)((?:\?(.*))?)/.exec(url);
 
-     try {
 
-       // Guard against directory traversal attacks such as
 
-       // `/../../../../../../../etc/passwd`, which let you make GET requests
 
-       // for files outside of `this.root`.
 
-       var pathPart = path.normalize(decodeURI(urlParts[1]));
 
-       // path.normalize returns a path on the basis of the current platform.
 
-       // Windows paths cause issues in statFile and serverDirectoryIndex.
 
-       // Converting to unix path would avoid platform checks in said functions.
 
-       pathPart = pathPart.replace(/\\/g, "/");
 
-     } catch (ex) {
 
-       // If the URI cannot be decoded, a `URIError` is thrown. This happens for
 
-       // malformed URIs such as `http://localhost:8888/%s%s` and should be
 
-       // handled as a bad request.
 
-       res.writeHead(400);
 
-       res.end("Bad request", "utf8");
 
-       return;
 
-     }
 
-     var queryPart = urlParts[3];
 
-     var verbose = this.verbose;
 
-     var methodHooks = this.hooks[req.method];
 
-     if (!methodHooks) {
 
-       res.writeHead(405);
 
-       res.end("Unsupported request method", "utf8");
 
-       return;
 
-     }
 
-     var handled = methodHooks.some(function (hook) {
 
-       return hook(req, res);
 
-     });
 
-     if (handled) {
 
-       return;
 
-     }
 
-     if (pathPart === "/favicon.ico") {
 
-       fs.realpath(
 
-         path.join(this.root, "test/resources/favicon.ico"),
 
-         checkFile
 
-       );
 
-       return;
 
-     }
 
-     var disableRangeRequests = this.disableRangeRequests;
 
-     var cacheExpirationTime = this.cacheExpirationTime;
 
-     var filePath;
 
-     fs.realpath(path.join(this.root, pathPart), checkFile);
 
-     function checkFile(err, file) {
 
-       if (err) {
 
-         res.writeHead(404);
 
-         res.end();
 
-         if (verbose) {
 
-           console.error(url + ": not found");
 
-         }
 
-         return;
 
-       }
 
-       filePath = file;
 
-       fs.stat(filePath, statFile);
 
-     }
 
-     var fileSize;
 
-     function statFile(err, stats) {
 
-       if (err) {
 
-         res.writeHead(500);
 
-         res.end();
 
-         return;
 
-       }
 
-       fileSize = stats.size;
 
-       var isDir = stats.isDirectory();
 
-       if (isDir && !/\/$/.test(pathPart)) {
 
-         res.setHeader("Location", pathPart + "/" + urlParts[2]);
 
-         res.writeHead(301);
 
-         res.end("Redirected", "utf8");
 
-         return;
 
-       }
 
-       if (isDir) {
 
-         serveDirectoryIndex(filePath);
 
-         return;
 
-       }
 
-       var range = req.headers.range;
 
-       if (range && !disableRangeRequests) {
 
-         var rangesMatches = /^bytes=(\d+)-(\d+)?/.exec(range);
 
-         if (!rangesMatches) {
 
-           res.writeHead(501);
 
-           res.end("Bad range", "utf8");
 
-           if (verbose) {
 
-             console.error(url + ': bad range: "' + range + '"');
 
-           }
 
-           return;
 
-         }
 
-         var start = +rangesMatches[1];
 
-         var end = +rangesMatches[2];
 
-         if (verbose) {
 
-           console.log(url + ": range " + start + " - " + end);
 
-         }
 
-         serveRequestedFileRange(
 
-           filePath,
 
-           start,
 
-           isNaN(end) ? fileSize : end + 1
 
-         );
 
-         return;
 
-       }
 
-       if (verbose) {
 
-         console.log(url);
 
-       }
 
-       serveRequestedFile(filePath);
 
-     }
 
-     function escapeHTML(untrusted) {
 
-       // Escape untrusted input so that it can safely be used in a HTML response
 
-       // in HTML and in HTML attributes.
 
-       return untrusted
 
-         .replace(/&/g, "&")
 
-         .replace(/</g, "<")
 
-         .replace(/>/g, ">")
 
-         .replace(/"/g, """)
 
-         .replace(/'/g, "'");
 
-     }
 
-     function serveDirectoryIndex(dir) {
 
-       res.setHeader("Content-Type", "text/html");
 
-       res.writeHead(200);
 
-       if (queryPart === "frame") {
 
-         res.end(
 
-           "<html><frameset cols=*,200><frame name=pdf>" +
 
-             '<frame src="' +
 
-             encodeURI(pathPart) +
 
-             '?side"></frameset></html>',
 
-           "utf8"
 
-         );
 
-         return;
 
-       }
 
-       var all = queryPart === "all";
 
-       fs.readdir(dir, function (err, files) {
 
-         if (err) {
 
-           res.end();
 
-           return;
 
-         }
 
-         res.write(
 
-           '<html><head><meta charset="utf-8"></head><body>' +
 
-             "<h1>PDFs of " +
 
-             pathPart +
 
-             "</h1>\n"
 
-         );
 
-         if (pathPart !== "/") {
 
-           res.write('<a href="..">..</a><br>\n');
 
-         }
 
-         files.forEach(function (file) {
 
-           var stat;
 
-           var item = pathPart + file;
 
-           var href = "";
 
-           var label = "";
 
-           var extraAttributes = "";
 
-           try {
 
-             stat = fs.statSync(path.join(dir, file));
 
-           } catch (e) {
 
-             href = encodeURI(item);
 
-             label = file + " (" + e + ")";
 
-             extraAttributes = ' style="color:red"';
 
-           }
 
-           if (stat) {
 
-             if (stat.isDirectory()) {
 
-               href = encodeURI(item);
 
-               label = file;
 
-             } else if (path.extname(file).toLowerCase() === ".pdf") {
 
-               href = "/web/viewer.html?file=" + encodeURIComponent(item);
 
-               label = file;
 
-               extraAttributes = ' target="pdf"';
 
-             } else if (all) {
 
-               href = encodeURI(item);
 
-               label = file;
 
-             }
 
-           }
 
-           if (label) {
 
-             res.write(
 
-               '<a href="' +
 
-                 escapeHTML(href) +
 
-                 '"' +
 
-                 extraAttributes +
 
-                 ">" +
 
-                 escapeHTML(label) +
 
-                 "</a><br>\n"
 
-             );
 
-           }
 
-         });
 
-         if (files.length === 0) {
 
-           res.write("<p>no files found</p>\n");
 
-         }
 
-         if (!all && queryPart !== "side") {
 
-           res.write(
 
-             "<hr><p>(only PDF files are shown, " +
 
-               '<a href="?all">show all</a>)</p>\n'
 
-           );
 
-         }
 
-         res.end("</body></html>");
 
-       });
 
-     }
 
-     function serveRequestedFile(reqFilePath) {
 
-       var stream = fs.createReadStream(reqFilePath, { flags: "rs" });
 
-       stream.on("error", function (error) {
 
-         res.writeHead(500);
 
-         res.end();
 
-       });
 
-       var ext = path.extname(reqFilePath).toLowerCase();
 
-       var contentType = mimeTypes[ext] || defaultMimeType;
 
-       if (!disableRangeRequests) {
 
-         res.setHeader("Accept-Ranges", "bytes");
 
-       }
 
-       res.setHeader("Content-Type", contentType);
 
-       res.setHeader("Content-Length", fileSize);
 
-       if (cacheExpirationTime > 0) {
 
-         var expireTime = new Date();
 
-         expireTime.setSeconds(expireTime.getSeconds() + cacheExpirationTime);
 
-         res.setHeader("Expires", expireTime.toUTCString());
 
-       }
 
-       res.writeHead(200);
 
-       stream.pipe(res);
 
-     }
 
-     function serveRequestedFileRange(reqFilePath, start, end) {
 
-       var stream = fs.createReadStream(reqFilePath, {
 
-         flags: "rs",
 
-         start,
 
-         end: end - 1,
 
-       });
 
-       stream.on("error", function (error) {
 
-         res.writeHead(500);
 
-         res.end();
 
-       });
 
-       var ext = path.extname(reqFilePath).toLowerCase();
 
-       var contentType = mimeTypes[ext] || defaultMimeType;
 
-       res.setHeader("Accept-Ranges", "bytes");
 
-       res.setHeader("Content-Type", contentType);
 
-       res.setHeader("Content-Length", end - start);
 
-       res.setHeader(
 
-         "Content-Range",
 
-         "bytes " + start + "-" + (end - 1) + "/" + fileSize
 
-       );
 
-       res.writeHead(206);
 
-       stream.pipe(res);
 
-     }
 
-   },
 
- };
 
- // This supports the "Cross-origin" test in test/unit/api_spec.js
 
- // It is here instead of test.js so that when the test will still complete as
 
- // expected if the user does "gulp server" and then visits
 
- // http://localhost:8888/test/unit/unit_test.html?spec=Cross-origin
 
- function crossOriginHandler(req, res) {
 
-   if (req.url === "/test/pdfs/basicapi.pdf?cors=withCredentials") {
 
-     res.setHeader("Access-Control-Allow-Origin", req.headers.origin);
 
-     res.setHeader("Access-Control-Allow-Credentials", "true");
 
-   }
 
-   if (req.url === "/test/pdfs/basicapi.pdf?cors=withoutCredentials") {
 
-     res.setHeader("Access-Control-Allow-Origin", req.headers.origin);
 
-   }
 
- }
 
- exports.WebServer = WebServer;
 
 
  |