Bug 1296280 (part 2) - Add pref for our SETTINGS_MAX_TABLE_SIZE. r?mcmanus
MozReview-Commit-ID: 44CYEvJOno0
--- a/netwerk/protocol/http/Http2Compression.cpp
+++ b/netwerk/protocol/http/Http2Compression.cpp
@@ -276,16 +276,17 @@ nvFIFO::operator[] (size_t index) const
}
return static_cast<nvPair *>(gStaticHeaders->ObjectAt(index));
}
Http2BaseCompressor::Http2BaseCompressor()
: mOutput(nullptr)
, mMaxBuffer(kDefaultMaxBuffer)
, mMaxBufferSetting(kDefaultMaxBuffer)
+ , mSetInitialMaxBufferSizeAllowed(true)
, mPeakSize(0)
, mPeakCount(0)
{
mDynamicReporter = new HpackDynamicTableReporter(this);
RegisterStrongMemoryReporter(mDynamicReporter);
}
Http2BaseCompressor::~Http2BaseCompressor()
@@ -379,19 +380,33 @@ Http2BaseCompressor::SetMaxBufferSizeInt
mHeaderTable.RemoveElement();
++removedCount;
}
mMaxBuffer = maxBufferSize;
}
nsresult
+Http2BaseCompressor::SetInitialMaxBufferSize(uint32_t maxBufferSize)
+{
+ MOZ_ASSERT(mSetInitialMaxBufferSizeAllowed);
+
+ if (mSetInitialMaxBufferSizeAllowed) {
+ mMaxBufferSetting = maxBufferSize;
+ return NS_OK;
+ }
+
+ return NS_ERROR_FAILURE;
+}
+
+nsresult
Http2Decompressor::DecodeHeaderBlock(const uint8_t *data, uint32_t datalen,
nsACString &output, bool isPush)
{
+ mSetInitialMaxBufferSizeAllowed = false;
mOffset = 0;
mData = data;
mDataLen = datalen;
mOutput = &output;
mOutput->Truncate();
mHeaderStatus.Truncate();
mHeaderHost.Truncate();
mHeaderScheme.Truncate();
@@ -1030,16 +1045,17 @@ Http2Decompressor::DoContextUpdate()
/////////////////////////////////////////////////////////////////
nsresult
Http2Compressor::EncodeHeaderBlock(const nsCString &nvInput,
const nsACString &method, const nsACString &path,
const nsACString &host, const nsACString &scheme,
bool connectForm, nsACString &output)
{
+ mSetInitialMaxBufferSizeAllowed = false;
mOutput = &output;
output.SetCapacity(1024);
output.Truncate();
mParsedContentLength = -1;
// first thing's first - context size updates (if necessary)
if (mBufferSizeChangeWaiting) {
if (mLowestBufferSizeWaiting < mMaxBufferSetting) {
--- a/netwerk/protocol/http/Http2Compression.h
+++ b/netwerk/protocol/http/Http2Compression.h
@@ -61,30 +61,32 @@ private:
class HpackDynamicTableReporter;
class Http2BaseCompressor
{
public:
Http2BaseCompressor();
virtual ~Http2BaseCompressor();
size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
+ nsresult SetInitialMaxBufferSize(uint32_t maxBufferSize);
protected:
const static uint32_t kDefaultMaxBuffer = 4096;
virtual void ClearHeaderTable();
virtual void MakeRoom(uint32_t amount, const char *direction);
virtual void DumpState();
virtual void SetMaxBufferSizeInternal(uint32_t maxBufferSize);
nsACString *mOutput;
nvFIFO mHeaderTable;
uint32_t mMaxBuffer;
uint32_t mMaxBufferSetting;
+ bool mSetInitialMaxBufferSizeAllowed;
uint32_t mPeakSize;
uint32_t mPeakCount;
Telemetry::ID mPeakSizeID;
Telemetry::ID mPeakCountID;
private:
RefPtr<HpackDynamicTableReporter> mDynamicReporter;
--- a/netwerk/protocol/http/Http2Session.cpp
+++ b/netwerk/protocol/http/Http2Session.cpp
@@ -827,20 +827,20 @@ Http2Session::GenerateGoAway(uint32_t aS
// these streams (3, 5, 7, 9, b) build a dependency tree that all other
// streams will be direct leaves of.
void
Http2Session::SendHello()
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
LOG3(("Http2Session::SendHello %p\n", this));
- // sized for magic + 4 settings and a session window update and 5 priority frames
+ // sized for magic + 5 settings and a session window update and 5 priority frames
// 24 magic, 33 for settings (9 header + 4 settings @6), 13 for window update,
// 5 priority frames at 14 (9 + 5) each
- static const uint32_t maxSettings = 4;
+ static const uint32_t maxSettings = 5;
static const uint32_t prioritySize = 5 * (kFrameHeaderBytes + 5);
static const uint32_t maxDataLen = 24 + kFrameHeaderBytes + maxSettings * 6 + 13 + prioritySize;
char *packet = EnsureOutputBuffer(maxDataLen);
memcpy(packet, kMagicHello, 24);
mOutputQueueUsed += 24;
LogIO(this, nullptr, "Magic Connection Header", packet, 24);
packet = mOutputQueueBuffer.get() + mOutputQueueUsed;
@@ -849,16 +849,24 @@ Http2Session::SendHello()
// frame header will be filled in after we know how long the frame is
uint8_t numberOfEntries = 0;
// entries need to be listed in order by ID
// 1st entry is bytes 9 to 14
// 2nd entry is bytes 15 to 20
// 3rd entry is bytes 21 to 26
// 4th entry is bytes 27 to 32
+ // 5th entry is bytes 33 to 38
+
+ // Let the other endpoint know about our default HPACK decompress table size
+ uint32_t maxHpackBufferSize = gHttpHandler->DefaultHpackBuffer();
+ mDecompressor.SetInitialMaxBufferSize(maxHpackBufferSize);
+ NetworkEndian::writeUint16(packet + kFrameHeaderBytes + (6 * numberOfEntries), SETTINGS_TYPE_HEADER_TABLE_SIZE);
+ NetworkEndian::writeUint32(packet + kFrameHeaderBytes + (6 * numberOfEntries) + 2, maxHpackBufferSize);
+ numberOfEntries++;
if (!gHttpHandler->AllowPush()) {
// If we don't support push then set MAX_CONCURRENT to 0 and also
// set ENABLE_PUSH to 0
NetworkEndian::writeUint16(packet + kFrameHeaderBytes + (6 * numberOfEntries), SETTINGS_TYPE_ENABLE_PUSH);
// The value portion of the setting pair is already initialized to 0
numberOfEntries++;
--- a/netwerk/protocol/http/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/nsHttpHandler.cpp
@@ -234,16 +234,17 @@ nsHttpHandler::nsHttpHandler()
, mCriticalRequestPrioritization(true)
, mTCPKeepaliveShortLivedEnabled(false)
, mTCPKeepaliveShortLivedTimeS(60)
, mTCPKeepaliveShortLivedIdleTimeS(10)
, mTCPKeepaliveLongLivedEnabled(false)
, mTCPKeepaliveLongLivedIdleTimeS(600)
, mEnforceH1Framing(FRAMECHECK_BARELY)
, mKeepEmptyResponseHeadersAsEmtpyString(false)
+ , mDefaultHpackBuffer(4096)
{
LOG(("Creating nsHttpHandler [this=%p].\n", this));
MOZ_ASSERT(!gHttpHandler, "HTTP handler already created!");
gHttpHandler = this;
}
nsHttpHandler::~nsHttpHandler()
@@ -1688,16 +1689,23 @@ nsHttpHandler::PrefsChanged(nsIPrefBranc
if (PREF_CHANGED(HTTP_PREF("keep_empty_response_headers_as_empty_string"))) {
rv = prefs->GetBoolPref(HTTP_PREF("keep_empty_response_headers_as_empty_string"),
&cVar);
if (NS_SUCCEEDED(rv)) {
mKeepEmptyResponseHeadersAsEmtpyString = cVar;
}
}
+ if (PREF_CHANGED(HTTP_PREF("spdy.hpack-default-buffer"))) {
+ rv = prefs->GetIntPref(HTTP_PREF("spdy.default-hpack-buffer"), &val);
+ if (NS_SUCCEEDED(rv)) {
+ mDefaultHpackBuffer = val;
+ }
+ }
+
// Enable HTTP response timeout if TCP Keepalives are disabled.
mResponseTimeoutEnabled = !mTCPKeepaliveShortLivedEnabled &&
!mTCPKeepaliveLongLivedEnabled;
#undef PREF_CHANGED
#undef MULTI_PREF_CHANGED
}
--- a/netwerk/protocol/http/nsHttpHandler.h
+++ b/netwerk/protocol/http/nsHttpHandler.h
@@ -363,16 +363,21 @@ public:
void ShutdownConnectionManager();
bool KeepEmptyResponseHeadersAsEmtpyString() const
{
return mKeepEmptyResponseHeadersAsEmtpyString;
}
+ uint32_t DefaultHpackBuffer() const
+ {
+ return mDefaultHpackBuffer;
+ }
+
private:
virtual ~nsHttpHandler();
//
// Useragent/prefs helper methods
//
void BuildUserAgent();
void InitUserAgentComponents();
@@ -582,16 +587,19 @@ private:
// If it is set to false, headers with empty value will not appear in the
// header array - behavior as it used to be. If it is true: empty headers
// coming from the network will exits in header array as empty string.
// Call SetHeader with an empty value will still delete the header.
// (Bug 6699259)
bool mKeepEmptyResponseHeadersAsEmtpyString;
+ // The default size (in bytes) of the HPACK decompressor table.
+ uint32_t mDefaultHpackBuffer;
+
private:
// For Rate Pacing Certain Network Events. Only assign this pointer on
// socket thread.
void MakeNewRequestTokenBucket();
RefPtr<EventTokenBucket> mRequestTokenBucket;
public:
// Socket thread only