Bug 1154309 - Add New Resource Timing Fields r=bz,hurley

This commit is contained in:
Nate Hughes ext:(%2C%20Valentin%20Gosu%20%3Cvalentin.gosu%40gmail.com%3E) 2015-07-24 08:49:25 -07:00
parent 3874e5d162
commit 33aa28e0f8
23 changed files with 322 additions and 6 deletions

View File

@ -27,7 +27,10 @@ PerformanceResourceTiming::PerformanceResourceTiming(nsPerformanceTiming* aPerfo
nsPerformance* aPerformance,
const nsAString& aName)
: PerformanceEntry(aPerformance, aName, NS_LITERAL_STRING("resource")),
mTiming(aPerformanceTiming)
mTiming(aPerformanceTiming),
mEncodedBodySize(0),
mTransferSize(0),
mDecodedBodySize(0)
{
MOZ_ASSERT(aPerformance, "Parent performance object should be provided");
}

View File

@ -52,6 +52,16 @@ public:
mInitiatorType = aInitiatorType;
}
void GetNextHopProtocol(nsAString& aNextHopProtocol) const
{
aNextHopProtocol = mNextHopProtocol;
}
void SetNextHopProtocol(const nsAString& aNextHopProtocol)
{
mNextHopProtocol = aNextHopProtocol;
}
DOMHighResTimeStamp FetchStart() const {
return mTiming
? mTiming->FetchStartHighRes()
@ -128,11 +138,45 @@ public:
return this;
}
uint64_t TransferSize() const
{
return mTiming && mTiming->TimingAllowed() ? mTransferSize : 0;
}
uint64_t EncodedBodySize() const
{
return mTiming && mTiming->TimingAllowed() ? mEncodedBodySize : 0;
}
uint64_t DecodedBodySize() const
{
return mTiming && mTiming->TimingAllowed() ? mDecodedBodySize : 0;
}
void SetEncodedBodySize(uint64_t aEncodedBodySize)
{
mEncodedBodySize = aEncodedBodySize;
}
void SetTransferSize(uint64_t aTransferSize)
{
mTransferSize = aTransferSize;
}
void SetDecodedBodySize(uint64_t aDecodedBodySize)
{
mDecodedBodySize = aDecodedBodySize;
}
protected:
virtual ~PerformanceResourceTiming();
nsString mInitiatorType;
nsString mNextHopProtocol;
RefPtr<nsPerformanceTiming> mTiming;
uint64_t mEncodedBodySize;
uint64_t mTransferSize;
uint64_t mDecodedBodySize;
};
} // namespace dom

View File

@ -566,6 +566,25 @@ nsPerformance::AddEntry(nsIHttpChannel* channel,
RefPtr<PerformanceResourceTiming> performanceEntry =
new PerformanceResourceTiming(performanceTiming, this, entryName);
nsAutoCString protocol;
channel->GetProtocolVersion(protocol);
performanceEntry->SetNextHopProtocol(NS_ConvertUTF8toUTF16(protocol));
uint64_t encodedBodySize = 0;
channel->GetEncodedBodySize(&encodedBodySize);
performanceEntry->SetEncodedBodySize(encodedBodySize);
uint64_t transferSize = 0;
channel->GetTransferSize(&transferSize);
performanceEntry->SetTransferSize(transferSize);
uint64_t decodedBodySize = 0;
channel->GetDecodedBodySize(&decodedBodySize);
if (decodedBodySize == 0) {
decodedBodySize = encodedBodySize;
}
performanceEntry->SetDecodedBodySize(decodedBodySize);
// If the initiator type had no valid value, then set it to the default
// ("other") value.
if (initiatorType.IsEmpty()) {

View File

@ -18,6 +18,7 @@ interface PerformanceResourceTiming : PerformanceEntry
// If the initiator is an XMLHttpRequest object, the initiatorType attribute
// must return the string "xmlhttprequest".
readonly attribute DOMString initiatorType;
readonly attribute DOMString nextHopProtocol;
readonly attribute DOMHighResTimeStamp redirectStart;
readonly attribute DOMHighResTimeStamp redirectEnd;
@ -31,5 +32,9 @@ interface PerformanceResourceTiming : PerformanceEntry
readonly attribute DOMHighResTimeStamp responseStart;
readonly attribute DOMHighResTimeStamp responseEnd;
readonly attribute unsigned long long transferSize;
readonly attribute unsigned long long encodedBodySize;
readonly attribute unsigned long long decodedBodySize;
jsonifier;
};

View File

@ -149,6 +149,9 @@ struct ParamTraits<mozilla::net::ResourceTimingStruct>
WriteParam(aMsg, aParam.fetchStart);
WriteParam(aMsg, aParam.redirectStart);
WriteParam(aMsg, aParam.redirectEnd);
WriteParam(aMsg, aParam.transferSize);
WriteParam(aMsg, aParam.encodedBodySize);
}
static bool Read(const Message* aMsg, void** aIter, mozilla::net::ResourceTimingStruct* aResult)
@ -162,7 +165,9 @@ struct ParamTraits<mozilla::net::ResourceTimingStruct>
ReadParam(aMsg, aIter, &aResult->responseEnd) &&
ReadParam(aMsg, aIter, &aResult->fetchStart) &&
ReadParam(aMsg, aIter, &aResult->redirectStart) &&
ReadParam(aMsg, aIter, &aResult->redirectEnd);
ReadParam(aMsg, aIter, &aResult->redirectEnd) &&
ReadParam(aMsg, aIter, &aResult->transferSize) &&
ReadParam(aMsg, aIter, &aResult->encodedBodySize);
}
};

View File

@ -95,6 +95,9 @@ HttpBaseChannel::HttpBaseChannel()
, mCorsMode(nsIHttpChannelInternal::CORS_MODE_NO_CORS)
, mRedirectMode(nsIHttpChannelInternal::REDIRECT_MODE_FOLLOW)
, mOnStartRequestCalled(false)
, mTransferSize(0)
, mDecodedBodySize(0)
, mEncodedBodySize(0)
, mRequireCORSPreflight(false)
, mWithCredentials(false)
, mReportCollector(new ConsoleReportCollector())
@ -1092,6 +1095,27 @@ HttpBaseChannel::nsContentEncodings::PrepareForNext(void)
// HttpBaseChannel::nsIHttpChannel
//-----------------------------------------------------------------------------
NS_IMETHODIMP
HttpBaseChannel::GetTransferSize(uint64_t *aTransferSize)
{
*aTransferSize = mTransferSize;
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::GetDecodedBodySize(uint64_t *aDecodedBodySize)
{
*aDecodedBodySize = mDecodedBodySize;
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::GetEncodedBodySize(uint64_t *aEncodedBodySize)
{
*aEncodedBodySize = mEncodedBodySize;
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::GetRequestMethod(nsACString& aMethod)
{
@ -1751,6 +1775,30 @@ HttpBaseChannel::SetIsMainDocumentChannel(bool aValue)
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::GetProtocolVersion(nsACString& aProtocolVersion)
{
nsresult rv;
nsCOMPtr<nsISSLSocketControl> ssl = do_QueryInterface(mSecurityInfo, &rv);
nsAutoCString protocol;
if (NS_SUCCEEDED(rv) && ssl &&
NS_SUCCEEDED(ssl->GetNegotiatedNPN(protocol)) &&
!protocol.IsEmpty()) {
// The negotiated protocol was not empty so we can use it.
aProtocolVersion = protocol;
return NS_OK;
}
if (mResponseHead) {
uint32_t version = mResponseHead->Version();
aProtocolVersion.Assign(nsHttp::GetProtocolVersion(version));
return NS_OK;
}
return NS_ERROR_NOT_AVAILABLE;
}
//-----------------------------------------------------------------------------
// HttpBaseChannel::nsIHttpChannelInternal
//-----------------------------------------------------------------------------
@ -2396,6 +2444,7 @@ HttpBaseChannel::ReleaseListeners()
mListenerContext = nullptr;
mCallbacks = nullptr;
mProgressSink = nullptr;
mCompressListener = nullptr;
}
void

View File

@ -164,9 +164,13 @@ public:
NS_IMETHOD GetRequestSucceeded(bool *aValue) override;
NS_IMETHOD RedirectTo(nsIURI *newURI) override;
NS_IMETHOD GetSchedulingContextID(nsID *aSCID) override;
NS_IMETHOD GetTransferSize(uint64_t *aTransferSize) override;
NS_IMETHOD GetDecodedBodySize(uint64_t *aDecodedBodySize) override;
NS_IMETHOD GetEncodedBodySize(uint64_t *aEncodedBodySize) override;
NS_IMETHOD SetSchedulingContextID(const nsID aSCID) override;
NS_IMETHOD GetIsMainDocumentChannel(bool* aValue) override;
NS_IMETHOD SetIsMainDocumentChannel(bool aValue) override;
NS_IMETHOD GetProtocolVersion(nsACString & aProtocolVersion) override;
// nsIHttpChannelInternal
NS_IMETHOD GetDocumentURI(nsIURI **aDocumentURI) override;
@ -355,6 +359,9 @@ protected:
nsCOMPtr<nsIURI> mReferrer;
nsCOMPtr<nsIApplicationCache> mApplicationCache;
// An instance of nsHTTPCompressConv
nsCOMPtr<nsIStreamListener> mCompressListener;
nsHttpRequestHead mRequestHead;
nsCOMPtr<nsIInputStream> mUploadStream;
nsCOMPtr<nsIRunnable> mUploadCloneableCallback;
@ -471,6 +478,10 @@ protected:
// than once.
bool mOnStartRequestCalled;
uint64_t mTransferSize;
uint64_t mDecodedBodySize;
uint64_t mEncodedBodySize;
// The network interface id that's associated with this channel.
nsCString mNetworkInterfaceId;

View File

@ -35,6 +35,7 @@
#include "mozIThirdPartyUtil.h"
#include "nsContentSecurityManager.h"
#include "nsIDeprecationWarner.h"
#include "nsICompressConvStats.h"
#ifdef OS_POSIX
#include "chrome/common/file_descriptor_set_posix.h"
@ -503,6 +504,7 @@ HttpChannelChild::DoOnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
if (mDivertingToParent) {
mListener = nullptr;
mListenerContext = nullptr;
mCompressListener = nullptr;
if (mLoadGroup) {
mLoadGroup->RemoveRequest(this, nullptr, mStatus);
}
@ -516,6 +518,7 @@ HttpChannelChild::DoOnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
Cancel(rv);
} else if (listener) {
mListener = listener;
mCompressListener = listener;
}
}
@ -840,6 +843,11 @@ HttpChannelChild::OnStopRequest(const nsresult& channelStatus,
new MaybeDivertOnStopHttpEvent(this, channelStatus));
}
nsCOMPtr<nsICompressConvStats> conv = do_QueryInterface(mCompressListener);
if (conv) {
conv->GetDecodedDataLength(&mDecodedBodySize);
}
mTransactionTimings.domainLookupStart = timing.domainLookupStart;
mTransactionTimings.domainLookupEnd = timing.domainLookupEnd;
mTransactionTimings.connectStart = timing.connectStart;
@ -850,6 +858,8 @@ HttpChannelChild::OnStopRequest(const nsresult& channelStatus,
mAsyncOpenTime = timing.fetchStart;
mRedirectStartTimeStamp = timing.redirectStart;
mRedirectEndTimeStamp = timing.redirectEnd;
mTransferSize = timing.transferSize;
mEncodedBodySize = timing.encodedBodySize;
nsPerformance* documentPerformance = GetPerformance();
if (documentPerformance) {

View File

@ -1174,6 +1174,10 @@ HttpChannelParent::OnStopRequest(nsIRequest *aRequest,
mChannel->GetAsyncOpen(&timing.fetchStart);
mChannel->GetRedirectStart(&timing.redirectStart);
mChannel->GetRedirectEnd(&timing.redirectEnd);
mChannel->GetTransferSize(&timing.transferSize);
mChannel->GetEncodedBodySize(&timing.encodedBodySize);
// decodedBodySize can be computed in the child process so it doesn't need
// to be passed down.
if (mIPCClosed || !SendOnStopRequest(aStatusCode, timing))
return NS_ERROR_UNEXPECTED;

View File

@ -56,6 +56,18 @@ NullHttpChannel::Init(nsIURI *aURI,
// NullHttpChannel::nsIHttpChannel
//-----------------------------------------------------------------------------
NS_IMETHODIMP
NullHttpChannel::GetTransferSize(uint64_t *aTransferSize)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
NullHttpChannel::GetDecodedBodySize(uint64_t *aDecodedBodySize)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
NullHttpChannel::GetRequestMethod(nsACString & aRequestMethod)
{
@ -232,6 +244,18 @@ NullHttpChannel::SetSchedulingContextID(const nsID scID)
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
NullHttpChannel::GetProtocolVersion(nsACString& aProtocolVersion)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
NullHttpChannel::GetEncodedBodySize(uint64_t *aEncodedBodySize)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
//-----------------------------------------------------------------------------
// NullHttpChannel::nsIChannel
//-----------------------------------------------------------------------------

View File

@ -24,6 +24,8 @@ struct ResourceTimingStruct : TimingStruct {
TimeStamp fetchStart;
TimeStamp redirectStart;
TimeStamp redirectEnd;
uint64_t transferSize;
uint64_t encodedBodySize;
};
} // namespace net

View File

@ -229,6 +229,26 @@ nsHttp::IsValidToken(const char *start, const char *end)
return true;
}
const char*
nsHttp::GetProtocolVersion(uint32_t pv)
{
switch (pv) {
case SPDY_VERSION_31:
return "spdy/3.1";
case HTTP_VERSION_2:
case NS_HTTP_VERSION_2_0:
return "h2";
case NS_HTTP_VERSION_1_0:
return "http/1.0";
case NS_HTTP_VERSION_1_1:
return "http/1.1";
default:
NS_WARNING(nsPrintfCString("Unkown protocol version: 0x%X. "
"Please file a bug", pv).get());
return "http/1.1";
}
}
// static
bool
nsHttp::IsReasonableHeaderValue(const nsACString &s)

View File

@ -167,6 +167,9 @@ struct nsHttp
// Return whether the HTTP status code represents a permanent redirect
static bool IsPermanentRedirect(uint32_t httpStatus);
// Returns the APLN token which represents the used protocol version.
static const char* GetProtocolVersion(uint32_t pv);
// Declare all atoms
//
// The atom names and values are stored in nsHttpAtomList.h and are brought

View File

@ -89,6 +89,7 @@
#include "nsIPackagedAppService.h"
#include "nsIDeprecationWarner.h"
#include "nsIDocument.h"
#include "nsICompressConvStats.h"
namespace mozilla { namespace net {
@ -1059,6 +1060,7 @@ nsHttpChannel::CallOnStartRequest()
}
if (listener) {
mListener = listener;
mCompressListener = listener;
}
}
@ -5351,6 +5353,19 @@ nsHttpChannel::BeginConnect()
return NS_OK;
}
NS_IMETHODIMP
nsHttpChannel::GetEncodedBodySize(uint64_t *aEncodedBodySize)
{
if (mCacheEntry && !mCacheEntryIsWriteOnly) {
int64_t dataSize = 0;
mCacheEntry->GetDataSize(&dataSize);
*aEncodedBodySize = dataSize;
} else {
*aEncodedBodySize = mLogicalOffset;
}
return NS_OK;
}
//-----------------------------------------------------------------------------
// nsHttpChannel::nsIHttpChannelInternal
//-----------------------------------------------------------------------------
@ -5844,6 +5859,11 @@ nsHttpChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult st
gHttpHandler->CancelTransaction(mTransaction, status);
}
nsCOMPtr<nsICompressConvStats> conv = do_QueryInterface(mCompressListener);
if (conv) {
conv->GetDecodedDataLength(&mDecodedBodySize);
}
if (mTransaction) {
// determine if we should call DoAuthRetry
bool authRetry = mAuthRetryPending && NS_SUCCEEDED(status);
@ -5871,6 +5891,8 @@ nsHttpChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult st
if (mCaps & NS_HTTP_STICKY_CONNECTION)
stickyConn = mTransaction->GetConnectionReference();
mTransferSize = mTransaction->GetTransferSize();
// at this point, we're done with the transaction
mTransactionTimings = mTransaction->Timings();
mTransaction = nullptr;

View File

@ -132,6 +132,8 @@ public:
NS_IMETHOD GetSecurityInfo(nsISupports **aSecurityInfo) override;
NS_IMETHOD AsyncOpen(nsIStreamListener *listener, nsISupports *aContext) override;
NS_IMETHOD AsyncOpen2(nsIStreamListener *aListener) override;
// nsIHttpChannel
NS_IMETHOD GetEncodedBodySize(uint64_t *aEncodedBodySize) override;
// nsIHttpChannelInternal
NS_IMETHOD SetupFallbackChannel(const char *aFallbackKey) override;
NS_IMETHOD ForceIntercepted(uint64_t aInterceptionID) override;
@ -530,7 +532,6 @@ private:
// If non-null, warnings should be reported to this object.
HttpChannelSecurityWarningReporter* mWarningReporter;
protected:
virtual void DoNotifyListenerCleanup() override;

View File

@ -96,6 +96,7 @@ nsHttpTransaction::nsHttpTransaction()
, mResponseHead(nullptr)
, mContentLength(-1)
, mContentRead(0)
, mTransferSize(0)
, mInvalidResponseBytesRead(0)
, mPushedStream(nullptr)
, mInitialRwin(0)
@ -773,6 +774,7 @@ nsHttpTransaction::WritePipeSegment(nsIOutputStream *stream,
MOZ_ASSERT(*countWritten > 0, "bad writer");
trans->CountRecvBytes(*countWritten);
trans->mReceivedData = true;
trans->mTransferSize += *countWritten;
// Let the transaction "play" with the buffer. It is free to modify
// the contents of the buffer and/or modify countWritten.

View File

@ -162,6 +162,8 @@ public:
mozilla::TimeStamp GetResponseStart();
mozilla::TimeStamp GetResponseEnd();
int64_t GetTransferSize() { return mTransferSize; }
private:
friend class DeleteHttpTransaction;
virtual ~nsHttpTransaction();
@ -242,6 +244,7 @@ private:
int64_t mContentLength; // equals -1 if unknown
int64_t mContentRead; // count of consumed content bytes
int64_t mTransferSize; // count of received bytes
// After a 304/204 or other "no-content" style response we will skip over
// up to MAX_INVALID_RESPONSE_BODY_SZ bytes when looking for the next

View File

@ -14,7 +14,7 @@ interface nsIHttpHeaderVisitor;
* the inspection of the resulting HTTP response status and headers when they
* become available.
*/
[builtinclass, scriptable, uuid(e90acf2d-eaf2-41d8-97b2-c8d99f6437a1)]
[builtinclass, scriptable, uuid(b2596105-3d0d-4e6a-824f-0539713bb879)]
interface nsIHttpChannel : nsIChannel
{
/**************************************************************************
@ -84,6 +84,31 @@ interface nsIHttpChannel : nsIChannel
*/
void setReferrerWithPolicy(in nsIURI referrer, in unsigned long referrerPolicy);
/**
* Returns the network protocol used to fetch the resource as identified
* by the ALPN Protocol ID.
*
* @throws NS_ERROR_NOT_AVAILABLE if called before the response
* has been received (before onStartRequest).
*/
readonly attribute ACString protocolVersion;
/**
* size consumed by the response header fields and the response payload body
*/
readonly attribute uint64_t transferSize;
/**
* The size of the message body received by the client,
* after removing any applied content-codings
*/
readonly attribute uint64_t decodedBodySize;
/**
* The size in octets of the payload body, prior to removing content-codings
*/
readonly attribute uint64_t encodedBodySize;
/**
* Get the value of a particular request header.
*

View File

@ -150,6 +150,24 @@ nsViewSourceChannel::GetName(nsACString &result)
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsViewSourceChannel::GetTransferSize(uint64_t *aTransferSize)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsViewSourceChannel::GetDecodedBodySize(uint64_t *aDecodedBodySize)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsViewSourceChannel::GetEncodedBodySize(uint64_t *aEncodedBodySize)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsViewSourceChannel::IsPending(bool *result)
{
@ -637,6 +655,12 @@ nsViewSourceChannel::SetBaseURI(nsIURI* aBaseURI)
return NS_OK;
}
NS_IMETHODIMP
nsViewSourceChannel::GetProtocolVersion(nsACString& aProtocolVersion)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
// nsIRequestObserver methods
NS_IMETHODIMP
nsViewSourceChannel::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)

View File

@ -4,6 +4,12 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
XPIDL_SOURCES += [
'nsICompressConvStats.idl'
]
XPIDL_MODULE = 'necko_http'
UNIFIED_SOURCES += [
'mozTXTToHTMLConv.cpp',
'nsDirIndex.cpp',

View File

@ -30,7 +30,8 @@ namespace net {
NS_IMPL_ISUPPORTS(nsHTTPCompressConv,
nsIStreamConverter,
nsIStreamListener,
nsIRequestObserver)
nsIRequestObserver,
nsICompressConvStats)
// nsFTPDirListingConv methods
nsHTTPCompressConv::nsHTTPCompressConv()
@ -46,6 +47,7 @@ nsHTTPCompressConv::nsHTTPCompressConv()
, hMode(0)
, mSkipCount(0)
, mFlags(0)
, mDecodedDataLength(0)
{
LOG(("nsHttpCompresssConv %p ctor\n", this));
if (NS_IsMainThread()) {
@ -74,6 +76,13 @@ nsHTTPCompressConv::~nsHTTPCompressConv()
}
}
NS_IMETHODIMP
nsHTTPCompressConv::GetDecodedDataLength(uint64_t *aDecodedDataLength)
{
*aDecodedDataLength = mDecodedDataLength;
return NS_OK;
}
NS_IMETHODIMP
nsHTTPCompressConv::AsyncConvertData(const char *aFromType,
const char *aToType,
@ -476,6 +485,7 @@ nsHTTPCompressConv::do_OnDataAvailable(nsIRequest* request,
// Make sure the stream no longer references |buffer| in case our listener
// is crazy enough to try to read from |mStream| after ODA.
mStream->ShareData("", 0);
mDecodedDataLength += count;
return rv;
}

View File

@ -8,6 +8,7 @@
#define __nsHTTPCompressConv__h__ 1
#include "nsIStreamConverter.h"
#include "nsICompressConvStats.h"
#include "nsCOMPtr.h"
#include "zlib.h"
@ -72,12 +73,16 @@ public:
uint64_t mSourceOffset;
};
class nsHTTPCompressConv : public nsIStreamConverter {
class nsHTTPCompressConv
: public nsIStreamConverter
, public nsICompressConvStats
{
public:
// nsISupports methods
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSICOMPRESSCONVSTATS
// nsIStreamConverter methods
NS_DECL_NSISTREAMCONVERTER
@ -119,6 +124,8 @@ private:
unsigned mLen, hMode, mSkipCount, mFlags;
uint32_t check_header (nsIInputStream *iStr, uint32_t streamLen, nsresult *rv);
uint32_t mDecodedDataLength;
};
} // namespace net

View File

@ -0,0 +1,17 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
/**
* nsICompressConvStats
*
* This interface allows for the observation of decoded resource sizes
*/
[builtinclass, scriptable, uuid(58172ad0-46a9-4893-8fde-cd909c10792a)]
interface nsICompressConvStats : nsISupports
{
readonly attribute uint64_t decodedDataLength;
};