aboutsummaryrefslogblamecommitdiffstats
path: root/0001-Make-cached-parameter-for-making-a-resource-explicit.patch
blob: 678e0e236c74cd10d1ab3877cf37a75cb8c6e8db (plain) (tree)




























































































































































                                                                                                  
From 5e88bb97d50c1ee32f60aa9ae062a101781de97c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mat=C4=9Bj=20Cepl?= <mcepl@redhat.com>
Date: Sun, 22 May 2011 02:46:39 +0200
Subject: [PATCH] Make cached parameter for making a resource explicitly
 cached.

Attempt to fix https://bugzilla.mozilla.org/show_bug.cgi?id=655749
(I wonder how much this cache is different from Firefox own caching).
---
 packages/addon-kit/lib/request.js |   92 +++++++++++++++++++++++++++++++++++--
 1 files changed, 87 insertions(+), 5 deletions(-)

diff --git a/packages/addon-kit/lib/request.js b/packages/addon-kit/lib/request.js
index 50da22a..f93716d 100644
--- a/packages/addon-kit/lib/request.js
+++ b/packages/addon-kit/lib/request.js
@@ -39,6 +39,8 @@ const xpcom = require("xpcom");
 const xhr = require("xhr");
 const errors = require("errors");
 const apiUtils = require("api-utils");
+const ss = require("simple-storage");
+
 
 // Ugly but will fix with: https://bugzilla.mozilla.org/show_bug.cgi?id=596248
 const EventEmitter = require('events').EventEmitter.compose({
@@ -62,6 +64,10 @@ const validator = new OptionsValidator({
   contentType: {
     map: function (v) v || "application/x-www-form-urlencoded",
     is:  ["string"]
+  },
+  cached: {
+    map: function (v) v || false,
+    is:  ["boolean"]
   }
 });
 
@@ -74,9 +80,9 @@ function Request(options) {
   // request will hold the actual XHR object
   let request;
   let response;
-
-  if ('onComplete' in options)
-    self.on('complete', options.onComplete)
+  if ('onComplete' in options) {
+    self.on('complete', options.onComplete);
+  }
   options = validator.validateOptions(options);
 
   // function to prep the request since it's the same between GET and POST
@@ -86,6 +92,17 @@ function Request(options) {
       throw new Error(REUSE_ERROR);
     }
 
+    var _recordingCache = (typeof options.recording === "undefined") ? false : options.recording;
+
+    if (options.cached && !("httpRequestCache" in ss.storage)) {
+      ss.storage.httpRequestCache = {};
+    }
+
+    if (options.cached) {
+      makeCachedRequest(mode);
+      return;
+    }
+
     request = new xhr.XMLHttpRequest();
 
     let url = options.url;
@@ -111,19 +128,84 @@ function Request(options) {
     // handle the readystate, create the response, and call the callback
     request.onreadystatechange = function () {
       if (request.readyState == 4) {
+        if (_recordingCache && request.status == 200) {
+          // index by unmodified URL we don't want to index by data
+          ss.storage.httpRequestCache[options.url] = {
+            responseText: request.responseText,
+            lastModified: new Date(request.getResponseHeader("Last-Modified")),
+            eTag: request.getResponseHeader("ETag"),
+            allResponseHeaders: request.getAllResponseHeaders()
+          };
+        }
         response = new Response(request);
         errors.catchAndLog(function () {
           self._emit('complete', response);
         })();
       }
-    }
+    };
 
     // actually send the request. we only want to send data on POST requests
     request.send(mode == "POST" ? data : null);
   }
 
+  /**
+   * return simulated request object or null, if the request is not cached
+   */
+  function makeCachedRequest(_mode) {
+    // request must provide in emitting "complete" at least these properties:
+    // request.responseText, request.status, request.statusText,
+    // and request.getAllResponseHeaders()
+    if (ss.storage.httpRequestCache && (options.url in ss.storage.httpRequestCache)) {
+      var cache = ss.storage.httpRequestCache[options.url];
+
+      // Randomize URL to avoid caching
+      // TODO see https://fedorahosted.org/bugzilla-triage-scripts/ticket/21
+      // for more thorough discussion and possible further improvement
+      options.url += (options.url.match(/\?/) == null ? "?" : "&") + (new Date()).getTime();
+
+      // check HEAD request and if (etag != cachedETag) && (last-modified > cachedLastModified)
+      // recursive call, but with options.cached set to false
+      var _headRequest = new xhr.XMLHttpRequest();
+      _headRequest.open("HEAD", options.url, true);
+      _headRequest.onreadystatechange=function() {
+        if (_headRequest.readyState==4) {
+          var _curETag = _headRequest.getResponseHeader("ETag");
+          var _curLastModified = new Date(_headRequest.getResponseHeader("Last-Modified"));
+          console.log("_curLastModified = " + _curLastModified);
+          console.log("cache.lastModified = " + cache.lastModified);
+          if ((_curETag == cache.eTag) || (_curLastModified <= cache.lastModified)) {
+            console.log("Loading from cache!");
+            // create false request with cached values
+            var fake_response = new Response({
+              responseText: cache.responseText,
+              status: 200, // could we have anything else than 200?
+              statusText: "200 OK",
+              getAllResponseHeaders: function() {
+                return cache.allResponseHeaders;
+              }
+            });
+            errors.catchAndLog(function () {
+              self._emit('complete', fake_response);
+            })();
+          } else { // cache is not up-to-date
+            console.log("Too old cache!");
+            options.cached = false;
+            options.recording = true;
+            makeRequest(_mode);
+          }
+        }
+      }
+      _headRequest.send(null);
+    } else { // We don't have this URL in cache at all
+      console.log("Not cached at all!");
+      options.cached = false;
+      options.recording = true;
+      makeRequest(_mode);
+    }
+  }
+
   // Map these setters/getters to the options
-  ["url", "headers", "content", "contentType"].forEach(function (k) {
+  ["url", "headers", "cached", "content", "contentType"].forEach(function (k) {
     _public.__defineGetter__(k, function () options[k]);
     _public.__defineSetter__(k, function (v) {
       // This will automatically rethrow errors from apiUtils.validateOptions.
-- 
1.7.6.1