bug 737470 patch 3 implement spdy v3 (pref off) r=honzab

This commit is contained in:
Patrick McManus 2012-05-25 17:43:10 -04:00
Родитель e68b6e9d07
Коммит cae1bafa38
5 изменённых файлов: 993 добавлений и 458 удалений

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -41,7 +41,7 @@
#define mozilla_net_SpdySession3_h
// SPDY as defined by
// http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft2
// http://dev.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3
#include "ASpdySession.h"
#include "nsClassHashtable.h"
@ -84,26 +84,13 @@ public:
PRUint32 RegisterStreamID(SpdyStream3 *);
const static PRUint8 kVersion = 3;
const static PRUint8 kFlag_Control = 0x80;
const static PRUint8 kFlag_Data_FIN = 0x01;
const static PRUint8 kFlag_Data_UNI = 0x02;
const static PRUint8 kFlag_Data_ZLIB = 0x02;
// The protocol document for v2 specifies that the
// highest value (3) is the highest priority, but in
// reality 0 is the highest priority.
//
// Draft 3 notes here https://sites.google.com/a/chromium.org/dev/spdy/spdy-protocol/
// are the best guide to the mistake. Also see
// GetLowestPriority() and GetHighestPriority() in spdy_framer.h of
// chromium source.
const static PRUint8 kPri00 = 0 << 6; // highest
const static PRUint8 kPri01 = 1 << 6;
const static PRUint8 kPri02 = 2 << 6;
const static PRUint8 kPri03 = 3 << 6; // lowest
enum
{
CONTROL_TYPE_FIRST = 0,
@ -111,12 +98,13 @@ public:
CONTROL_TYPE_SYN_REPLY = 2,
CONTROL_TYPE_RST_STREAM = 3,
CONTROL_TYPE_SETTINGS = 4,
CONTROL_TYPE_NOOP = 5,
CONTROL_TYPE_NOOP = 5, /* deprecated */
CONTROL_TYPE_PING = 6,
CONTROL_TYPE_GOAWAY = 7,
CONTROL_TYPE_HEADERS = 8,
CONTROL_TYPE_WINDOW_UPDATE = 9, /* no longer in v2 */
CONTROL_TYPE_LAST = 10
CONTROL_TYPE_WINDOW_UPDATE = 9,
CONTROL_TYPE_CREDENTIAL = 10,
CONTROL_TYPE_LAST = 11
};
enum rstReason
@ -128,7 +116,10 @@ public:
RST_CANCEL = 5,
RST_INTERNAL_ERROR = 6,
RST_FLOW_CONTROL_ERROR = 7,
RST_BAD_ASSOC_STREAM = 8
RST_STREAM_IN_USE = 8,
RST_STREAM_ALREADY_CLOSED = 9,
RST_INVALID_CREDENTIALS = 10,
RST_FRAME_TOO_LARGE = 11
};
enum
@ -139,7 +130,8 @@ public:
SETTINGS_TYPE_MAX_CONCURRENT = 4, // streams
SETTINGS_TYPE_CWND = 5, // packets
SETTINGS_TYPE_DOWNLOAD_RETRANS_RATE = 6, // percentage
SETTINGS_TYPE_INITIAL_WINDOW = 7 // bytes. Not used in v2.
SETTINGS_TYPE_INITIAL_WINDOW = 7, // bytes
SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE = 8
};
// This should be big enough to hold all of your control packets,
@ -161,6 +153,16 @@ public:
// 31 bit stream ID.
const static PRUint32 kDeadStreamID = 0xffffdead;
// until we have an API that can push back on receiving data (right now
// WriteSegments is obligated to accept data and buffer) there is no
// reason to throttle with the rwin other than in server push
// scenarios.
const static PRUint32 kInitialRwin = 256 * 1024 * 1024;
const static PRUint32 kMinimumToAck = 64 * 1024;
// The default peer rwin is 64KB unless updated by a settings frame
const static PRUint32 kDefaultServerRwin = 64 * 1024;
static nsresult HandleSynStream(SpdySession3 *);
static nsresult HandleSynReply(SpdySession3 *);
static nsresult HandleRstStream(SpdySession3 *);
@ -187,6 +189,8 @@ public:
// an overload of nsAHttpSegementReader
virtual nsresult CommitToSegmentSize(PRUint32 size);
PRUint32 GetServerInitialWindow() { return mServerInitialWindow; }
private:
enum stateType {
@ -194,25 +198,23 @@ private:
BUFFERING_CONTROL_FRAME,
PROCESSING_DATA_FRAME,
DISCARDING_DATA_FRAME,
PROCESSING_CONTROL_SYN_REPLY,
PROCESSING_COMPLETE_HEADERS,
PROCESSING_CONTROL_RST_STREAM
};
void DeterminePingThreshold();
nsresult HandleSynReplyForValidStream();
nsresult ResponseHeadersComplete();
PRUint32 GetWriteQueueSize();
void ChangeDownstreamState(enum stateType);
void ResetDownstreamState();
nsresult DownstreamUncompress(char *, PRUint32);
nsresult UncompressAndDiscard(PRUint32, PRUint32);
void zlibInit();
nsresult FindHeader(nsCString, nsDependentCSubstring &);
nsresult ConvertHeaders(nsDependentCSubstring &,
nsDependentCSubstring &);
void GeneratePing(PRUint32);
void ClearPing(bool);
void GenerateRstStream(PRUint32, PRUint32);
void GenerateGoAway();
void CleanupStream(SpdyStream3 *, nsresult, rstReason);
void GenerateSettings();
void SetWriteCallbacks();
void FlushOutputQueue();
@ -224,6 +226,8 @@ private:
bool VerifyStream(SpdyStream3 *, PRUint32);
void SetNeedsCleanup();
void UpdateLocalRwin(SpdyStream3 *stream, PRUint32 bytes);
// a wrapper for all calls to the nshttpconnection level segment writer. Used
// to track network I/O for timeout purposes
nsresult NetworkRead(nsAHttpSegmentWriter *, char *, PRUint32, PRUint32 *);
@ -232,6 +236,10 @@ private:
nsAutoPtr<SpdyStream3> &,
void *);
static PLDHashOperator UpdateServerRwinEnumerator(nsAHttpTransaction *,
nsAutoPtr<SpdyStream3> &,
void *);
// This is intended to be nsHttpConnectionMgr:nsHttpConnectionHandle taken
// from the first transaction on this session. That object contains the
// pointer to the real network-level nsHttpConnection object.
@ -252,28 +260,23 @@ private:
stateType mDownstreamState; /* in frame, between frames, etc.. */
// Maintain 5 indexes - one by stream ID, one by transaction ptr,
// Maintain 4 indexes - one by stream ID, one by transaction ptr,
// one list of streams ready to write, one list of streams that are queued
// due to max parallelism settings, and one list of streams
// that must be given priority to write for window updates. The objects
// due to max parallelism settings. The objects
// are not ref counted - they get destroyed
// by the nsClassHashtable implementation when they are removed from
// there.
// the transaction hash.
nsDataHashtable<nsUint32HashKey, SpdyStream3 *> mStreamIDHash;
nsClassHashtable<nsPtrHashKey<nsAHttpTransaction>,
SpdyStream3> mStreamTransactionHash;
nsDeque mReadyForWrite;
nsDeque mQueuedStreams;
// UrgentForWrite is meant to carry window updates. They were defined in
// the v2 spec but apparently never implemented so are now scheduled to
// be removed. But they will be reintroduced for v3, so we will leave
// this queue in place to ease that transition.
nsDeque mUrgentForWrite;
// Compression contexts for header transport using deflate.
// SPDY compresses only HTTP headers and does not reset zlib in between
// frames.
// frames. Even data that is not associated with a stream (e.g invalid
// stream ID) is passed through these contexts to keep the compression
// context correct.
z_stream mDownstreamZlib;
z_stream mUpstreamZlib;
@ -308,15 +311,8 @@ private:
// This reason code in the last processed RESET frame
PRUint32 mDownstreamRstReason;
// These are used for decompressing downstream spdy response headers
// This is done at the session level because sometimes the stream
// has already been canceled but the decompression still must happen
// to keep the zlib state correct for the next state of headers.
PRUint32 mDecompressBufferSize;
PRUint32 mDecompressBufferUsed;
nsAutoArrayPtr<char> mDecompressBuffer;
// for the conversion of downstream http headers into spdy formatted headers
// The data here does not persist between frames
nsCString mFlatHTTPResponseHeaders;
PRUint32 mFlatHTTPResponseHeadersOut;
@ -333,6 +329,11 @@ private:
// the session received a GoAway frame with a valid GoAwayID
bool mCleanShutdown;
// indicates PROCESSING_COMPLETE_HEADERS state was pushed onto the stack
// over an active PROCESSING_DATA_FRAME, which should be restored when
// the processed headers are written to the stream
bool mDataPending;
// If a GoAway message was received this is the ID of the last valid
// stream. 0 otherwise. (0 is never a valid stream id.)
PRUint32 mGoAwayID;
@ -350,6 +351,9 @@ private:
// The number of server initiated SYN-STREAMS, tracked for telemetry
PRUint32 mServerPushedResources;
// The server rwin for new streams as determined from a SETTINGS frame
PRUint32 mServerInitialWindow;
// This is a output queue of bytes ready to be written to the SSL stream.
// When that streams returns WOULD_BLOCK on direct write the bytes get
// coalesced together here. This results in larger writes to the SSL layer.

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

@ -295,7 +295,7 @@ SpdyStream2::ParseHttpRequestHeaders(const char *buf,
// Priority flags are the C0 mask of byte 16.
//
// The other 6 bits of 16 are unused. Spdy/3 will expand
// priority to 4 bits.
// priority to 3 bits.
//
// When Spdy/3 implements WINDOW_UPDATE the lowest priority
// streams over a threshold (32?) should be given tiny

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

@ -75,12 +75,19 @@ SpdyStream3::SpdyStream3(nsAHttpTransaction *httpTransaction,
mRecvdFin(0),
mFullyOpen(0),
mSentWaitingFor(0),
mReceivedData(0),
mTxInlineFrameSize(SpdySession3::kDefaultBufferSize),
mTxInlineFrameUsed(0),
mTxStreamFrameSize(0),
mZlib(compressionContext),
mDecompressBufferSize(SpdySession3::kDefaultBufferSize),
mDecompressBufferUsed(0),
mDecompressedBytes(0),
mRequestBodyLenRemaining(0),
mPriority(priority),
mLocalWindow(SpdySession3::kInitialRwin),
mLocalUnacked(0),
mBlockedOnRwin(false),
mTotalSent(0),
mTotalRead(0)
{
@ -88,7 +95,9 @@ SpdyStream3::SpdyStream3(nsAHttpTransaction *httpTransaction,
LOG3(("SpdyStream3::SpdyStream3 %p", this));
mRemoteWindow = spdySession->GetServerInitialWindow();
mTxInlineFrame = new char[mTxInlineFrameSize];
mDecompressBuffer = new char[mDecompressBufferSize];
}
SpdyStream3::~SpdyStream3()
@ -143,9 +152,12 @@ SpdyStream3::ReadSegments(nsAHttpSegmentReader *reader,
if (rv == NS_BASE_STREAM_WOULD_BLOCK && !mTxInlineFrameUsed)
mRequestBlockedOnRead = 1;
if (!mTxInlineFrameUsed && NS_SUCCEEDED(rv) && (!*countRead)) {
LOG3(("ReadSegments %p: Sending request data complete, mUpstreamState=%x",
this, mUpstreamState));
// If the sending flow control window is open (!mBlockedOnRwin) then
// continue sending the request
if (!mBlockedOnRwin &&
!mTxInlineFrameUsed && NS_SUCCEEDED(rv) && (!*countRead)) {
LOG3(("SpdyStream3::ReadSegments %p 0x%X: Sending request data complete, "
"mUpstreamState=%x",this, mStreamID, mUpstreamState));
if (mSentFinOnData) {
ChangeState(UPSTREAM_COMPLETE);
}
@ -156,7 +168,6 @@ SpdyStream3::ReadSegments(nsAHttpSegmentReader *reader,
rv = NS_BASE_STREAM_WOULD_BLOCK;
}
}
break;
case SENDING_SYN_STREAM:
@ -313,7 +324,7 @@ SpdyStream3::ParseHttpRequestHeaders(const char *buf,
// of SPDY headers.. writing to mTxInlineFrame{sz}
mTxInlineFrame[0] = SpdySession3::kFlag_Control;
mTxInlineFrame[1] = 2; /* version */
mTxInlineFrame[1] = SpdySession3::kVersion;
mTxInlineFrame[2] = 0;
mTxInlineFrame[3] = SpdySession3::CONTROL_TYPE_SYN_STREAM;
// 4 to 7 are length and flags, we'll fill that in later
@ -325,25 +336,32 @@ SpdyStream3::ParseHttpRequestHeaders(const char *buf,
// from the client in the http binding
memset (mTxInlineFrame + 12, 0, 4);
// Priority flags are the C0 mask of byte 16.
//
// The other 6 bits of 16 are unused. Spdy/3 will expand
// priority to 4 bits.
//
// When Spdy/3 implements WINDOW_UPDATE the lowest priority
// streams over a threshold (32?) should be given tiny
// receive windows, separate from their spdy priority
//
if (mPriority >= nsISupportsPriority::PRIORITY_LOW)
mTxInlineFrame[16] = SpdySession3::kPri03;
else if (mPriority >= nsISupportsPriority::PRIORITY_NORMAL)
mTxInlineFrame[16] = SpdySession3::kPri02;
else if (mPriority >= nsISupportsPriority::PRIORITY_HIGH)
mTxInlineFrame[16] = SpdySession3::kPri01;
else
mTxInlineFrame[16] = SpdySession3::kPri00;
// Priority flags are the E0 mask of byte 16.
// 0 is highest priority, 7 is lowest.
// The other 5 bits of byte 16 are unused.
if (mPriority >= nsISupportsPriority::PRIORITY_LOWEST)
mTxInlineFrame[16] = 7 << 5;
else if (mPriority <= nsISupportsPriority::PRIORITY_HIGHEST)
mTxInlineFrame[16] = 0 << 5;
else {
// The priority mapping relies on the unfiltered ranged to be
// between -20 .. +20
PR_STATIC_ASSERT(nsISupportsPriority::PRIORITY_LOWEST == 20);
PR_STATIC_ASSERT(nsISupportsPriority::PRIORITY_HIGHEST == -20);
mTxInlineFrame[17] = 0; /* unused */
// Add one to the priority so that values such as -10 and -11
// get different spdy priorities - this appears to be an important
// breaking line in the priorities content assigns to
// transactions.
PRUint8 calculatedPriority = 3 + ((mPriority + 1) / 5);
NS_ABORT_IF_FALSE (!(calculatedPriority & 0xf8),
"Calculated Priority Out Of Range");
mTxInlineFrame[16] = calculatedPriority << 5;
}
// The client cert "slot". Right now we don't send client certs
mTxInlineFrame[17] = 0;
const char *methodHeader = mTransaction->RequestHead()->Method().get();
@ -386,17 +404,16 @@ SpdyStream3::ParseHttpRequestHeaders(const char *buf,
// all header names are lower case in spdy
ToLowerCase(name);
if (name.Equals("method") ||
name.Equals("version") ||
name.Equals("scheme") ||
// exclusions.. mostly from 3.2.1
if (name.Equals("connection") ||
name.Equals("keep-alive") ||
name.Equals("host") ||
name.Equals("proxy-connection") ||
name.Equals("accept-encoding") ||
name.Equals("te") ||
name.Equals("connection") ||
name.Equals("proxy-connection") ||
name.Equals("url"))
name.Equals("transfer-encoding"))
continue;
nsCString *val = hdrHash.Get(name);
if (!val) {
val = new nsCString();
@ -427,20 +444,23 @@ SpdyStream3::ParseHttpRequestHeaders(const char *buf,
// headers at this same level so it is not necessary to do so here.
// The header block length
PRUint16 count = hdrHash.Count() + 4; /* method, scheme, url, version */
PRUint16 count = hdrHash.Count() + 5; /* method, path, version, host, scheme */
CompressToFrame(count);
// method, scheme, url, and version headers for request line
CompressToFrame(NS_LITERAL_CSTRING("method"));
// :method, :path, :version comprise a HTTP/1 request line, so send those first
// to make life easy for any gateways
CompressToFrame(NS_LITERAL_CSTRING(":method"));
CompressToFrame(methodHeader, strlen(methodHeader));
CompressToFrame(NS_LITERAL_CSTRING("scheme"));
CompressToFrame(NS_LITERAL_CSTRING("https"));
CompressToFrame(NS_LITERAL_CSTRING("url"));
CompressToFrame(NS_LITERAL_CSTRING(":path"));
CompressToFrame(mTransaction->RequestHead()->RequestURI());
CompressToFrame(NS_LITERAL_CSTRING("version"));
CompressToFrame(NS_LITERAL_CSTRING(":version"));
CompressToFrame(versionHeader);
CompressToFrame(NS_LITERAL_CSTRING(":host"));
CompressToFrame(hostHeader);
CompressToFrame(NS_LITERAL_CSTRING(":scheme"));
CompressToFrame(NS_LITERAL_CSTRING("https"));
hdrHash.Enumerate(hdrHashEnumerate, this);
CompressFlushFrame();
@ -678,26 +698,188 @@ SpdyStream3::CompressToFrame(const nsACString *str)
}
// Dictionary taken from
// http://dev.chromium.org/spdy/spdy-protocol/spdy-protocol-draft2
// Name/Value Header Block Format
// spec indicates that the compression dictionary is not null terminated
// but in reality it is. see:
// https://groups.google.com/forum/#!topic/spdy-dev/2pWxxOZEIcs
// http://dev.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3
const char *SpdyStream3::kDictionary =
"optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-"
"languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi"
"f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser"
"-agent10010120020120220320420520630030130230330430530630740040140240340440"
"5406407408409410411412413414415416417500501502503504505accept-rangesageeta"
"glocationproxy-authenticatepublicretry-afterservervarywarningwww-authentic"
"ateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertran"
"sfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locati"
"oncontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMo"
"ndayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSe"
"pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic"
"ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1"
".1statusversionurl";
const unsigned char SpdyStream3::kDictionary[] = {
0x00, 0x00, 0x00, 0x07, 0x6f, 0x70, 0x74, 0x69, // - - - - o p t i
0x6f, 0x6e, 0x73, 0x00, 0x00, 0x00, 0x04, 0x68, // o n s - - - - h
0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x70, // e a d - - - - p
0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x70, // o s t - - - - p
0x75, 0x74, 0x00, 0x00, 0x00, 0x06, 0x64, 0x65, // u t - - - - d e
0x6c, 0x65, 0x74, 0x65, 0x00, 0x00, 0x00, 0x05, // l e t e - - - -
0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00, // t r a c e - - -
0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00, // - a c c e p t -
0x00, 0x00, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, // - - - a c c e p
0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, // t - c h a r s e
0x74, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63, // t - - - - a c c
0x65, 0x70, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, // e p t - e n c o
0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x0f, // d i n g - - - -
0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c, // a c c e p t - l
0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00, // a n g u a g e -
0x00, 0x00, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70, // - - - a c c e p
0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, // t - r a n g e s
0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00, // - - - - a g e -
0x00, 0x00, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77, // - - - a l l o w
0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x68, // - - - - a u t h
0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, // o r i z a t i o
0x6e, 0x00, 0x00, 0x00, 0x0d, 0x63, 0x61, 0x63, // n - - - - c a c
0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, // h e - c o n t r
0x6f, 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f, // o l - - - - c o
0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, // n n e c t i o n
0x00, 0x00, 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, // - - - - c o n t
0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65, // e n t - b a s e
0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, 0x6e, 0x74, // - - - - c o n t
0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, // e n t - e n c o
0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, // d i n g - - - -
0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, // c o n t e n t -
0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, // l a n g u a g e
0x00, 0x00, 0x00, 0x0e, 0x63, 0x6f, 0x6e, 0x74, // - - - - c o n t
0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67, // e n t - l e n g
0x74, 0x68, 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, // t h - - - - c o
0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f, // n t e n t - l o
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, // c a t i o n - -
0x00, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, // - - c o n t e n
0x74, 0x2d, 0x6d, 0x64, 0x35, 0x00, 0x00, 0x00, // t - m d 5 - - -
0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, // - c o n t e n t
0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, // - r a n g e - -
0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, // - - c o n t e n
0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x00, 0x00, // t - t y p e - -
0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00, // - - d a t e - -
0x00, 0x04, 0x65, 0x74, 0x61, 0x67, 0x00, 0x00, // - - e t a g - -
0x00, 0x06, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, // - - e x p e c t
0x00, 0x00, 0x00, 0x07, 0x65, 0x78, 0x70, 0x69, // - - - - e x p i
0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x04, 0x66, // r e s - - - - f
0x72, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x68, // r o m - - - - h
0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x69, // o s t - - - - i
0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, // f - m a t c h -
0x00, 0x00, 0x11, 0x69, 0x66, 0x2d, 0x6d, 0x6f, // - - - i f - m o
0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73, // d i f i e d - s
0x69, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x00, 0x0d, // i n c e - - - -
0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d, // i f - n o n e -
0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00, // m a t c h - - -
0x08, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67, // - i f - r a n g
0x65, 0x00, 0x00, 0x00, 0x13, 0x69, 0x66, 0x2d, // e - - - - i f -
0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, // u n m o d i f i
0x65, 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65, // e d - s i n c e
0x00, 0x00, 0x00, 0x0d, 0x6c, 0x61, 0x73, 0x74, // - - - - l a s t
0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, // - m o d i f i e
0x64, 0x00, 0x00, 0x00, 0x08, 0x6c, 0x6f, 0x63, // d - - - - l o c
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, // a t i o n - - -
0x0c, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72, // - m a x - f o r
0x77, 0x61, 0x72, 0x64, 0x73, 0x00, 0x00, 0x00, // w a r d s - - -
0x06, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x00, // - p r a g m a -
0x00, 0x00, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79, // - - - p r o x y
0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, // - a u t h e n t
0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00, // i c a t e - - -
0x13, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61, // - p r o x y - a
0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, // u t h o r i z a
0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05, // t i o n - - - -
0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00, // r a n g e - - -
0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72, // - r e f e r e r
0x00, 0x00, 0x00, 0x0b, 0x72, 0x65, 0x74, 0x72, // - - - - r e t r
0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00, // y - a f t e r -
0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, // - - - s e r v e
0x72, 0x00, 0x00, 0x00, 0x02, 0x74, 0x65, 0x00, // r - - - - t e -
0x00, 0x00, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6c, // - - - t r a i l
0x65, 0x72, 0x00, 0x00, 0x00, 0x11, 0x74, 0x72, // e r - - - - t r
0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65, // a n s f e r - e
0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00, // n c o d i n g -
0x00, 0x00, 0x07, 0x75, 0x70, 0x67, 0x72, 0x61, // - - - u p g r a
0x64, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73, // d e - - - - u s
0x65, 0x72, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74, // e r - a g e n t
0x00, 0x00, 0x00, 0x04, 0x76, 0x61, 0x72, 0x79, // - - - - v a r y
0x00, 0x00, 0x00, 0x03, 0x76, 0x69, 0x61, 0x00, // - - - - v i a -
0x00, 0x00, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69, // - - - w a r n i
0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77, // n g - - - - w w
0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, // w - a u t h e n
0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, // t i c a t e - -
0x00, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, // - - m e t h o d
0x00, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00, // - - - - g e t -
0x00, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, // - - - s t a t u
0x73, 0x00, 0x00, 0x00, 0x06, 0x32, 0x30, 0x30, // s - - - - 2 0 0
0x20, 0x4f, 0x4b, 0x00, 0x00, 0x00, 0x07, 0x76, // - O K - - - - v
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00, // e r s i o n - -
0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, // - - H T T P - 1
0x2e, 0x31, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72, // - 1 - - - - u r
0x6c, 0x00, 0x00, 0x00, 0x06, 0x70, 0x75, 0x62, // l - - - - p u b
0x6c, 0x69, 0x63, 0x00, 0x00, 0x00, 0x0a, 0x73, // l i c - - - - s
0x65, 0x74, 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69, // e t - c o o k i
0x65, 0x00, 0x00, 0x00, 0x0a, 0x6b, 0x65, 0x65, // e - - - - k e e
0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x00, // p - a l i v e -
0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, // - - - o r i g i
0x6e, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x32, // n 1 0 0 1 0 1 2
0x30, 0x31, 0x32, 0x30, 0x32, 0x32, 0x30, 0x35, // 0 1 2 0 2 2 0 5
0x32, 0x30, 0x36, 0x33, 0x30, 0x30, 0x33, 0x30, // 2 0 6 3 0 0 3 0
0x32, 0x33, 0x30, 0x33, 0x33, 0x30, 0x34, 0x33, // 2 3 0 3 3 0 4 3
0x30, 0x35, 0x33, 0x30, 0x36, 0x33, 0x30, 0x37, // 0 5 3 0 6 3 0 7
0x34, 0x30, 0x32, 0x34, 0x30, 0x35, 0x34, 0x30, // 4 0 2 4 0 5 4 0
0x36, 0x34, 0x30, 0x37, 0x34, 0x30, 0x38, 0x34, // 6 4 0 7 4 0 8 4
0x30, 0x39, 0x34, 0x31, 0x30, 0x34, 0x31, 0x31, // 0 9 4 1 0 4 1 1
0x34, 0x31, 0x32, 0x34, 0x31, 0x33, 0x34, 0x31, // 4 1 2 4 1 3 4 1
0x34, 0x34, 0x31, 0x35, 0x34, 0x31, 0x36, 0x34, // 4 4 1 5 4 1 6 4
0x31, 0x37, 0x35, 0x30, 0x32, 0x35, 0x30, 0x34, // 1 7 5 0 2 5 0 4
0x35, 0x30, 0x35, 0x32, 0x30, 0x33, 0x20, 0x4e, // 5 0 5 2 0 3 - N
0x6f, 0x6e, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f, // o n - A u t h o
0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65, // r i t a t i v e
0x20, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, // - I n f o r m a
0x74, 0x69, 0x6f, 0x6e, 0x32, 0x30, 0x34, 0x20, // t i o n 2 0 4 -
0x4e, 0x6f, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65, // N o - C o n t e
0x6e, 0x74, 0x33, 0x30, 0x31, 0x20, 0x4d, 0x6f, // n t 3 0 1 - M o
0x76, 0x65, 0x64, 0x20, 0x50, 0x65, 0x72, 0x6d, // v e d - P e r m
0x61, 0x6e, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x34, // a n e n t l y 4
0x30, 0x30, 0x20, 0x42, 0x61, 0x64, 0x20, 0x52, // 0 0 - B a d - R
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x34, 0x30, // e q u e s t 4 0
0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, // 1 - U n a u t h
0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x34, 0x30, // o r i z e d 4 0
0x33, 0x20, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, // 3 - F o r b i d
0x64, 0x65, 0x6e, 0x34, 0x30, 0x34, 0x20, 0x4e, // d e n 4 0 4 - N
0x6f, 0x74, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, // o t - F o u n d
0x35, 0x30, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65, // 5 0 0 - I n t e
0x72, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72, // r n a l - S e r
0x76, 0x65, 0x72, 0x20, 0x45, 0x72, 0x72, 0x6f, // v e r - E r r o
0x72, 0x35, 0x30, 0x31, 0x20, 0x4e, 0x6f, 0x74, // r 5 0 1 - N o t
0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, // - I m p l e m e
0x6e, 0x74, 0x65, 0x64, 0x35, 0x30, 0x33, 0x20, // n t e d 5 0 3 -
0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, // S e r v i c e -
0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, // U n a v a i l a
0x62, 0x6c, 0x65, 0x4a, 0x61, 0x6e, 0x20, 0x46, // b l e J a n - F
0x65, 0x62, 0x20, 0x4d, 0x61, 0x72, 0x20, 0x41, // e b - M a r - A
0x70, 0x72, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x4a, // p r - M a y - J
0x75, 0x6e, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x41, // u n - J u l - A
0x75, 0x67, 0x20, 0x53, 0x65, 0x70, 0x74, 0x20, // u g - S e p t -
0x4f, 0x63, 0x74, 0x20, 0x4e, 0x6f, 0x76, 0x20, // O c t - N o v -
0x44, 0x65, 0x63, 0x20, 0x30, 0x30, 0x3a, 0x30, // D e c - 0 0 - 0
0x30, 0x3a, 0x30, 0x30, 0x20, 0x4d, 0x6f, 0x6e, // 0 - 0 0 - M o n
0x2c, 0x20, 0x54, 0x75, 0x65, 0x2c, 0x20, 0x57, // - - T u e - - W
0x65, 0x64, 0x2c, 0x20, 0x54, 0x68, 0x75, 0x2c, // e d - - T h u -
0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x53, 0x61, // - F r i - - S a
0x74, 0x2c, 0x20, 0x53, 0x75, 0x6e, 0x2c, 0x20, // t - - S u n - -
0x47, 0x4d, 0x54, 0x63, 0x68, 0x75, 0x6e, 0x6b, // G M T c h u n k
0x65, 0x64, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, // e d - t e x t -
0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x69, 0x6d, 0x61, // h t m l - i m a
0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x2c, 0x69, // g e - p n g - i
0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x67, // m a g e - j p g
0x2c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, // - i m a g e - g
0x69, 0x66, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, // i f - a p p l i
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, // c a t i o n - x
0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, // m l - a p p l i
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, // c a t i o n - x
0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, // h t m l - x m l
0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, // - t e x t - p l
0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74, // a i n - t e x t
0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72, // - j a v a s c r
0x69, 0x70, 0x74, 0x2c, 0x70, 0x75, 0x62, 0x6c, // i p t - p u b l
0x69, 0x63, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, // i c p r i v a t
0x65, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65, // e m a x - a g e
0x3d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x64, 0x65, // - g z i p - d e
0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64, // f l a t e - s d
0x63, 0x68, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, // c h c h a r s e
0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x63, // t - u t f - 8 c
0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x69, // h a r s e t - i
0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d, // s o - 8 8 5 9 -
0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x2c, 0x2a, // 1 - u t f - - -
0x2c, 0x65, 0x6e, 0x71, 0x3d, 0x30, 0x2e // - e n q - 0 -
};
// use for zlib data types
void *
@ -713,6 +895,239 @@ SpdyStream3::zlib_destructor(void *opaque, void *addr)
moz_free(addr);
}
nsresult
SpdyStream3::Uncompress(z_stream *context,
char *blockStart,
PRUint32 blockLen)
{
mDecompressedBytes += blockLen;
context->avail_in = blockLen;
context->next_in = reinterpret_cast<unsigned char *>(blockStart);
do {
context->next_out =
reinterpret_cast<unsigned char *>(mDecompressBuffer.get()) +
mDecompressBufferUsed;
context->avail_out = mDecompressBufferSize - mDecompressBufferUsed;
int zlib_rv = inflate(context, Z_NO_FLUSH);
if (zlib_rv == Z_NEED_DICT)
inflateSetDictionary(context, kDictionary, sizeof(kDictionary));
if (zlib_rv == Z_DATA_ERROR || zlib_rv == Z_MEM_ERROR)
return NS_ERROR_FAILURE;
// zlib's inflate() decreases context->avail_out by the amount it places
// in the output buffer
mDecompressBufferUsed += mDecompressBufferSize - mDecompressBufferUsed -
context->avail_out;
// When there is no more output room, but input still available then
// increase the output space
if (zlib_rv == Z_OK &&
!context->avail_out && context->avail_in) {
LOG3(("SpdyStream3::Uncompress %p Large Headers - so far %d",
this, mDecompressBufferSize));
SpdySession3::EnsureBuffer(mDecompressBuffer,
mDecompressBufferSize + 4096,
mDecompressBufferUsed,
mDecompressBufferSize);
}
}
while (context->avail_in);
return NS_OK;
}
nsresult
SpdyStream3::FindHeader(nsCString name,
nsDependentCSubstring &value)
{
const unsigned char *nvpair = reinterpret_cast<unsigned char *>
(mDecompressBuffer.get()) + 4;
const unsigned char *lastHeaderByte = reinterpret_cast<unsigned char *>
(mDecompressBuffer.get()) + mDecompressBufferUsed;
if (lastHeaderByte < nvpair)
return NS_ERROR_ILLEGAL_VALUE;
PRUint32 numPairs =
PR_ntohl(reinterpret_cast<PRUint32 *>(mDecompressBuffer.get())[0]);
for (PRUint32 index = 0; index < numPairs; ++index) {
if (lastHeaderByte < nvpair + 4)
return NS_ERROR_ILLEGAL_VALUE;
PRUint32 nameLen = (nvpair[0] << 24) + (nvpair[1] << 16) +
(nvpair[2] << 8) + nvpair[3];
if (lastHeaderByte < nvpair + 4 + nameLen)
return NS_ERROR_ILLEGAL_VALUE;
nsDependentCSubstring nameString =
Substring(reinterpret_cast<const char *>(nvpair) + 4,
reinterpret_cast<const char *>(nvpair) + 4 + nameLen);
if (lastHeaderByte < nvpair + 8 + nameLen)
return NS_ERROR_ILLEGAL_VALUE;
PRUint32 valueLen = (nvpair[4 + nameLen] << 24) + (nvpair[5 + nameLen] << 16) +
(nvpair[6 + nameLen] << 8) + nvpair[7 + nameLen];
if (lastHeaderByte < nvpair + 8 + nameLen + valueLen)
return NS_ERROR_ILLEGAL_VALUE;
if (nameString.Equals(name)) {
value.Assign(((char *)nvpair) + 8 + nameLen, valueLen);
return NS_OK;
}
nvpair += 8 + nameLen + valueLen;
}
return NS_ERROR_NOT_AVAILABLE;
}
// ConvertHeaders is used to convert the response headers
// in a syn_reply or in 0..N headers frames that follow it into
// HTTP/1 format
nsresult
SpdyStream3::ConvertHeaders(nsACString &aHeadersOut)
{
// :status and :version are required.
nsDependentCSubstring status, version;
nsresult rv = FindHeader(NS_LITERAL_CSTRING(":status"),
status);
if (NS_FAILED(rv))
return (rv == NS_ERROR_NOT_AVAILABLE) ? NS_ERROR_ILLEGAL_VALUE : rv;
rv = FindHeader(NS_LITERAL_CSTRING(":version"),
version);
if (NS_FAILED(rv))
return (rv == NS_ERROR_NOT_AVAILABLE) ? NS_ERROR_ILLEGAL_VALUE : rv;
if (mDecompressedBytes && mDecompressBufferUsed) {
Telemetry::Accumulate(Telemetry::SPDY_SYN_REPLY_SIZE, mDecompressedBytes);
PRUint32 ratio =
mDecompressedBytes * 100 / mDecompressBufferUsed;
Telemetry::Accumulate(Telemetry::SPDY_SYN_REPLY_RATIO, ratio);
}
aHeadersOut.Truncate();
aHeadersOut.SetCapacity(mDecompressBufferUsed + 64);
// Connection, Keep-Alive and chunked transfer encodings are to be
// removed.
// Content-Length is 'advisory'.. we will not strip it because it can
// create UI feedback.
aHeadersOut.Append(version);
aHeadersOut.Append(NS_LITERAL_CSTRING(" "));
aHeadersOut.Append(status);
aHeadersOut.Append(NS_LITERAL_CSTRING("\r\n"));
const unsigned char *nvpair = reinterpret_cast<unsigned char *>
(mDecompressBuffer.get()) + 4;
const unsigned char *lastHeaderByte = reinterpret_cast<unsigned char *>
(mDecompressBuffer.get()) + mDecompressBufferUsed;
if (lastHeaderByte < nvpair)
return NS_ERROR_ILLEGAL_VALUE;
PRUint32 numPairs =
PR_ntohl(reinterpret_cast<PRUint32 *>(mDecompressBuffer.get())[0]);
for (PRUint32 index = 0; index < numPairs; ++index) {
if (lastHeaderByte < nvpair + 4)
return NS_ERROR_ILLEGAL_VALUE;
PRUint32 nameLen = (nvpair[0] << 24) + (nvpair[1] << 16) +
(nvpair[2] << 8) + nvpair[3];
if (lastHeaderByte < nvpair + 4 + nameLen)
return NS_ERROR_ILLEGAL_VALUE;
nsDependentCSubstring nameString =
Substring(reinterpret_cast<const char *>(nvpair) + 4,
reinterpret_cast<const char *>(nvpair) + 4 + nameLen);
if (lastHeaderByte < nvpair + 8 + nameLen)
return NS_ERROR_ILLEGAL_VALUE;
// Look for illegal characters in the nameString.
// This includes upper case characters and nulls (as they will
// break the fixup-nulls-in-value-string algorithm)
// Look for upper case characters in the name. They are illegal.
for (char *cPtr = nameString.BeginWriting();
cPtr && cPtr < nameString.EndWriting();
++cPtr) {
if (*cPtr <= 'Z' && *cPtr >= 'A') {
nsCString toLog(nameString);
LOG3(("SpdyStream3::ConvertHeaders session=%p stream=%p "
"upper case response header found. [%s]\n",
mSession, this, toLog.get()));
return NS_ERROR_ILLEGAL_VALUE;
}
// check for null characters
if (*cPtr == '\0')
return NS_ERROR_ILLEGAL_VALUE;
}
// HTTP Chunked responses are not legal over spdy. We do not need
// to look for chunked specifically because it is the only HTTP
// allowed default encoding and we did not negotiate further encodings
// via TE
if (nameString.Equals(NS_LITERAL_CSTRING("transfer-encoding"))) {
LOG3(("SpdyStream3::ConvertHeaders session=%p stream=%p "
"transfer-encoding found. Chunked is invalid and no TE sent.",
mSession, this));
return NS_ERROR_ILLEGAL_VALUE;
}
PRUint32 valueLen =
(nvpair[4 + nameLen] << 24) + (nvpair[5 + nameLen] << 16) +
(nvpair[6 + nameLen] << 8) + nvpair[7 + nameLen];
if (lastHeaderByte < nvpair + 8 + nameLen + valueLen)
return NS_ERROR_ILLEGAL_VALUE;
if (!nameString.Equals(NS_LITERAL_CSTRING(":version")) &&
!nameString.Equals(NS_LITERAL_CSTRING(":status")) &&
!nameString.Equals(NS_LITERAL_CSTRING("connection")) &&
!nameString.Equals(NS_LITERAL_CSTRING("keep-alive"))) {
nsDependentCSubstring valueString =
Substring(reinterpret_cast<const char *>(nvpair) + 8 + nameLen,
reinterpret_cast<const char *>(nvpair) + 8 + nameLen +
valueLen);
aHeadersOut.Append(nameString);
aHeadersOut.Append(NS_LITERAL_CSTRING(": "));
// expand NULL bytes in the value string
for (char *cPtr = valueString.BeginWriting();
cPtr && cPtr < valueString.EndWriting();
++cPtr) {
if (*cPtr != 0) {
aHeadersOut.Append(*cPtr);
continue;
}
// NULLs are really "\r\nhdr: "
aHeadersOut.Append(NS_LITERAL_CSTRING("\r\n"));
aHeadersOut.Append(nameString);
aHeadersOut.Append(NS_LITERAL_CSTRING(": "));
}
aHeadersOut.Append(NS_LITERAL_CSTRING("\r\n"));
}
nvpair += 8 + nameLen + valueLen;
}
aHeadersOut.Append(NS_LITERAL_CSTRING("X-Firefox-Spdy: 3\r\n\r\n"));
LOG (("decoded response headers are:\n%s",
aHeadersOut.BeginReading()));
// The spdy formatted buffer isnt needed anymore - free it up
mDecompressBuffer = nsnull;
mDecompressBufferSize = 0;
mDecompressBufferUsed = 0;
return NS_OK;
}
void
SpdyStream3::ExecuteCompress(PRUint32 flushMode)
{
@ -739,15 +1154,14 @@ SpdyStream3::ExecuteCompress(PRUint32 flushMode)
}
void
SpdyStream3::CompressToFrame(PRUint16 data)
SpdyStream3::CompressToFrame(PRUint32 data)
{
// convert the data to network byte order and write that
// convert the data to 4 byte network byte order and write that
// to the compressed stream
data = PR_htons(data);
data = PR_htonl(data);
mZlib->next_in = reinterpret_cast<unsigned char *> (&data);
mZlib->avail_in = 2;
mZlib->avail_in = 4;
ExecuteCompress(Z_NO_FLUSH);
}
@ -755,19 +1169,14 @@ SpdyStream3::CompressToFrame(PRUint16 data)
void
SpdyStream3::CompressToFrame(const char *data, PRUint32 len)
{
// Format calls for a network ordered 16 bit length
// Format calls for a network ordered 32 bit length
// followed by the utf8 string
// for now, silently truncate headers greater than 64KB. Spdy/3 will
// fix this by making the len a 32 bit quantity
if (len > 0xffff)
len = 0xffff;
PRUint16 networkLen = PR_htons(len);
PRUint32 networkLen = PR_htonl(len);
// write out the length
mZlib->next_in = reinterpret_cast<unsigned char *> (&networkLen);
mZlib->avail_in = 2;
mZlib->avail_in = 4;
ExecuteCompress(Z_NO_FLUSH);
// write out the data
@ -854,7 +1263,24 @@ SpdyStream3::OnReadSegment(const char *buf,
break;
case GENERATING_REQUEST_BODY:
if (mRemoteWindow <= 0) {
*countRead = 0;
LOG3(("SpdyStream3 this=%p, id 0x%X request body suspended because "
"remote window is %d.\n", this, mStreamID, mRemoteWindow));
mBlockedOnRwin = true;
return NS_BASE_STREAM_WOULD_BLOCK;
}
mBlockedOnRwin = false;
dataLength = NS_MIN(count, mChunkSize);
if (dataLength > mRemoteWindow)
dataLength = mRemoteWindow;
LOG3(("SpdyStream3 this=%p id 0x%X remote window is %d. Chunk is %d\n",
this, mStreamID, mRemoteWindow, dataLength));
mRemoteWindow -= dataLength;
LOG3(("SpdyStream3 %p id %x request len remaining %d, "
"count avail %d, chunk used %d",
this, mStreamID, mRequestBodyLenRemaining, count, dataLength));

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

@ -83,15 +83,37 @@ public:
void SetRecvdFin(bool aStatus) { mRecvdFin = aStatus ? 1 : 0; }
bool RecvdFin() { return mRecvdFin; }
void SetRecvdData(bool aStatus) { mReceivedData = aStatus ? 1 : 0; }
bool RecvdData() { return mReceivedData; }
void UpdateTransportSendEvents(PRUint32 count);
void UpdateTransportReadEvents(PRUint32 count);
// The zlib header compression dictionary defined by SPDY,
// and hooks to the mozilla allocator for zlib to use.
static const char *kDictionary;
static const unsigned char kDictionary[1423];
static void *zlib_allocator(void *, uInt, uInt);
static void zlib_destructor(void *, void *);
nsresult Uncompress(z_stream *, char *, PRUint32);
nsresult ConvertHeaders(nsACString &);
void UpdateRemoteWindow(PRInt32 delta) { mRemoteWindow += delta; }
PRInt64 RemoteWindow() { return mRemoteWindow; }
void DecrementLocalWindow(PRUint32 delta) {
mLocalWindow -= delta;
mLocalUnacked += delta;
}
void IncrementLocalWindow(PRUint32 delta) {
mLocalWindow += delta;
mLocalUnacked -= delta;
}
PRUint64 LocalUnAcked() { return mLocalUnacked; }
bool BlockedOnRwin() { return mBlockedOnRwin; }
private:
// a SpdyStream3 object is only destroyed by being removed from the
@ -121,9 +143,10 @@ private:
void CompressToFrame(const nsACString &);
void CompressToFrame(const nsACString *);
void CompressToFrame(const char *, PRUint32);
void CompressToFrame(PRUint16);
void CompressToFrame(PRUint32);
void CompressFlushFrame();
void ExecuteCompress(PRUint32);
nsresult FindHeader(nsCString, nsDependentCSubstring &);
// Each stream goes from syn_stream to upstream_complete, perhaps
// looping on multiple instances of generating_request_body and
@ -175,6 +198,10 @@ private:
// Flag is set after the WAITING_FOR Transport event has been generated
PRUint32 mSentWaitingFor : 1;
// Flag is set after 1st DATA frame has been passed to stream, after
// which additional HEADERS data is invalid
PRUint32 mReceivedData : 1;
// The InlineFrame and associated data is used for composing control
// frames and data frame headers.
nsAutoArrayPtr<char> mTxInlineFrame;
@ -192,6 +219,12 @@ private:
z_stream *mZlib;
nsCString mFlatHttpRequestHeaders;
// These are used for decompressing downstream spdy response headers
PRUint32 mDecompressBufferSize;
PRUint32 mDecompressBufferUsed;
PRUint32 mDecompressedBytes;
nsAutoArrayPtr<char> mDecompressBuffer;
// Track the content-length of a request body so that we can
// place the fin flag on the last data packet instead of waiting
// for a stream closed indication. Relying on stream close results
@ -202,6 +235,27 @@ private:
// based on nsISupportsPriority definitions
PRInt32 mPriority;
// mLocalWindow, mRemoteWindow, and mLocalUnacked are for flow control.
// *window are signed because they race conditions in asynchronous SETTINGS
// messages can force them temporarily negative.
// LocalWindow is how much data the server will send without getting a
// window update
PRInt64 mLocalWindow;
// RemoteWindow is how much data the client is allowed to send without
// getting a window update
PRInt64 mRemoteWindow;
// LocalUnacked is the number of bytes received by the client but not
// yet reflected in a window update. Sending that update will increment
// LocalWindow
PRUint64 mLocalUnacked;
// True when sending is suspended becuase the remote flow control window is
// <= 0
bool mBlockedOnRwin;
// For Progress Events
PRUint64 mTotalSent;
PRUint64 mTotalRead;