Add some docs for Resource module

This commit is contained in:
Anant Narayanan 2009-06-25 16:13:52 -07:00
Родитель d7369a90e1
Коммит b8e79586eb
1 изменённых файлов: 112 добавлений и 5 удалений

Просмотреть файл

@ -52,6 +52,10 @@ Cu.import("resource://weave/auth.js");
Function.prototype.async = Async.sugar; Function.prototype.async = Async.sugar;
// = RequestException =
//
// This function raises an exception through the call
// stack for a failed network request.
function RequestException(resource, action, request) { function RequestException(resource, action, request) {
this._resource = resource; this._resource = resource;
this._action = action; this._action = action;
@ -69,12 +73,21 @@ RequestException.prototype = {
} }
}; };
// = Resource =
//
// Represents a remote network resource, identified by a URI.
function Resource(uri) { function Resource(uri) {
this._init(uri); this._init(uri);
} }
Resource.prototype = { Resource.prototype = {
_logName: "Net.Resource", _logName: "Net.Resource",
// ** {{{ Resource.authenticator }}} **
//
// Getter and setter for the authenticator module
// responsible for this particular resource. The authenticator
// module may modify the headers to perform authentication
// while performing a request for the resource, for example.
get authenticator() { get authenticator() {
if (this._authenticator) if (this._authenticator)
return this._authenticator; return this._authenticator;
@ -85,6 +98,11 @@ Resource.prototype = {
this._authenticator = value; this._authenticator = value;
}, },
// ** {{{ Resource.headers }}} **
//
// Getter for access to received headers after the request
// for the resource has been made, setter for headers to be included
// while making a request for the resource.
get headers() { get headers() {
return this.authenticator.onRequest(this._headers); return this.authenticator.onRequest(this._headers);
}, },
@ -99,6 +117,9 @@ Resource.prototype = {
} }
}, },
// ** {{{ Resource.uri }}} **
//
// URI representing this resource.
get uri() { get uri() {
return this._uri; return this._uri;
}, },
@ -111,12 +132,18 @@ Resource.prototype = {
this._uri = value; this._uri = value;
}, },
// ** {{{ Resource.spec }}} **
//
// Get the string representation of the URI.
get spec() { get spec() {
if (this._uri) if (this._uri)
return this._uri.spec; return this._uri.spec;
return null; return null;
}, },
// ** {{{ Resource.data }}} **
//
// Get and set the data encapulated in the resource.
_data: null, _data: null,
get data() this._data, get data() this._data,
set data(value) { set data(value) {
@ -131,6 +158,11 @@ Resource.prototype = {
get downloaded() this._downloaded, get downloaded() this._downloaded,
get dirty() this._dirty, get dirty() this._dirty,
// ** {{{ Resource.filters }}} **
//
// Filters are used to perform pre and post processing on
// requests made for resources. Use these methods to add,
// remove and clear filters applied to the resource.
_filters: null, _filters: null,
pushFilter: function Res_pushFilter(filter) { pushFilter: function Res_pushFilter(filter) {
this._filters.push(filter); this._filters.push(filter);
@ -151,19 +183,28 @@ Resource.prototype = {
this._filters = []; this._filters = [];
}, },
// ** {{{ Resource._createRequest }}} **
//
// This method returns a new IO Channel for requests to be made
// through. It is never called directly, only {{{_request}}} uses it
// to obtain a request channel.
//
_createRequest: function Res__createRequest() { _createRequest: function Res__createRequest() {
this._lastChannel = Svc.IO.newChannel(this.spec, null, null). this._lastChannel = Svc.IO.newChannel(this.spec, null, null).
QueryInterface(Ci.nsIRequest); QueryInterface(Ci.nsIRequest);
// Always validate the cache: // Always validate the cache:
let loadFlags = this._lastChannel.loadFlags; let loadFlags = this._lastChannel.loadFlags;
loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE; loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
loadFlags |= Ci.nsIRequest.INHIBIT_CACHING; loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
this._lastChannel.loadFlags = loadFlags; this._lastChannel.loadFlags = loadFlags;
this._lastChannel = this._lastChannel.QueryInterface(Ci.nsIHttpChannel); this._lastChannel = this._lastChannel.QueryInterface(Ci.nsIHttpChannel);
// Setup a callback to handle bad HTTPS certificates.
this._lastChannel.notificationCallbacks = new badCertListener(); this._lastChannel.notificationCallbacks = new badCertListener();
let headers = this.headers; // avoid calling the authorizer more than once // Avoid calling the authorizer more than once
let headers = this.headers;
for (let key in headers) { for (let key in headers) {
if (key == 'Authorization') if (key == 'Authorization')
this._log.trace("HTTP Header " + key + ": ***** (suppressed)"); this._log.trace("HTTP Header " + key + ": ***** (suppressed)");
@ -178,6 +219,10 @@ Resource.prototype = {
this._lastProgress = Date.now(); this._lastProgress = Date.now();
}, },
// ** {{{ Resource.filterUpload }}} **
//
// Apply pre-request filters. Currently, this is done before
// any PUT request.
filterUpload: function Res_filterUpload(onComplete) { filterUpload: function Res_filterUpload(onComplete) {
let fn = function() { let fn = function() {
let self = yield; let self = yield;
@ -188,6 +233,10 @@ Resource.prototype = {
fn.async(this, onComplete); fn.async(this, onComplete);
}, },
// ** {{{ Resource.filterDownload }}} **
//
// Apply post-request filters. Currently, this done after
// any GET request.
filterDownload: function Res_filterUpload(onComplete) { filterDownload: function Res_filterUpload(onComplete) {
let fn = function() { let fn = function() {
let self = yield; let self = yield;
@ -199,6 +248,11 @@ Resource.prototype = {
fn.async(this, onComplete); fn.async(this, onComplete);
}, },
// ** {{{ Resource._request }}} **
//
// Perform a particular HTTP request on the resource. This method
// is never called directly, but is used by the high-level
// {{{get}}}, {{{put}}}, {{{post}}} and {{delete}} methods.
_request: function Res__request(action, data) { _request: function Res__request(action, data) {
let self = yield; let self = yield;
let iter = 0; let iter = 0;
@ -207,6 +261,8 @@ Resource.prototype = {
if ("undefined" != typeof(data)) if ("undefined" != typeof(data))
this._data = data; this._data = data;
// PUT and POST are trreated differently because
// they have payload data.
if ("PUT" == action || "POST" == action) { if ("PUT" == action || "POST" == action) {
yield this.filterUpload(self.cb); yield this.filterUpload(self.cb);
this._log.trace(action + " Body:\n" + this._data); this._log.trace(action + " Body:\n" + this._data);
@ -222,6 +278,8 @@ Resource.prototype = {
channel.setUploadStream(stream, type, this._data.length); channel.setUploadStream(stream, type, this._data.length);
} }
// Setup a channel listener so that the actual network operation
// is performed asynchronously.
let listener = new ChannelListener(self.cb, this._onProgress, this._log); let listener = new ChannelListener(self.cb, this._onProgress, this._log);
channel.requestMethod = action; channel.requestMethod = action;
this._data = yield channel.asyncOpen(listener, null); this._data = yield channel.asyncOpen(listener, null);
@ -253,23 +311,40 @@ Resource.prototype = {
self.done(this._data); self.done(this._data);
}, },
// ** {{{ Resource.get }}} **
//
// Perform an asynchronous HTTP GET for this resource.
// onComplete will be called on completion of the request.
get: function Res_get(onComplete) { get: function Res_get(onComplete) {
this._request.async(this, onComplete, "GET"); this._request.async(this, onComplete, "GET");
}, },
// ** {{{ Resource.get }}} **
//
// Perform a HTTP PUT for this resource.
put: function Res_put(onComplete, data) { put: function Res_put(onComplete, data) {
this._request.async(this, onComplete, "PUT", data); this._request.async(this, onComplete, "PUT", data);
}, },
// ** {{{ Resource.post }}} **
//
// Perform a HTTP POST for this resource.
post: function Res_post(onComplete, data) { post: function Res_post(onComplete, data) {
this._request.async(this, onComplete, "POST", data); this._request.async(this, onComplete, "POST", data);
}, },
// ** {{{ Resource.delete }}} **
//
// Perform a HTTP DELETE for this resource.
delete: function Res_delete(onComplete) { delete: function Res_delete(onComplete) {
this._request.async(this, onComplete, "DELETE"); this._request.async(this, onComplete, "DELETE");
} }
}; };
// = ChannelListener =
//
// This object implements the {{{nsIStreamListener}}} interface
// and is called as the network operation proceeds.
function ChannelListener(onComplete, onProgress, logger) { function ChannelListener(onComplete, onProgress, logger) {
this._onComplete = onComplete; this._onComplete = onComplete;
this._onProgress = onProgress; this._onProgress = onProgress;
@ -302,11 +377,24 @@ ChannelListener.prototype = {
} }
}; };
/* Parses out single WBOs from a full dump */ // = RecordParser =
//
// This object retrives single WBOs from a stream of incoming
// JSON. This should be useful for performance optimizations
// in cases where memory is low (on Fennec, for example).
//
// XXX: Note that this parser is currently not used because we
// are yet to figure out the best way to integrate it with the
// asynchronous nature of {{{ChannelListener}}}. Ed's work in the
// Sync module will make this easier in the future.
function RecordParser(data) { function RecordParser(data) {
this._data = data; this._data = data;
} }
RecordParser.prototype = { RecordParser.prototype = {
// ** {{{ RecordParser.getNextRecord }}} **
//
// Returns a single WBO from the stream of JSON received
// so far.
getNextRecord: function RecordParser_getNextRecord() { getNextRecord: function RecordParser_getNextRecord() {
let start; let start;
let bCount = 0; let bCount = 0;
@ -333,11 +421,23 @@ RecordParser.prototype = {
return false; return false;
}, },
// ** {{{ RecordParser.append }}} **
//
// Appends data to the current internal buffer
// of received data by the parser. The buffer
// is continously processed as {{{getNextRecord}}}
// is called, so the caller need not keep a copy
// of the data passed to this function.
append: function RecordParser_append(data) { append: function RecordParser_append(data) {
this._data += data; this._data += data;
} }
}; };
// = JsonFilter =
//
// Currently, the only filter used in conjunction with
// {{{Resource.filters}}}. It simply encodes outgoing records
// as JSON, and decodes incoming JSON into JS objects.
function JsonFilter() { function JsonFilter() {
let level = "Debug"; let level = "Debug";
try { level = Utils.prefs.getCharPref("log.logger.network.jsonFilter"); } try { level = Utils.prefs.getCharPref("log.logger.network.jsonFilter"); }
@ -359,6 +459,13 @@ JsonFilter.prototype = {
} }
}; };
// = badCertListener =
//
// We use this listener to ignore bad HTTPS
// certificates and continue a request on a network
// channel. Probably not a very smart thing to do,
// but greatly simplifies debugging and is just very
// convenient.
function badCertListener() { function badCertListener() {
} }
badCertListener.prototype = { badCertListener.prototype = {