browser/extensions/pdfjs/content/network.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/browser/extensions/pdfjs/content/network.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,237 @@
     1.4 +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
     1.6 +/* Copyright 2012 Mozilla Foundation
     1.7 + *
     1.8 + * Licensed under the Apache License, Version 2.0 (the "License");
     1.9 + * you may not use this file except in compliance with the License.
    1.10 + * You may obtain a copy of the License at
    1.11 + *
    1.12 + *     http://www.apache.org/licenses/LICENSE-2.0
    1.13 + *
    1.14 + * Unless required by applicable law or agreed to in writing, software
    1.15 + * distributed under the License is distributed on an "AS IS" BASIS,
    1.16 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    1.17 + * See the License for the specific language governing permissions and
    1.18 + * limitations under the License.
    1.19 + */
    1.20 +
    1.21 +// NOTE: Be careful what goes in this file, as it is also used from the context
    1.22 +// of the addon. So using warn/error in here will break the addon.
    1.23 +
    1.24 +'use strict';
    1.25 +
    1.26 +
    1.27 +  
    1.28 +  Components.utils.import('resource://gre/modules/Services.jsm');
    1.29 +  
    1.30 +  var EXPORTED_SYMBOLS = ['NetworkManager'];
    1.31 +  
    1.32 +  var console = {
    1.33 +    log: function console_log(aMsg) {
    1.34 +      var msg = 'network.js: ' + (aMsg.join ? aMsg.join('') : aMsg);
    1.35 +      Services.console.logStringMessage(msg);
    1.36 +      // TODO(mack): dump() doesn't seem to work here...
    1.37 +      dump(msg + '\n');
    1.38 +    }
    1.39 +  }
    1.40 +
    1.41 +var NetworkManager = (function NetworkManagerClosure() {
    1.42 +
    1.43 +  var OK_RESPONSE = 200;
    1.44 +  var PARTIAL_CONTENT_RESPONSE = 206;
    1.45 +
    1.46 +  function NetworkManager(url, args) {
    1.47 +    this.url = url;
    1.48 +    args = args || {};
    1.49 +    this.isHttp = /^https?:/i.test(url);
    1.50 +    this.httpHeaders = (this.isHttp && args.httpHeaders) || {};
    1.51 +    this.withCredentials = args.withCredentials || false;
    1.52 +    this.getXhr = args.getXhr ||
    1.53 +      function NetworkManager_getXhr() {
    1.54 +        return new XMLHttpRequest();
    1.55 +      };
    1.56 +
    1.57 +    this.currXhrId = 0;
    1.58 +    this.pendingRequests = {};
    1.59 +    this.loadedRequests = {};
    1.60 +  }
    1.61 +
    1.62 +  function getArrayBuffer(xhr) {
    1.63 +    var data = (xhr.mozResponseArrayBuffer || xhr.mozResponse ||
    1.64 +                xhr.responseArrayBuffer || xhr.response);
    1.65 +    if (typeof data !== 'string') {
    1.66 +      return data;
    1.67 +    }
    1.68 +    var length = data.length;
    1.69 +    var buffer = new Uint8Array(length);
    1.70 +    for (var i = 0; i < length; i++) {
    1.71 +      buffer[i] = data.charCodeAt(i) & 0xFF;
    1.72 +    }
    1.73 +    return buffer;
    1.74 +  }
    1.75 +
    1.76 +  NetworkManager.prototype = {
    1.77 +    requestRange: function NetworkManager_requestRange(begin, end, listeners) {
    1.78 +      var args = {
    1.79 +        begin: begin,
    1.80 +        end: end
    1.81 +      };
    1.82 +      for (var prop in listeners) {
    1.83 +        args[prop] = listeners[prop];
    1.84 +      }
    1.85 +      return this.request(args);
    1.86 +    },
    1.87 +
    1.88 +    requestFull: function NetworkManager_requestRange(listeners) {
    1.89 +      return this.request(listeners);
    1.90 +    },
    1.91 +
    1.92 +    request: function NetworkManager_requestRange(args) {
    1.93 +      var xhr = this.getXhr();
    1.94 +      var xhrId = this.currXhrId++;
    1.95 +      var pendingRequest = this.pendingRequests[xhrId] = {
    1.96 +        xhr: xhr
    1.97 +      };
    1.98 +
    1.99 +      xhr.open('GET', this.url);
   1.100 +      xhr.withCredentials = this.withCredentials;
   1.101 +      for (var property in this.httpHeaders) {
   1.102 +        var value = this.httpHeaders[property];
   1.103 +        if (typeof value === 'undefined') {
   1.104 +          continue;
   1.105 +        }
   1.106 +        xhr.setRequestHeader(property, value);
   1.107 +      }
   1.108 +      if (this.isHttp && 'begin' in args && 'end' in args) {
   1.109 +        var rangeStr = args.begin + '-' + (args.end - 1);
   1.110 +        xhr.setRequestHeader('Range', 'bytes=' + rangeStr);
   1.111 +        pendingRequest.expectedStatus = 206;
   1.112 +      } else {
   1.113 +        pendingRequest.expectedStatus = 200;
   1.114 +      }
   1.115 +
   1.116 +      xhr.mozResponseType = xhr.responseType = 'arraybuffer';
   1.117 +
   1.118 +      if (args.onProgress) {
   1.119 +        xhr.onprogress = args.onProgress;
   1.120 +      }
   1.121 +      if (args.onError) {
   1.122 +        xhr.onerror = function(evt) {
   1.123 +          args.onError(xhr.status);
   1.124 +        };
   1.125 +      }
   1.126 +      xhr.onreadystatechange = this.onStateChange.bind(this, xhrId);
   1.127 +
   1.128 +      pendingRequest.onHeadersReceived = args.onHeadersReceived;
   1.129 +      pendingRequest.onDone = args.onDone;
   1.130 +      pendingRequest.onError = args.onError;
   1.131 +
   1.132 +      xhr.send(null);
   1.133 +
   1.134 +      return xhrId;
   1.135 +    },
   1.136 +
   1.137 +    onStateChange: function NetworkManager_onStateChange(xhrId, evt) {
   1.138 +      var pendingRequest = this.pendingRequests[xhrId];
   1.139 +      if (!pendingRequest) {
   1.140 +        // Maybe abortRequest was called...
   1.141 +        return;
   1.142 +      }
   1.143 +
   1.144 +      var xhr = pendingRequest.xhr;
   1.145 +      if (xhr.readyState >= 2 && pendingRequest.onHeadersReceived) {
   1.146 +        pendingRequest.onHeadersReceived();
   1.147 +        delete pendingRequest.onHeadersReceived;
   1.148 +      }
   1.149 +
   1.150 +      if (xhr.readyState !== 4) {
   1.151 +        return;
   1.152 +      }
   1.153 +
   1.154 +      if (!(xhrId in this.pendingRequests)) {
   1.155 +        // The XHR request might have been aborted in onHeadersReceived()
   1.156 +        // callback, in which case we should abort request
   1.157 +        return;
   1.158 +      }
   1.159 +
   1.160 +      delete this.pendingRequests[xhrId];
   1.161 +
   1.162 +      // success status == 0 can be on ftp, file and other protocols
   1.163 +      if (xhr.status === 0 && this.isHttp) {
   1.164 +        if (pendingRequest.onError) {
   1.165 +          pendingRequest.onError(xhr.status);
   1.166 +        }
   1.167 +        return;
   1.168 +      }
   1.169 +      var xhrStatus = xhr.status || OK_RESPONSE;
   1.170 +
   1.171 +      // From http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.2:
   1.172 +      // "A server MAY ignore the Range header". This means it's possible to
   1.173 +      // get a 200 rather than a 206 response from a range request.
   1.174 +      var ok_response_on_range_request =
   1.175 +          xhrStatus === OK_RESPONSE &&
   1.176 +          pendingRequest.expectedStatus === PARTIAL_CONTENT_RESPONSE;
   1.177 +
   1.178 +      if (!ok_response_on_range_request &&
   1.179 +          xhrStatus !== pendingRequest.expectedStatus) {
   1.180 +        if (pendingRequest.onError) {
   1.181 +          pendingRequest.onError(xhr.status);
   1.182 +        }
   1.183 +        return;
   1.184 +      }
   1.185 +
   1.186 +      this.loadedRequests[xhrId] = true;
   1.187 +
   1.188 +      var chunk = getArrayBuffer(xhr);
   1.189 +      if (xhrStatus === PARTIAL_CONTENT_RESPONSE) {
   1.190 +        var rangeHeader = xhr.getResponseHeader('Content-Range');
   1.191 +        var matches = /bytes (\d+)-(\d+)\/(\d+)/.exec(rangeHeader);
   1.192 +        var begin = parseInt(matches[1], 10);
   1.193 +        pendingRequest.onDone({
   1.194 +          begin: begin,
   1.195 +          chunk: chunk
   1.196 +        });
   1.197 +      } else {
   1.198 +        pendingRequest.onDone({
   1.199 +          begin: 0,
   1.200 +          chunk: chunk
   1.201 +        });
   1.202 +      }
   1.203 +    },
   1.204 +
   1.205 +    hasPendingRequests: function NetworkManager_hasPendingRequests() {
   1.206 +      for (var xhrId in this.pendingRequests) {
   1.207 +        return true;
   1.208 +      }
   1.209 +      return false;
   1.210 +    },
   1.211 +
   1.212 +    getRequestXhr: function NetworkManager_getXhr(xhrId) {
   1.213 +      return this.pendingRequests[xhrId].xhr;
   1.214 +    },
   1.215 +
   1.216 +    isPendingRequest: function NetworkManager_isPendingRequest(xhrId) {
   1.217 +      return xhrId in this.pendingRequests;
   1.218 +    },
   1.219 +
   1.220 +    isLoadedRequest: function NetworkManager_isLoadedRequest(xhrId) {
   1.221 +      return xhrId in this.loadedRequests;
   1.222 +    },
   1.223 +
   1.224 +    abortAllRequests: function NetworkManager_abortAllRequests() {
   1.225 +      for (var xhrId in this.pendingRequests) {
   1.226 +        this.abortRequest(xhrId | 0);
   1.227 +      }
   1.228 +    },
   1.229 +
   1.230 +    abortRequest: function NetworkManager_abortRequest(xhrId) {
   1.231 +      var xhr = this.pendingRequests[xhrId].xhr;
   1.232 +      delete this.pendingRequests[xhrId];
   1.233 +      xhr.abort();
   1.234 +    }
   1.235 +  };
   1.236 +
   1.237 +  return NetworkManager;
   1.238 +})();
   1.239 +
   1.240 +

mercurial