1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
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
|