tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

partial_content.sjs (6183B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4  * License, v. 2.0. If a copy of the MPL was not distributed with this
      5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 /* Debug and Error wrapper functions for dump().
      8  */
      9 function ERR(response, responseCode, responseCodeStr, msg) {
     10   // Reset state var.
     11   setState("expectedRequestType", "");
     12   // Dump to console log and send to client in response.
     13   dump("SERVER ERROR: " + msg + "\n");
     14   response.write("HTTP/1.1 " + responseCode + " " + responseCodeStr + "\r\n");
     15   response.write("Content-Type: text/html; charset=UTF-8\r\n");
     16   response.write("Content-Length: " + msg.length + "\r\n");
     17   response.write("\r\n");
     18   response.write(msg);
     19 }
     20 
     21 function DBG(msg) {
     22   // Dump to console only.
     23   dump("SERVER DEBUG: " + msg + "\n");
     24 }
     25 
     26 /* Delivers content in parts to test partially cached content: requires two
     27  * requests for the same resource.
     28  *
     29  * First call will respond with partial content, but a 200 header and
     30  * Content-Length equal to the full content length. No Range or If-Range
     31  * headers are allowed in the request.
     32  *
     33  * Second call will require Range and If-Range in the request headers, and
     34  * will respond with the range requested.
     35  */
     36 function handleRequest(request, response) {
     37   DBG("Trying to seize power");
     38   response.seizePower();
     39 
     40   DBG("About to check state vars");
     41   // Get state var to determine if this is the first or second request.
     42   var expectedRequestType;
     43   var lastModified;
     44   if (getState("expectedRequestType") === "") {
     45     DBG("First call: Should be requesting full content.");
     46     expectedRequestType = "fullRequest";
     47     // Set state var for second request.
     48     setState("expectedRequestType", "partialRequest");
     49     // Create lastModified variable for responses.
     50     lastModified = new Date().toUTCString();
     51     setState("lastModified", lastModified);
     52   } else if (getState("expectedRequestType") === "partialRequest") {
     53     DBG("Second call: Should be requesting undelivered content.");
     54     expectedRequestType = "partialRequest";
     55     // Reset state var for first request.
     56     setState("expectedRequestType", "");
     57     // Get last modified date and reset state var.
     58     lastModified = getState("lastModified");
     59   } else {
     60     ERR(
     61       response,
     62       500,
     63       "Internal Server Error",
     64       'Invalid expectedRequestType "' +
     65         expectedRequestType +
     66         '"in ' +
     67         "server state db."
     68     );
     69     return;
     70   }
     71 
     72   // Look for Range and If-Range
     73   var range = request.hasHeader("Range") ? request.getHeader("Range") : "";
     74   var ifRange = request.hasHeader("If-Range")
     75     ? request.getHeader("If-Range")
     76     : "";
     77 
     78   if (expectedRequestType === "fullRequest") {
     79     // Should not have Range or If-Range in first request.
     80     if (range && range.length) {
     81       ERR(
     82         response,
     83         400,
     84         "Bad Request",
     85         'Should not receive "Range: ' + range + '" for first, full request.'
     86       );
     87       return;
     88     }
     89     if (ifRange && ifRange.length) {
     90       ERR(
     91         response,
     92         400,
     93         "Bad Request",
     94         'Should not receive "Range: ' + range + '" for first, full request.'
     95       );
     96       return;
     97     }
     98   } else if (expectedRequestType === "partialRequest") {
     99     // Range AND If-Range should both be present in second request.
    100     if (!range) {
    101       ERR(
    102         response,
    103         400,
    104         "Bad Request",
    105         'Should receive "Range: " for second, partial request.'
    106       );
    107       return;
    108     }
    109     if (!ifRange) {
    110       ERR(
    111         response,
    112         400,
    113         "Bad Request",
    114         'Should receive "If-Range: " for second, partial request.'
    115       );
    116       return;
    117     }
    118   } else {
    119     // Somewhat redundant, but a check for errors in this test code.
    120     ERR(
    121       response,
    122       500,
    123       "Internal Server Error",
    124       'expectedRequestType not set correctly: "' + expectedRequestType + '"'
    125     );
    126     return;
    127   }
    128 
    129   // Prepare content in two parts for responses.
    130   var partialContent =
    131     '<html><head></head><body><p id="firstResponse">First response</p>';
    132   var remainderContent =
    133     '<p id="secondResponse">Second response</p></body></html>';
    134   var totalLength = partialContent.length + remainderContent.length;
    135 
    136   DBG("totalLength: " + totalLength);
    137 
    138   // Prepare common headers for the two responses.
    139   let date = new Date();
    140   DBG("Date: " + date.toUTCString() + ", Last-Modified: " + lastModified);
    141   var commonHeaders =
    142     "Date: " +
    143     date.toUTCString() +
    144     "\r\n" +
    145     "Last-Modified: " +
    146     lastModified +
    147     "\r\n" +
    148     "Content-Type: text/html; charset=UTF-8\r\n" +
    149     "ETag: abcd0123\r\n" +
    150     "Accept-Ranges: bytes\r\n";
    151 
    152   // Prepare specific headers and content for first and second responses.
    153   if (expectedRequestType === "fullRequest") {
    154     DBG("First response: Sending partial content with a full header");
    155     response.write("HTTP/1.1 200 OK\r\n");
    156     response.write(commonHeaders);
    157     // Set Content-Length to full length of resource.
    158     response.write("Content-Length: " + totalLength + "\r\n");
    159     response.write("\r\n");
    160     response.write(partialContent);
    161   } else if (expectedRequestType === "partialRequest") {
    162     DBG("Second response: Sending remaining content with a range header");
    163     response.write("HTTP/1.1 206 Partial Content\r\n");
    164     response.write(commonHeaders);
    165     // Set Content-Length to length of bytes transmitted.
    166     response.write("Content-Length: " + remainderContent.length + "\r\n");
    167     response.write(
    168       "Content-Range: bytes " +
    169         partialContent.length +
    170         "-" +
    171         (totalLength - 1) +
    172         "/" +
    173         totalLength +
    174         "\r\n"
    175     );
    176     response.write("\r\n");
    177     response.write(remainderContent);
    178   } else {
    179     // Somewhat redundant, but a check for errors in this test code.
    180     ERR(
    181       response,
    182       500,
    183       "Internal Server Error",
    184       "Something very bad happened here: expectedRequestType is invalid " +
    185         'towards the end of handleRequest! - "' +
    186         expectedRequestType +
    187         '"'
    188     );
    189     return;
    190   }
    191 
    192   response.finish();
    193 }