Bug 1470286 Propagate channel creation and async open time across internal redirects. r=valentin

This commit is contained in:
Ben Kelly 2018-06-23 10:10:10 -07:00
parent af8fa26053
commit 06ae64dde8
7 changed files with 75 additions and 7 deletions

View File

@ -36,8 +36,12 @@ interface nsITimedChannel : nsISupports {
attribute uint8_t redirectCount;
attribute uint8_t internalRedirectCount;
[noscript] readonly attribute TimeStamp channelCreation;
[noscript] readonly attribute TimeStamp asyncOpen;
// These properties should only be written externally when they must be
// propagated across an internal redirect. For example, when a service
// worker interception falls back to network we need to copy the original
// timing values to the new nsHttpChannel.
[noscript] attribute TimeStamp channelCreation;
[noscript] attribute TimeStamp asyncOpen;
// The following are only set when the request is intercepted by a service
// worker no matter the response is synthesized.

View File

@ -201,6 +201,7 @@ HttpBaseChannel::HttpBaseChannel()
, mRedirectCount(0)
, mInternalRedirectCount(0)
, mChannelCreationTime(0)
, mAsyncOpenTimeOverriden(false)
, mForcePending(false)
, mCorsIncludeCredentials(false)
, mCorsMode(nsIHttpChannelInternal::CORS_MODE_NO_CORS)
@ -3784,14 +3785,28 @@ HttpBaseChannel::SetupReplacementChannel(nsIURI *newURI,
newTimedChannel->SetInternalRedirectCount(mInternalRedirectCount);
}
TimeStamp oldAsyncOpenTime;
oldTimedChannel->GetAsyncOpen(&oldAsyncOpenTime);
if (redirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) {
TimeStamp oldChannelCreationTimestamp;
oldTimedChannel->GetChannelCreation(&oldChannelCreationTimestamp);
if (!oldChannelCreationTimestamp.IsNull()) {
newTimedChannel->SetChannelCreation(oldChannelCreationTimestamp);
}
if (!oldAsyncOpenTime.IsNull()) {
newTimedChannel->SetAsyncOpen(oldAsyncOpenTime);
}
}
// If the RedirectStart is null, we will use the AsyncOpen value of the
// previous channel (this is the first redirect in the redirects chain).
if (mRedirectStartTimeStamp.IsNull()) {
// Only do this for real redirects. Internal redirects should be hidden.
if (!(redirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL)) {
TimeStamp asyncOpen;
oldTimedChannel->GetAsyncOpen(&asyncOpen);
newTimedChannel->SetRedirectStart(asyncOpen);
newTimedChannel->SetRedirectStart(oldAsyncOpenTime);
}
} else {
newTimedChannel->SetRedirectStart(mRedirectStartTimeStamp);
@ -3928,12 +3943,29 @@ HttpBaseChannel::GetChannelCreation(TimeStamp* _retval) {
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::SetChannelCreation(TimeStamp aValue) {
MOZ_DIAGNOSTIC_ASSERT(!aValue.IsNull());
TimeDuration adjust = aValue - mChannelCreationTimestamp;
mChannelCreationTimestamp = aValue;
mChannelCreationTime += (PRTime)adjust.ToMicroseconds();
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::GetAsyncOpen(TimeStamp* _retval) {
*_retval = mAsyncOpenTime;
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::SetAsyncOpen(TimeStamp aValue) {
MOZ_DIAGNOSTIC_ASSERT(!aValue.IsNull());
mAsyncOpenTime = aValue;
mAsyncOpenTimeOverriden = true;
return NS_OK;
}
/**
* @return the number of redirects. There is no check for cross-domain
* redirects. This check must be done by the consumers.

View File

@ -676,6 +676,7 @@ protected:
// so that the timing can still be queried from OnStopRequest
TimingStruct mTransactionTimings;
bool mAsyncOpenTimeOverriden;
bool mForcePending;
bool mCorsIncludeCredentials;

View File

@ -2502,7 +2502,10 @@ HttpChannelChild::AsyncOpen(nsIStreamListener *listener, nsISupports *aContext)
return NS_OK;
}
mAsyncOpenTime = TimeStamp::Now();
if (!mAsyncOpenTimeOverriden) {
mAsyncOpenTime = TimeStamp::Now();
}
#ifdef MOZ_TASK_TRACER
if (tasktracer::IsStartLogging()) {
nsCOMPtr<nsIURI> uri;

View File

@ -685,6 +685,16 @@ InterceptedHttpChannel::ResetInterception(void)
rv = SetupReplacementChannel(mURI, newChannel, true, flags);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsITimedChannel> newTimedChannel = do_QueryInterface(newChannel);
if (newTimedChannel) {
if (!mAsyncOpenTime.IsNull()) {
newTimedChannel->SetAsyncOpen(mAsyncOpenTime);
}
if (!mChannelCreationTimestamp.IsNull()) {
newTimedChannel->SetChannelCreation(mChannelCreationTimestamp);
}
}
if (mRedirectMode != nsIHttpChannelInternal::REDIRECT_MODE_MANUAL) {
nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL;
rv = newChannel->GetLoadFlags(&loadFlags);

View File

@ -610,6 +610,15 @@ NullHttpChannel::GetChannelCreation(mozilla::TimeStamp *aChannelCreation)
return NS_OK;
}
NS_IMETHODIMP
NullHttpChannel::SetChannelCreation(TimeStamp aValue) {
MOZ_DIAGNOSTIC_ASSERT(!aValue.IsNull());
TimeDuration adjust = aValue - mChannelCreationTimestamp;
mChannelCreationTimestamp = aValue;
mChannelCreationTime += (PRTime)adjust.ToMicroseconds();
return NS_OK;
}
NS_IMETHODIMP
NullHttpChannel::GetAsyncOpen(mozilla::TimeStamp *aAsyncOpen)
{
@ -617,6 +626,13 @@ NullHttpChannel::GetAsyncOpen(mozilla::TimeStamp *aAsyncOpen)
return NS_OK;
}
NS_IMETHODIMP
NullHttpChannel::SetAsyncOpen(TimeStamp aValue) {
MOZ_DIAGNOSTIC_ASSERT(!aValue.IsNull());
mAsyncOpenTime = aValue;
return NS_OK;
}
NS_IMETHODIMP
NullHttpChannel::GetLaunchServiceWorkerStart(mozilla::TimeStamp *_retval)
{

View File

@ -6050,7 +6050,9 @@ nsHttpChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *context)
// don't want it after OnModifyRequest() weighs in. But waiting for
// that to complete would mean we don't include proxy resolution in the
// timing.
mAsyncOpenTime = TimeStamp::Now();
if (!mAsyncOpenTimeOverriden) {
mAsyncOpenTime = TimeStamp::Now();
}
// Remember we have Authorization header set here. We need to check on it
// just once and early, AsyncOpen is the best place.