mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-22 09:45:41 +00:00
Bug 1244227
- properly report throttled network timing; r=Honza
MozReview-Commit-ID: BCJLSRGS0vE --HG-- extra : transplant_source : y%95%21%B8%DC%C3%7BM%F7%5D%88c9%B9%D0r%19%D8%3C%E4
This commit is contained in:
parent
becfb61023
commit
397c46c617
@ -563,8 +563,6 @@ NetworkResponseListener.prototype = {
|
||||
this.httpActivity.discardResponseBody
|
||||
);
|
||||
|
||||
this.httpActivity.channel = null;
|
||||
this.httpActivity.owner = null;
|
||||
this.httpActivity = null;
|
||||
this.sink = null;
|
||||
this.inputStream = null;
|
||||
@ -680,6 +678,13 @@ NetworkMonitor.prototype = {
|
||||
0x804b0006: "STATUS_RECEIVING_FROM"
|
||||
},
|
||||
|
||||
httpDownloadActivities: [
|
||||
gActivityDistributor.ACTIVITY_SUBTYPE_RESPONSE_START,
|
||||
gActivityDistributor.ACTIVITY_SUBTYPE_RESPONSE_HEADER,
|
||||
gActivityDistributor.ACTIVITY_SUBTYPE_RESPONSE_COMPLETE,
|
||||
gActivityDistributor.ACTIVITY_SUBTYPE_TRANSACTION_CLOSE
|
||||
],
|
||||
|
||||
// Network response bodies are piped through a buffer of the given size (in
|
||||
// bytes).
|
||||
responsePipeSegmentSize: null,
|
||||
@ -864,6 +869,44 @@ NetworkMonitor.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* A helper function for observeActivity. This does whatever work
|
||||
* is required by a particular http activity event. Arguments are
|
||||
* the same as for observeActivity.
|
||||
*/
|
||||
_dispatchActivity: function (httpActivity, channel, activityType,
|
||||
activitySubtype, timestamp, extraSizeData,
|
||||
extraStringData) {
|
||||
let transCodes = this.httpTransactionCodes;
|
||||
|
||||
// Store the time information for this activity subtype.
|
||||
if (activitySubtype in transCodes) {
|
||||
let stage = transCodes[activitySubtype];
|
||||
if (stage in httpActivity.timings) {
|
||||
httpActivity.timings[stage].last = timestamp;
|
||||
} else {
|
||||
httpActivity.timings[stage] = {
|
||||
first: timestamp,
|
||||
last: timestamp,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
switch (activitySubtype) {
|
||||
case gActivityDistributor.ACTIVITY_SUBTYPE_REQUEST_BODY_SENT:
|
||||
this._onRequestBodySent(httpActivity);
|
||||
break;
|
||||
case gActivityDistributor.ACTIVITY_SUBTYPE_RESPONSE_HEADER:
|
||||
this._onResponseHeader(httpActivity, extraStringData);
|
||||
break;
|
||||
case gActivityDistributor.ACTIVITY_SUBTYPE_TRANSACTION_CLOSE:
|
||||
this._onTransactionClose(httpActivity);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Begin observing HTTP traffic that originates inside the current tab.
|
||||
*
|
||||
@ -913,33 +956,20 @@ NetworkMonitor.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
let transCodes = this.httpTransactionCodes;
|
||||
|
||||
// Store the time information for this activity subtype.
|
||||
if (activitySubtype in transCodes) {
|
||||
let stage = transCodes[activitySubtype];
|
||||
if (stage in httpActivity.timings) {
|
||||
httpActivity.timings[stage].last = timestamp;
|
||||
} else {
|
||||
httpActivity.timings[stage] = {
|
||||
first: timestamp,
|
||||
last: timestamp,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
switch (activitySubtype) {
|
||||
case gActivityDistributor.ACTIVITY_SUBTYPE_REQUEST_BODY_SENT:
|
||||
this._onRequestBodySent(httpActivity);
|
||||
break;
|
||||
case gActivityDistributor.ACTIVITY_SUBTYPE_RESPONSE_HEADER:
|
||||
this._onResponseHeader(httpActivity, extraStringData);
|
||||
break;
|
||||
case gActivityDistributor.ACTIVITY_SUBTYPE_TRANSACTION_CLOSE:
|
||||
this._onTransactionClose(httpActivity);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
// If we're throttling, we must not report events as they arrive
|
||||
// from platform, but instead let the throttler emit the events
|
||||
// after some time has elapsed.
|
||||
if (httpActivity.downloadThrottle &&
|
||||
this.httpDownloadActivities.indexOf(activitySubtype) >= 0) {
|
||||
let callback = this._dispatchActivity.bind(this);
|
||||
httpActivity.downloadThrottle
|
||||
.addActivityCallback(callback, httpActivity, channel, activityType,
|
||||
activitySubtype, timestamp, extraSizeData,
|
||||
extraStringData);
|
||||
} else {
|
||||
this._dispatchActivity(httpActivity, channel, activityType,
|
||||
activitySubtype, timestamp, extraSizeData,
|
||||
extraStringData);
|
||||
}
|
||||
}),
|
||||
|
||||
@ -1297,12 +1327,10 @@ NetworkMonitor.prototype = {
|
||||
harTimings.connect = -1;
|
||||
}
|
||||
|
||||
if ((timings.STATUS_WAITING_FOR || timings.STATUS_RECEIVING_FROM) &&
|
||||
(timings.STATUS_CONNECTED_TO || timings.STATUS_SENDING_TO)) {
|
||||
harTimings.send = (timings.STATUS_WAITING_FOR ||
|
||||
timings.STATUS_RECEIVING_FROM).first -
|
||||
(timings.STATUS_CONNECTED_TO ||
|
||||
timings.STATUS_SENDING_TO).last;
|
||||
if (timings.STATUS_SENDING_TO) {
|
||||
harTimings.send = timings.STATUS_SENDING_TO.last - timings.STATUS_SENDING_TO.first;
|
||||
} else if (timings.REQUEST_HEADER && timings.REQUEST_BODY_SENT) {
|
||||
harTimings.send = timings.REQUEST_BODY_SENT.last - timings.REQUEST_HEADER.first;
|
||||
} else {
|
||||
harTimings.send = -1;
|
||||
}
|
||||
|
@ -13,6 +13,10 @@ const ArrayBufferInputStream = CC("@mozilla.org/io/arraybuffer-input-stream;1",
|
||||
const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
|
||||
"nsIBinaryInputStream", "setInputStream");
|
||||
|
||||
loader.lazyServiceGetter(this, "gActivityDistributor",
|
||||
"@mozilla.org/network/http-activity-distributor;1",
|
||||
"nsIHttpActivityDistributor");
|
||||
|
||||
const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const {setTimeout} = Cu.import("resource://gre/modules/Timer.jsm", {});
|
||||
|
||||
@ -32,6 +36,8 @@ function NetworkThrottleListener(queue) {
|
||||
this.pendingData = [];
|
||||
this.pendingException = null;
|
||||
this.offset = 0;
|
||||
this.responseStarted = false;
|
||||
this.activities = {};
|
||||
}
|
||||
|
||||
NetworkThrottleListener.prototype = {
|
||||
@ -133,6 +139,9 @@ NetworkThrottleListener.prototype = {
|
||||
}
|
||||
|
||||
this.offset += bytesPermitted;
|
||||
// Maybe our state has changed enough to emit an event.
|
||||
this.maybeEmitEvents();
|
||||
|
||||
return {length: bytesPermitted, done};
|
||||
},
|
||||
|
||||
@ -143,6 +152,71 @@ NetworkThrottleListener.prototype = {
|
||||
pendingCount: function () {
|
||||
return this.pendingData.length;
|
||||
},
|
||||
|
||||
/**
|
||||
* This is called when an http activity event is delivered. This
|
||||
* object delays the event until the appropriate moment.
|
||||
*/
|
||||
addActivityCallback: function (callback, httpActivity, channel, activityType,
|
||||
activitySubtype, timestamp, extraSizeData,
|
||||
extraStringData) {
|
||||
let datum = {callback, httpActivity, channel, activityType,
|
||||
activitySubtype, extraSizeData,
|
||||
extraStringData};
|
||||
this.activities[activitySubtype] = datum;
|
||||
|
||||
if (activitySubtype ===
|
||||
gActivityDistributor.ACTIVITY_SUBTYPE_RESPONSE_COMPLETE) {
|
||||
this.totalSize = extraSizeData;
|
||||
}
|
||||
|
||||
this.maybeEmitEvents();
|
||||
},
|
||||
|
||||
/**
|
||||
* This is called for a download throttler when the latency timeout
|
||||
* has ended.
|
||||
*/
|
||||
responseStart: function () {
|
||||
this.responseStarted = true;
|
||||
this.maybeEmitEvents();
|
||||
},
|
||||
|
||||
/**
|
||||
* Check our internal state and emit any http activity events as
|
||||
* needed. Note that we wait until both our internal state has
|
||||
* changed and we've received the real http activity event from
|
||||
* platform. This approach ensures we can both pass on the correct
|
||||
* data from the original event, and update the reported time to be
|
||||
* consistent with the delay we're introducing.
|
||||
*/
|
||||
maybeEmitEvents: function () {
|
||||
if (this.responseStarted) {
|
||||
this.maybeEmit(gActivityDistributor.ACTIVITY_SUBTYPE_RESPONSE_START);
|
||||
this.maybeEmit(gActivityDistributor.ACTIVITY_SUBTYPE_RESPONSE_HEADER);
|
||||
}
|
||||
|
||||
if (this.totalSize !== undefined && this.offset >= this.totalSize) {
|
||||
this.maybeEmit(gActivityDistributor.ACTIVITY_SUBTYPE_RESPONSE_COMPLETE);
|
||||
this.maybeEmit(gActivityDistributor.ACTIVITY_SUBTYPE_TRANSACTION_CLOSE);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Emit an event for |code|, if the appropriate entry in
|
||||
* |activities| is defined.
|
||||
*/
|
||||
maybeEmit: function (code) {
|
||||
if (this.activities[code] !== undefined) {
|
||||
let {callback, httpActivity, channel, activityType,
|
||||
activitySubtype, extraSizeData,
|
||||
extraStringData} = this.activities[code];
|
||||
let now = Date.now() * 1000;
|
||||
callback(httpActivity, channel, activityType, activitySubtype,
|
||||
now, extraSizeData, extraStringData);
|
||||
this.activities[code] = undefined;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -183,6 +257,7 @@ NetworkThrottleQueue.prototype = {
|
||||
* listener has elapsed.
|
||||
*/
|
||||
allowDataFrom: function (throttleListener) {
|
||||
throttleListener.responseStart();
|
||||
this.pendingRequests.delete(throttleListener);
|
||||
const count = throttleListener.pendingCount();
|
||||
for (let i = 0; i < count; ++i) {
|
||||
|
Loading…
Reference in New Issue
Block a user