зеркало из https://github.com/mozilla/gecko-dev.git
Backout SPDY to keep us under the MSVC virtual address space limit during win PGO builds (bug 709193)
Backs out 952d14a9e508 (bug 707173), c170c678c9ac (bug 708305), 0a5f66d5d8e4 (bug 707662), 3204b70435fe (bug 706236) and the main landing range 48807fde0339:0bd45ead1676 (bug 528288).
This commit is contained in:
Родитель
3b340fd477
Коммит
8d3d1667ec
|
@ -791,13 +791,6 @@ pref("network.http.connection-retry-timeout", 250);
|
|||
// IPv6 connectivity.
|
||||
pref("network.http.fast-fallback-to-IPv4", true);
|
||||
|
||||
// Try and use SPDY when using SSL
|
||||
pref("network.http.spdy.enabled", false);
|
||||
pref("network.http.spdy.chunk-size", 4096);
|
||||
pref("network.http.spdy.timeout", 180);
|
||||
pref("network.http.spdy.coalesce-hostnames", true);
|
||||
pref("network.http.spdy.use-alternate-protocol", true);
|
||||
|
||||
// default values for FTP
|
||||
// in a DSCP environment this should be 40 (0x28, or AF11), per RFC-4594,
|
||||
// Section 4.8 "High-Throughput Data Service Class", and 80 (0x50, or AF22)
|
||||
|
|
|
@ -552,8 +552,7 @@ nsSocketOutputStream::Write(const char *buf, PRUint32 count, PRUint32 *countWrit
|
|||
|
||||
*countWritten = 0;
|
||||
|
||||
// A write of 0 bytes can be used to force the initial SSL handshake.
|
||||
if (count == 0 && mByteCount)
|
||||
if (count == 0)
|
||||
return NS_OK;
|
||||
|
||||
PRFileDesc *fd;
|
||||
|
|
|
@ -80,7 +80,6 @@ HttpBaseChannel::HttpBaseChannel()
|
|||
, mChannelIsForDownload(false)
|
||||
, mTracingEnabled(true)
|
||||
, mTimingEnabled(false)
|
||||
, mAllowSpdy(true)
|
||||
, mSuspendCount(0)
|
||||
, mRedirectedCachekeys(nsnull)
|
||||
{
|
||||
|
@ -1311,22 +1310,6 @@ HttpBaseChannel::HTTPUpgrade(const nsACString &aProtocolName,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HttpBaseChannel::GetAllowSpdy(bool *aAllowSpdy)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aAllowSpdy);
|
||||
|
||||
*aAllowSpdy = mAllowSpdy;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HttpBaseChannel::SetAllowSpdy(bool aAllowSpdy)
|
||||
{
|
||||
mAllowSpdy = aAllowSpdy;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// HttpBaseChannel::nsISupportsPriority
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -1636,8 +1619,6 @@ HttpBaseChannel::SetupReplacementChannel(nsIURI *newURI,
|
|||
if (httpInternal) {
|
||||
// convey the mForceAllowThirdPartyCookie flag
|
||||
httpInternal->SetForceAllowThirdPartyCookie(mForceAllowThirdPartyCookie);
|
||||
// convey the spdy flag
|
||||
httpInternal->SetAllowSpdy(mAllowSpdy);
|
||||
|
||||
// update the DocumentURI indicator since we are being redirected.
|
||||
// if this was a top-level document channel, then the new channel
|
||||
|
|
|
@ -167,9 +167,6 @@ public:
|
|||
NS_IMETHOD GetLocalPort(PRInt32* port);
|
||||
NS_IMETHOD GetRemoteAddress(nsACString& addr);
|
||||
NS_IMETHOD GetRemotePort(PRInt32* port);
|
||||
NS_IMETHOD GetAllowSpdy(bool *aAllowSpdy);
|
||||
NS_IMETHOD SetAllowSpdy(bool aAllowSpdy);
|
||||
|
||||
inline void CleanRedirectCacheChainIfNecessary()
|
||||
{
|
||||
if (mRedirectedCachekeys) {
|
||||
|
@ -298,7 +295,6 @@ protected:
|
|||
PRUint32 mTracingEnabled : 1;
|
||||
// True if timing collection is enabled
|
||||
PRUint32 mTimingEnabled : 1;
|
||||
PRUint32 mAllowSpdy : 1;
|
||||
|
||||
// Current suspension depth for this channel object
|
||||
PRUint32 mSuspendCount;
|
||||
|
|
|
@ -1079,7 +1079,7 @@ HttpChannelChild::AsyncOpen(nsIStreamListener *listener, nsISupports *aContext)
|
|||
mPriority, mRedirectionLimit, mAllowPipelining,
|
||||
mForceAllowThirdPartyCookie, mSendResumeAt,
|
||||
mStartPos, mEntityID, mChooseApplicationCache,
|
||||
appCacheClientId, mAllowSpdy);
|
||||
appCacheClientId);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -143,8 +143,7 @@ HttpChannelParent::RecvAsyncOpen(const IPC::URI& aURI,
|
|||
const PRUint64& startPos,
|
||||
const nsCString& entityID,
|
||||
const bool& chooseApplicationCache,
|
||||
const nsCString& appCacheClientID,
|
||||
const bool& allowSpdy)
|
||||
const nsCString& appCacheClientID)
|
||||
{
|
||||
nsCOMPtr<nsIURI> uri(aURI);
|
||||
nsCOMPtr<nsIURI> originalUri(aOriginalURI);
|
||||
|
@ -204,7 +203,6 @@ HttpChannelParent::RecvAsyncOpen(const IPC::URI& aURI,
|
|||
httpChan->SetRedirectionLimit(redirectionLimit);
|
||||
httpChan->SetAllowPipelining(allowPipelining);
|
||||
httpChan->SetForceAllowThirdPartyCookie(forceAllowThirdPartyCookie);
|
||||
httpChan->SetAllowSpdy(allowSpdy);
|
||||
|
||||
nsCOMPtr<nsIApplicationCacheChannel> appCacheChan =
|
||||
do_QueryInterface(mChannel);
|
||||
|
|
|
@ -97,8 +97,7 @@ protected:
|
|||
const PRUint64& startPos,
|
||||
const nsCString& entityID,
|
||||
const bool& chooseApplicationCache,
|
||||
const nsCString& appCacheClientID,
|
||||
const bool& allowSpdy);
|
||||
const nsCString& appCacheClientID);
|
||||
|
||||
virtual bool RecvConnectChannel(const PRUint32& channelId);
|
||||
virtual bool RecvSetPriority(const PRUint16& priority);
|
||||
|
|
|
@ -110,8 +110,6 @@ CPPSRCS = \
|
|||
HttpChannelParent.cpp \
|
||||
HttpChannelChild.cpp \
|
||||
HttpChannelParentListener.cpp \
|
||||
SpdySession.cpp \
|
||||
SpdyStream.cpp \
|
||||
$(NULL)
|
||||
|
||||
LOCAL_INCLUDES = \
|
||||
|
|
|
@ -81,8 +81,7 @@ parent:
|
|||
PRUint64 startPos,
|
||||
nsCString entityID,
|
||||
bool chooseApplicationCache,
|
||||
nsCString appCacheClientID,
|
||||
bool allowSpdy);
|
||||
nsCString appCacheClientID);
|
||||
|
||||
// Used to connect redirected-to channel on the parent with redirected-to
|
||||
// channel on the child.
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,322 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Patrick McManus <mcmanus@ducksong.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef mozilla_net_SpdySession_h
|
||||
#define mozilla_net_SpdySession_h
|
||||
|
||||
// SPDY as defined by
|
||||
// http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft2
|
||||
|
||||
#include "nsAHttpTransaction.h"
|
||||
#include "nsAHttpConnection.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsDeque.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "zlib.h"
|
||||
|
||||
class nsHttpConnection;
|
||||
class nsISocketTransport;
|
||||
|
||||
namespace mozilla { namespace net {
|
||||
|
||||
class SpdyStream;
|
||||
|
||||
class SpdySession : public nsAHttpTransaction
|
||||
, public nsAHttpConnection
|
||||
, public nsAHttpSegmentReader
|
||||
, public nsAHttpSegmentWriter
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSAHTTPTRANSACTION
|
||||
NS_DECL_NSAHTTPCONNECTION
|
||||
NS_DECL_NSAHTTPSEGMENTREADER
|
||||
NS_DECL_NSAHTTPSEGMENTWRITER
|
||||
|
||||
SpdySession(nsAHttpTransaction *, nsISocketTransport *, PRInt32);
|
||||
~SpdySession();
|
||||
|
||||
bool AddStream(nsAHttpTransaction *, PRInt32);
|
||||
bool CanReuse() { return !mShouldGoAway && !mClosed; }
|
||||
void DontReuse();
|
||||
bool RoomForMoreStreams();
|
||||
PRUint32 RegisterStreamID(SpdyStream *);
|
||||
|
||||
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;
|
||||
|
||||
const static PRUint8 kPri00 = 0x00;
|
||||
const static PRUint8 kPri01 = 0x40;
|
||||
const static PRUint8 kPri02 = 0x80;
|
||||
const static PRUint8 kPri03 = 0xC0;
|
||||
|
||||
enum
|
||||
{
|
||||
CONTROL_TYPE_FIRST = 0,
|
||||
CONTROL_TYPE_SYN_STREAM = 1,
|
||||
CONTROL_TYPE_SYN_REPLY = 2,
|
||||
CONTROL_TYPE_RST_STREAM = 3,
|
||||
CONTROL_TYPE_SETTINGS = 4,
|
||||
CONTROL_TYPE_NOOP = 5,
|
||||
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
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
RST_PROTOCOL_ERROR = 1,
|
||||
RST_INVALID_STREAM = 2,
|
||||
RST_REFUSED_STREAM = 3,
|
||||
RST_UNSUPPORTED_VERSION = 4,
|
||||
RST_CANCEL = 5,
|
||||
RST_INTERNAL_ERROR = 6,
|
||||
RST_FLOW_CONTROL_ERROR = 7,
|
||||
RST_BAD_ASSOC_STREAM = 8
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SETTINGS_TYPE_UPLOAD_BW = 1, // kb/s
|
||||
SETTINGS_TYPE_DOWNLOAD_BW = 2, // kb/s
|
||||
SETTINGS_TYPE_RTT = 3, // ms
|
||||
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.
|
||||
};
|
||||
|
||||
// This should be big enough to hold all of your control packets,
|
||||
// but if it needs to grow for huge headers it can do so dynamically.
|
||||
// About 1% of requests to SPDY google services seem to be > 1000
|
||||
// with all less than 2000.
|
||||
const static PRUint32 kDefaultBufferSize = 2000;
|
||||
|
||||
const static PRUint32 kDefaultQueueSize = 16000;
|
||||
const static PRUint32 kQueueTailRoom = 4000;
|
||||
const static PRUint32 kSendingChunkSize = 4000;
|
||||
const static PRUint32 kDefaultMaxConcurrent = 100;
|
||||
const static PRUint32 kMaxStreamID = 0x7800000;
|
||||
|
||||
static nsresult HandleSynStream(SpdySession *);
|
||||
static nsresult HandleSynReply(SpdySession *);
|
||||
static nsresult HandleRstStream(SpdySession *);
|
||||
static nsresult HandleSettings(SpdySession *);
|
||||
static nsresult HandleNoop(SpdySession *);
|
||||
static nsresult HandlePing(SpdySession *);
|
||||
static nsresult HandleGoAway(SpdySession *);
|
||||
static nsresult HandleHeaders(SpdySession *);
|
||||
static nsresult HandleWindowUpdate(SpdySession *);
|
||||
|
||||
static void EnsureBuffer(nsAutoArrayPtr<char> &,
|
||||
PRUint32, PRUint32, PRUint32 &);
|
||||
|
||||
// For writing the SPDY data stream to LOG4
|
||||
static void LogIO(SpdySession *, SpdyStream *, const char *,
|
||||
const char *, PRUint32);
|
||||
|
||||
private:
|
||||
|
||||
enum stateType {
|
||||
BUFFERING_FRAME_HEADER,
|
||||
BUFFERING_CONTROL_FRAME,
|
||||
PROCESSING_DATA_FRAME,
|
||||
DISCARD_DATA_FRAME,
|
||||
PROCESSING_CONTROL_SYN_REPLY,
|
||||
PROCESSING_CONTROL_RST_STREAM
|
||||
};
|
||||
|
||||
PRUint32 WriteQueueSize();
|
||||
void ChangeDownstreamState(enum stateType);
|
||||
nsresult DownstreamUncompress(char *, PRUint32);
|
||||
void zlibInit();
|
||||
nsresult FindHeader(nsCString, nsDependentCSubstring &);
|
||||
nsresult ConvertHeaders(nsDependentCSubstring &,
|
||||
nsDependentCSubstring &);
|
||||
void GeneratePing(PRUint32);
|
||||
void GenerateRstStream(PRUint32, PRUint32);
|
||||
void GenerateGoAway();
|
||||
void CleanupStream(SpdyStream *, nsresult);
|
||||
|
||||
void SetWriteCallbacks(nsAHttpTransaction *);
|
||||
void FlushOutputQueue();
|
||||
|
||||
bool RoomForMoreConcurrent();
|
||||
void ActivateStream(SpdyStream *);
|
||||
void ProcessPending();
|
||||
|
||||
static PLDHashOperator Shutdown(nsAHttpTransaction *,
|
||||
nsAutoPtr<SpdyStream> &,
|
||||
void *);
|
||||
|
||||
// This is intended to be nsHttpConnectionMgr:nsHttpConnectionHandle taken
|
||||
// from the first transcation on this session. That object contains the
|
||||
// pointer to the real network-level nsHttpConnection object.
|
||||
nsRefPtr<nsAHttpConnection> mConnection;
|
||||
|
||||
// The underlying socket transport object is needed to propogate some events
|
||||
nsISocketTransport *mSocketTransport;
|
||||
|
||||
// These are temporary state variables to hold the argument to
|
||||
// Read/WriteSegments so it can be accessed by On(read/write)segment
|
||||
// further up the stack.
|
||||
nsAHttpSegmentReader *mSegmentReader;
|
||||
nsAHttpSegmentWriter *mSegmentWriter;
|
||||
|
||||
PRUint32 mSendingChunkSize; /* the transmisison chunk size */
|
||||
PRUint32 mNextStreamID; /* 24 bits */
|
||||
PRUint32 mConcurrentHighWater; /* max parallelism on session */
|
||||
|
||||
stateType mDownstreamState; /* in frame, between frames, etc.. */
|
||||
|
||||
// Maintain 5 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
|
||||
// are not ref counted - they get destryoed
|
||||
// by the nsClassHashtable implementation when they are removed from
|
||||
// there.
|
||||
nsDataHashtable<nsUint32HashKey, SpdyStream *> mStreamIDHash;
|
||||
nsClassHashtable<nsPtrHashKey<nsAHttpTransaction>,
|
||||
SpdyStream> 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;
|
||||
|
||||
// If we block while wrting out a frame then this points to the stream
|
||||
// that was blocked. When writing again that stream must be the first
|
||||
// one to write. It is null if there is not a partial frame.
|
||||
SpdyStream *mPartialFrame;
|
||||
|
||||
// Compression contexts for header transport using deflate.
|
||||
// SPDY compresses only HTTP headers and does not reset zlib in between
|
||||
// frames.
|
||||
z_stream mDownstreamZlib;
|
||||
z_stream mUpstreamZlib;
|
||||
|
||||
// mFrameBuffer is used to store received control packets and the 8 bytes
|
||||
// of header on data packets
|
||||
PRUint32 mFrameBufferSize;
|
||||
PRUint32 mFrameBufferUsed;
|
||||
nsAutoArrayPtr<char> mFrameBuffer;
|
||||
|
||||
// mFrameDataSize/Read are used for tracking the amount of data consumed
|
||||
// in a data frame. the data itself is not buffered in spdy
|
||||
// The frame size is mFrameDataSize + the constant 8 byte header
|
||||
PRUint32 mFrameDataSize;
|
||||
PRUint32 mFrameDataRead;
|
||||
bool mFrameDataLast; // This frame was marked FIN
|
||||
|
||||
// When a frame has been received that is addressed to a particular stream
|
||||
// (e.g. a data frame after the stream-id has been decoded), this points
|
||||
// to the stream.
|
||||
SpdyStream *mFrameDataStream;
|
||||
|
||||
// A state variable to cleanup a closed stream after the stack has unwound.
|
||||
SpdyStream *mNeedsCleanup;
|
||||
|
||||
// The CONTROL_TYPE value for a control frame
|
||||
PRUint32 mFrameControlType;
|
||||
|
||||
// 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
|
||||
nsCString mFlatHTTPResponseHeaders;
|
||||
PRUint32 mFlatHTTPResponseHeadersOut;
|
||||
|
||||
// when set, the session will go away when it reaches 0 streams
|
||||
bool mShouldGoAway;
|
||||
|
||||
// the session has received a nsAHttpTransaction::Close() call
|
||||
bool mClosed;
|
||||
|
||||
// the session received a GoAway frame with a valid GoAwayID
|
||||
bool mCleanShutdown;
|
||||
|
||||
// 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;
|
||||
|
||||
// The limit on number of concurrent streams for this session. Normally it
|
||||
// is basically unlimited, but the SETTINGS control message from the
|
||||
// server might bring it down.
|
||||
PRUint32 mMaxConcurrent;
|
||||
|
||||
// The actual number of concurrent streams at this moment. Generally below
|
||||
// mMaxConcurrent, but the max can be lowered in real time to a value
|
||||
// below the current value
|
||||
PRUint32 mConcurrent;
|
||||
|
||||
// The number of server initiated SYN-STREAMS, tracked for telemetry
|
||||
PRUint32 mServerPushedResources;
|
||||
|
||||
// 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.
|
||||
// The buffer is not dynamically grown to accomodate stream writes, but
|
||||
// does expand to accept infallible session wide frames like GoAway and RST.
|
||||
PRUint32 mOutputQueueSize;
|
||||
PRUint32 mOutputQueueUsed;
|
||||
PRUint32 mOutputQueueSent;
|
||||
nsAutoArrayPtr<char> mOutputQueueBuffer;
|
||||
};
|
||||
|
||||
}} // namespace mozilla::net
|
||||
|
||||
#endif // mozilla_net_SpdySession_h
|
|
@ -1,849 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et tw=80 : */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Patrick McManus <mcmanus@ducksong.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsHttp.h"
|
||||
#include "SpdySession.h"
|
||||
#include "SpdyStream.h"
|
||||
#include "nsAlgorithm.h"
|
||||
#include "prnetdb.h"
|
||||
#include "nsHttpRequestHead.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "nsISocketTransport.h"
|
||||
#include "nsISupportsPriority.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
// defined by the socket transport service while active
|
||||
extern PRThread *gSocketThread;
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
SpdyStream::SpdyStream(nsAHttpTransaction *httpTransaction,
|
||||
SpdySession *spdySession,
|
||||
nsISocketTransport *socketTransport,
|
||||
PRUint32 chunkSize,
|
||||
z_stream *compressionContext,
|
||||
PRInt32 priority)
|
||||
: mUpstreamState(GENERATING_SYN_STREAM),
|
||||
mTransaction(httpTransaction),
|
||||
mSession(spdySession),
|
||||
mSocketTransport(socketTransport),
|
||||
mSegmentReader(nsnull),
|
||||
mSegmentWriter(nsnull),
|
||||
mStreamID(0),
|
||||
mChunkSize(chunkSize),
|
||||
mSynFrameComplete(0),
|
||||
mBlockedOnWrite(0),
|
||||
mRequestBlockedOnRead(0),
|
||||
mSentFinOnData(0),
|
||||
mRecvdFin(0),
|
||||
mFullyOpen(0),
|
||||
mTxInlineFrameAllocation(SpdySession::kDefaultBufferSize),
|
||||
mTxInlineFrameSize(0),
|
||||
mTxInlineFrameSent(0),
|
||||
mTxStreamFrameSize(0),
|
||||
mTxStreamFrameSent(0),
|
||||
mZlib(compressionContext),
|
||||
mRequestBodyLen(0),
|
||||
mPriority(priority)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
|
||||
LOG3(("SpdyStream::SpdyStream %p", this));
|
||||
|
||||
mTxInlineFrame = new char[mTxInlineFrameAllocation];
|
||||
}
|
||||
|
||||
SpdyStream::~SpdyStream()
|
||||
{
|
||||
}
|
||||
|
||||
// ReadSegments() is used to write data down the socket. Generally, HTTP
|
||||
// request data is pulled from the approriate transaction and
|
||||
// converted to SPDY data. Sometimes control data like a window-update is
|
||||
// generated instead.
|
||||
|
||||
nsresult
|
||||
SpdyStream::ReadSegments(nsAHttpSegmentReader *reader,
|
||||
PRUint32 count,
|
||||
PRUint32 *countRead)
|
||||
{
|
||||
LOG3(("SpdyStream %p ReadSegments reader=%p count=%d state=%x",
|
||||
this, reader, count, mUpstreamState));
|
||||
|
||||
NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
|
||||
nsresult rv = NS_ERROR_UNEXPECTED;
|
||||
mBlockedOnWrite = 0;
|
||||
mRequestBlockedOnRead = 0;
|
||||
|
||||
switch (mUpstreamState) {
|
||||
case GENERATING_SYN_STREAM:
|
||||
case GENERATING_REQUEST_BODY:
|
||||
case SENDING_REQUEST_BODY:
|
||||
// Call into the HTTP Transaction to generate the HTTP request
|
||||
// stream. That stream will show up in OnReadSegment().
|
||||
mSegmentReader = reader;
|
||||
rv = mTransaction->ReadSegments(this, count, countRead);
|
||||
mSegmentReader = nsnull;
|
||||
|
||||
if (NS_SUCCEEDED(rv) &&
|
||||
mUpstreamState == GENERATING_SYN_STREAM &&
|
||||
!mSynFrameComplete)
|
||||
mBlockedOnWrite = 1;
|
||||
|
||||
// Mark that we are blocked on read if we the http transaction
|
||||
// is going to get us going again.
|
||||
if (rv == NS_BASE_STREAM_WOULD_BLOCK && !mBlockedOnWrite)
|
||||
mRequestBlockedOnRead = 1;
|
||||
|
||||
if (!mBlockedOnWrite && NS_SUCCEEDED(rv) && (!*countRead)) {
|
||||
LOG3(("ReadSegments %p Send Request data complete from %x",
|
||||
this, mUpstreamState));
|
||||
if (mSentFinOnData) {
|
||||
ChangeState(UPSTREAM_COMPLETE);
|
||||
}
|
||||
else {
|
||||
GenerateDataFrameHeader(0, true);
|
||||
ChangeState(SENDING_FIN_STREAM);
|
||||
mBlockedOnWrite = 1;
|
||||
rv = NS_BASE_STREAM_WOULD_BLOCK;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SENDING_SYN_STREAM:
|
||||
// We were trying to send the SYN-STREAM but only got part of it out
|
||||
// before being blocked. Try and send more.
|
||||
mSegmentReader = reader;
|
||||
rv = TransmitFrame(nsnull, nsnull);
|
||||
mSegmentReader = nsnull;
|
||||
*countRead = 0;
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = NS_BASE_STREAM_WOULD_BLOCK;
|
||||
|
||||
if (!mTxInlineFrameSize) {
|
||||
if (mSentFinOnData) {
|
||||
ChangeState(UPSTREAM_COMPLETE);
|
||||
rv = NS_OK;
|
||||
}
|
||||
else {
|
||||
ChangeState(GENERATING_REQUEST_BODY);
|
||||
mBlockedOnWrite = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SENDING_FIN_STREAM:
|
||||
// We were trying to send the SYN-STREAM but only got part of it out
|
||||
// before being blocked. Try and send more.
|
||||
if (!mSentFinOnData) {
|
||||
mSegmentReader = reader;
|
||||
rv = TransmitFrame(nsnull, nsnull);
|
||||
mSegmentReader = nsnull;
|
||||
if (!mTxInlineFrameSize)
|
||||
ChangeState(UPSTREAM_COMPLETE);
|
||||
}
|
||||
else {
|
||||
rv = NS_OK;
|
||||
mTxInlineFrameSize = 0; // cancel fin data packet
|
||||
ChangeState(UPSTREAM_COMPLETE);
|
||||
}
|
||||
|
||||
*countRead = 0;
|
||||
|
||||
// don't change OK to WOULD BLOCK. we are really done sending if OK
|
||||
break;
|
||||
|
||||
default:
|
||||
NS_ABORT_IF_FALSE(false, "SpdyStream::ReadSegments unknown state");
|
||||
break;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
// WriteSegments() is used to read data off the socket. Generally this is
|
||||
// just the SPDY frame header and from there the appropriate SPDYStream
|
||||
// is identified from the Stream-ID. The http transaction associated with
|
||||
// that read then pulls in the data directly.
|
||||
|
||||
nsresult
|
||||
SpdyStream::WriteSegments(nsAHttpSegmentWriter *writer,
|
||||
PRUint32 count,
|
||||
PRUint32 *countWritten)
|
||||
{
|
||||
LOG3(("SpdyStream::WriteSegments %p count=%d state=%x",
|
||||
this, count, mUpstreamState));
|
||||
|
||||
NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
NS_ABORT_IF_FALSE(!mSegmentWriter, "segment writer in progress");
|
||||
|
||||
mSegmentWriter = writer;
|
||||
nsresult rv = mTransaction->WriteSegments(writer, count, countWritten);
|
||||
mSegmentWriter = nsnull;
|
||||
return rv;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
SpdyStream::hdrHashEnumerate(const nsACString &key,
|
||||
nsAutoPtr<nsCString> &value,
|
||||
void *closure)
|
||||
{
|
||||
SpdyStream *self = static_cast<SpdyStream *>(closure);
|
||||
|
||||
self->CompressToFrame(key);
|
||||
self->CompressToFrame(value.get());
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
nsresult
|
||||
SpdyStream::ParseHttpRequestHeaders(const char *buf,
|
||||
PRUint32 avail,
|
||||
PRUint32 *countUsed)
|
||||
{
|
||||
// Returns NS_OK even if the headers are incomplete
|
||||
// set mSynFrameComplete flag if they are complete
|
||||
|
||||
NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
NS_ABORT_IF_FALSE(mUpstreamState == GENERATING_SYN_STREAM, "wrong state");
|
||||
|
||||
LOG3(("SpdyStream::ParseHttpRequestHeaders %p avail=%d state=%x",
|
||||
this, avail, mUpstreamState));
|
||||
|
||||
mFlatHttpRequestHeaders.Append(buf, avail);
|
||||
|
||||
// We can use the simple double crlf because firefox is the
|
||||
// only client we are parsing
|
||||
PRInt32 endHeader = mFlatHttpRequestHeaders.Find("\r\n\r\n");
|
||||
|
||||
if (endHeader == -1) {
|
||||
// We don't have all the headers yet
|
||||
LOG3(("SpdyStream::ParseHttpRequestHeaders %p "
|
||||
"Need more header bytes. Len = %d",
|
||||
this, mFlatHttpRequestHeaders.Length()));
|
||||
*countUsed = avail;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// We have recvd all the headers, trim the local
|
||||
// buffer of the final empty line, and set countUsed to reflect
|
||||
// the whole header has been consumed.
|
||||
PRUint32 oldLen = mFlatHttpRequestHeaders.Length();
|
||||
mFlatHttpRequestHeaders.SetLength(endHeader + 2);
|
||||
*countUsed = avail - (oldLen - endHeader) + 4;
|
||||
mSynFrameComplete = 1;
|
||||
|
||||
// It is now OK to assign a streamID that we are assured will
|
||||
// be monotonically increasing amongst syn-streams on this
|
||||
// session
|
||||
mStreamID = mSession->RegisterStreamID(this);
|
||||
NS_ABORT_IF_FALSE(mStreamID & 1,
|
||||
"Spdy Stream Channel ID must be odd");
|
||||
|
||||
if (mStreamID >= 0x80000000) {
|
||||
// streamID must fit in 31 bits. This is theoretically possible
|
||||
// because stream ID assignment is asynchronous to stream creation
|
||||
// because of the protocol requirement that the ID in syn-stream
|
||||
// be monotonically increasing. In reality this is really not possible
|
||||
// because new streams stop being added to a session with 0x10000000 / 2
|
||||
// IDs still available and no race condition is going to bridge that gap,
|
||||
// so we can be comfortable on just erroring out for correctness in that
|
||||
// case.
|
||||
LOG3(("Stream assigned out of range ID: 0x%X", mStreamID));
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Now we need to convert the flat http headers into a set
|
||||
// of SPDY headers.. writing to mTxInlineFrame{sz}
|
||||
|
||||
mTxInlineFrame[0] = SpdySession::kFlag_Control;
|
||||
mTxInlineFrame[1] = 2; /* version */
|
||||
mTxInlineFrame[2] = 0;
|
||||
mTxInlineFrame[3] = SpdySession::CONTROL_TYPE_SYN_STREAM;
|
||||
// 4 to 7 are length and flags, we'll fill that in later
|
||||
|
||||
PRUint32 networkOrderID = PR_htonl(mStreamID);
|
||||
memcpy(mTxInlineFrame + 8, &networkOrderID, 4);
|
||||
|
||||
// this is the associated-to field, which is not used sending
|
||||
// from the client in the http binding
|
||||
memset (mTxInlineFrame + 12, 0, 4);
|
||||
|
||||
// Priority flags are the C0 mask of byte 16.
|
||||
// From low to high: 00 40 80 C0
|
||||
// higher raw priority values are actually less important
|
||||
//
|
||||
// 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] = SpdySession::kPri00;
|
||||
else if (mPriority >= nsISupportsPriority::PRIORITY_NORMAL)
|
||||
mTxInlineFrame[16] = SpdySession::kPri01;
|
||||
else if (mPriority >= nsISupportsPriority::PRIORITY_HIGH)
|
||||
mTxInlineFrame[16] = SpdySession::kPri02;
|
||||
else
|
||||
mTxInlineFrame[16] = SpdySession::kPri03;
|
||||
|
||||
mTxInlineFrame[17] = 0; /* unused */
|
||||
|
||||
// nsCString methodHeader;
|
||||
// mTransaction->RequestHead()->Method()->ToUTF8String(methodHeader);
|
||||
const char *methodHeader = mTransaction->RequestHead()->Method().get();
|
||||
|
||||
nsCString hostHeader;
|
||||
mTransaction->RequestHead()->GetHeader(nsHttp::Host, hostHeader);
|
||||
|
||||
nsCString versionHeader;
|
||||
if (mTransaction->RequestHead()->Version() == NS_HTTP_VERSION_1_1)
|
||||
versionHeader = NS_LITERAL_CSTRING("HTTP/1.1");
|
||||
else
|
||||
versionHeader = NS_LITERAL_CSTRING("HTTP/1.0");
|
||||
|
||||
nsClassHashtable<nsCStringHashKey, nsCString> hdrHash;
|
||||
|
||||
// use mRequestHead() to get a sense of how big to make the hash,
|
||||
// even though we are parsing the actual text stream because
|
||||
// it is legit to append headers.
|
||||
hdrHash.Init(1 + (mTransaction->RequestHead()->Headers().Count() * 2));
|
||||
|
||||
const char *beginBuffer = mFlatHttpRequestHeaders.BeginReading();
|
||||
|
||||
// need to hash all the headers together to remove duplicates, special
|
||||
// headers, etc..
|
||||
|
||||
PRInt32 crlfIndex = mFlatHttpRequestHeaders.Find("\r\n");
|
||||
while (true) {
|
||||
PRInt32 startIndex = crlfIndex + 2;
|
||||
|
||||
crlfIndex = mFlatHttpRequestHeaders.Find("\r\n", false, startIndex);
|
||||
if (crlfIndex == -1)
|
||||
break;
|
||||
|
||||
PRInt32 colonIndex = mFlatHttpRequestHeaders.Find(":", false, startIndex,
|
||||
crlfIndex - startIndex);
|
||||
if (colonIndex == -1)
|
||||
break;
|
||||
|
||||
nsDependentCSubstring name = Substring(beginBuffer + startIndex,
|
||||
beginBuffer + colonIndex);
|
||||
// all header names are lower case in spdy
|
||||
ToLowerCase(name);
|
||||
|
||||
if (name.Equals("method") ||
|
||||
name.Equals("version") ||
|
||||
name.Equals("scheme") ||
|
||||
name.Equals("keep-alive") ||
|
||||
name.Equals("accept-encoding") ||
|
||||
name.Equals("te") ||
|
||||
name.Equals("connection") ||
|
||||
name.Equals("proxy-connection") ||
|
||||
name.Equals("url"))
|
||||
continue;
|
||||
|
||||
nsCString *val = hdrHash.Get(name);
|
||||
if (!val) {
|
||||
val = new nsCString();
|
||||
hdrHash.Put(name, val);
|
||||
}
|
||||
|
||||
PRInt32 valueIndex = colonIndex + 1;
|
||||
while (valueIndex < crlfIndex && beginBuffer[valueIndex] == ' ')
|
||||
++valueIndex;
|
||||
|
||||
nsDependentCSubstring v = Substring(beginBuffer + valueIndex,
|
||||
beginBuffer + crlfIndex);
|
||||
if (!val->IsEmpty())
|
||||
val->Append(static_cast<char>(0));
|
||||
val->Append(v);
|
||||
|
||||
if (name.Equals("content-length")) {
|
||||
PRInt64 len;
|
||||
if (nsHttp::ParseInt64(val->get(), nsnull, &len))
|
||||
mRequestBodyLen = len;
|
||||
}
|
||||
}
|
||||
|
||||
mTxInlineFrameSize = 18;
|
||||
|
||||
LOG3(("http request headers to encode are: \n%s",
|
||||
mFlatHttpRequestHeaders.get()));
|
||||
|
||||
// The header block length
|
||||
PRUint16 count = hdrHash.Count() + 4; /* method, scheme, url, version */
|
||||
CompressToFrame(count);
|
||||
|
||||
// method, scheme, url, and version headers for request line
|
||||
|
||||
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(mTransaction->RequestHead()->RequestURI());
|
||||
CompressToFrame(NS_LITERAL_CSTRING("version"));
|
||||
CompressToFrame(versionHeader);
|
||||
|
||||
hdrHash.Enumerate(hdrHashEnumerate, this);
|
||||
CompressFlushFrame();
|
||||
|
||||
// 4 to 7 are length and flags, which we can now fill in
|
||||
(reinterpret_cast<PRUint32 *>(mTxInlineFrame.get()))[1] =
|
||||
PR_htonl(mTxInlineFrameSize - 8);
|
||||
|
||||
NS_ABORT_IF_FALSE(!mTxInlineFrame[4],
|
||||
"Size greater than 24 bits");
|
||||
|
||||
// For methods other than POST and PUT, we will set the fin bit
|
||||
// right on the syn stream packet.
|
||||
|
||||
if (mTransaction->RequestHead()->Method() != nsHttp::Post &&
|
||||
mTransaction->RequestHead()->Method() != nsHttp::Put) {
|
||||
mSentFinOnData = 1;
|
||||
mTxInlineFrame[4] = SpdySession::kFlag_Data_FIN;
|
||||
}
|
||||
|
||||
Telemetry::Accumulate(Telemetry::SPDY_SYN_SIZE, mTxInlineFrameSize - 18);
|
||||
|
||||
// The size of the input headers is approximate
|
||||
PRUint32 ratio =
|
||||
(mTxInlineFrameSize - 18) * 100 /
|
||||
(11 + mTransaction->RequestHead()->RequestURI().Length() +
|
||||
mFlatHttpRequestHeaders.Length());
|
||||
|
||||
Telemetry::Accumulate(Telemetry::SPDY_SYN_RATIO, ratio);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
SpdyStream::TransmitFrame(const char *buf,
|
||||
PRUint32 *countUsed)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(mTxInlineFrameSize, "empty stream frame in transmit");
|
||||
NS_ABORT_IF_FALSE(mSegmentReader, "TransmitFrame with null mSegmentReader");
|
||||
|
||||
PRUint32 transmittedCount;
|
||||
nsresult rv;
|
||||
|
||||
LOG3(("SpdyStream::TransmitFrame %p inline=%d of %d stream=%d of %d",
|
||||
this, mTxInlineFrameSent, mTxInlineFrameSize,
|
||||
mTxStreamFrameSent, mTxStreamFrameSize));
|
||||
if (countUsed)
|
||||
*countUsed = 0;
|
||||
mBlockedOnWrite = 0;
|
||||
|
||||
// In the (relatively common) event that we have a small amount of data
|
||||
// split between the inlineframe and the streamframe, then move the stream
|
||||
// data into the inlineframe via copy in order to coalesce into one write.
|
||||
// Given the interaction with ssl this is worth the small copy cost.
|
||||
if (mTxStreamFrameSize && mTxInlineFrameSize &&
|
||||
!mTxInlineFrameSent && !mTxStreamFrameSent &&
|
||||
mTxStreamFrameSize < SpdySession::kDefaultBufferSize &&
|
||||
mTxInlineFrameSize + mTxStreamFrameSize < mTxInlineFrameAllocation) {
|
||||
LOG3(("Coalesce Transmit"));
|
||||
memcpy (mTxInlineFrame + mTxInlineFrameSize,
|
||||
buf, mTxStreamFrameSize);
|
||||
mTxInlineFrameSize += mTxStreamFrameSize;
|
||||
mTxStreamFrameSent = 0;
|
||||
mTxStreamFrameSize = 0;
|
||||
}
|
||||
|
||||
// This function calls mSegmentReader->OnReadSegment to report the actual SPDY
|
||||
// bytes through to the SpdySession and then the HttpConnection which calls
|
||||
// the socket write function.
|
||||
|
||||
while (mTxInlineFrameSent < mTxInlineFrameSize) {
|
||||
rv = mSegmentReader->OnReadSegment(mTxInlineFrame + mTxInlineFrameSent,
|
||||
mTxInlineFrameSize - mTxInlineFrameSent,
|
||||
&transmittedCount);
|
||||
LOG3(("SpdyStream::TransmitFrame for inline session=%p "
|
||||
"stream=%p result %x len=%d",
|
||||
mSession, this, rv, transmittedCount));
|
||||
SpdySession::LogIO(mSession, this, "Writing from Inline Buffer",
|
||||
mTxInlineFrame + mTxInlineFrameSent,
|
||||
transmittedCount);
|
||||
|
||||
if (rv == NS_BASE_STREAM_WOULD_BLOCK)
|
||||
mBlockedOnWrite = 1;
|
||||
|
||||
if (NS_FAILED(rv)) // this will include WOULD_BLOCK
|
||||
return rv;
|
||||
|
||||
mTxInlineFrameSent += transmittedCount;
|
||||
}
|
||||
|
||||
PRUint32 offset = 0;
|
||||
NS_ABORT_IF_FALSE(mTxStreamFrameSize >= mTxStreamFrameSent,
|
||||
"negative unsent");
|
||||
PRUint32 avail = mTxStreamFrameSize - mTxStreamFrameSent;
|
||||
|
||||
while (avail) {
|
||||
NS_ABORT_IF_FALSE(countUsed, "null countused pointer in a stream context");
|
||||
rv = mSegmentReader->OnReadSegment(buf + offset, avail, &transmittedCount);
|
||||
|
||||
LOG3(("SpdyStream::TransmitFrame for regular session=%p "
|
||||
"stream=%p result %x len=%d",
|
||||
mSession, this, rv, transmittedCount));
|
||||
SpdySession::LogIO(mSession, this, "Writing from Transaction Buffer",
|
||||
buf + offset, transmittedCount);
|
||||
|
||||
if (rv == NS_BASE_STREAM_WOULD_BLOCK)
|
||||
mBlockedOnWrite = 1;
|
||||
|
||||
if (NS_FAILED(rv)) // this will include WOULD_BLOCK
|
||||
return rv;
|
||||
|
||||
if (mUpstreamState == SENDING_REQUEST_BODY) {
|
||||
mTransaction->OnTransportStatus(mSocketTransport,
|
||||
nsISocketTransport::STATUS_SENDING_TO,
|
||||
transmittedCount);
|
||||
}
|
||||
|
||||
*countUsed += transmittedCount;
|
||||
avail -= transmittedCount;
|
||||
offset += transmittedCount;
|
||||
mTxStreamFrameSent += transmittedCount;
|
||||
}
|
||||
|
||||
if (!avail) {
|
||||
mTxInlineFrameSent = 0;
|
||||
mTxInlineFrameSize = 0;
|
||||
mTxStreamFrameSent = 0;
|
||||
mTxStreamFrameSize = 0;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
SpdyStream::ChangeState(enum stateType newState)
|
||||
{
|
||||
LOG3(("SpdyStream::ChangeState() %p from %X to %X",
|
||||
this, mUpstreamState, newState));
|
||||
mUpstreamState = newState;
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
SpdyStream::GenerateDataFrameHeader(PRUint32 dataLength, bool lastFrame)
|
||||
{
|
||||
LOG3(("SpdyStream::GenerateDataFrameHeader %p len=%d last=%d",
|
||||
this, dataLength, lastFrame));
|
||||
|
||||
NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
NS_ABORT_IF_FALSE(!mTxInlineFrameSize, "inline frame not empty");
|
||||
NS_ABORT_IF_FALSE(!mTxInlineFrameSent, "inline partial send not 0");
|
||||
NS_ABORT_IF_FALSE(!mTxStreamFrameSize, "stream frame not empty");
|
||||
NS_ABORT_IF_FALSE(!mTxStreamFrameSent, "stream partial send not 0");
|
||||
NS_ABORT_IF_FALSE(!(dataLength & 0xff000000), "datalength > 24 bits");
|
||||
|
||||
(reinterpret_cast<PRUint32 *>(mTxInlineFrame.get()))[0] = PR_htonl(mStreamID);
|
||||
(reinterpret_cast<PRUint32 *>(mTxInlineFrame.get()))[1] =
|
||||
PR_htonl(dataLength);
|
||||
|
||||
NS_ABORT_IF_FALSE(!(mTxInlineFrame[0] & 0x80),
|
||||
"control bit set unexpectedly");
|
||||
NS_ABORT_IF_FALSE(!mTxInlineFrame[4], "flag bits set unexpectedly");
|
||||
|
||||
mTxInlineFrameSize = 8;
|
||||
mTxStreamFrameSize = dataLength;
|
||||
|
||||
if (lastFrame) {
|
||||
mTxInlineFrame[4] |= SpdySession::kFlag_Data_FIN;
|
||||
if (dataLength)
|
||||
mSentFinOnData = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SpdyStream::CompressToFrame(const nsACString &str)
|
||||
{
|
||||
CompressToFrame(str.BeginReading(), str.Length());
|
||||
}
|
||||
|
||||
void
|
||||
SpdyStream::CompressToFrame(const nsACString *str)
|
||||
{
|
||||
CompressToFrame(str->BeginReading(), str->Length());
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
const char *SpdyStream::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";
|
||||
|
||||
// use for zlib data types
|
||||
void *
|
||||
SpdyStream::zlib_allocator(void *opaque, uInt items, uInt size)
|
||||
{
|
||||
return moz_xmalloc(items * size);
|
||||
}
|
||||
|
||||
// use for zlib data types
|
||||
void
|
||||
SpdyStream::zlib_destructor(void *opaque, void *addr)
|
||||
{
|
||||
moz_free(addr);
|
||||
}
|
||||
|
||||
void
|
||||
SpdyStream::ExecuteCompress(PRUint32 flushMode)
|
||||
{
|
||||
// Expect mZlib->avail_in and mZlib->next_in to be set.
|
||||
// Append the compressed version of next_in to mTxInlineFrame
|
||||
|
||||
do
|
||||
{
|
||||
PRUint32 avail = mTxInlineFrameAllocation - mTxInlineFrameSize;
|
||||
if (avail < 1) {
|
||||
SpdySession::EnsureBuffer(mTxInlineFrame,
|
||||
mTxInlineFrameAllocation + 2000,
|
||||
mTxInlineFrameSize,
|
||||
mTxInlineFrameAllocation);
|
||||
avail = mTxInlineFrameAllocation - mTxInlineFrameSize;
|
||||
}
|
||||
|
||||
mZlib->next_out = reinterpret_cast<unsigned char *> (mTxInlineFrame.get()) +
|
||||
mTxInlineFrameSize;
|
||||
mZlib->avail_out = avail;
|
||||
deflate(mZlib, flushMode);
|
||||
mTxInlineFrameSize += avail - mZlib->avail_out;
|
||||
} while (mZlib->avail_in > 0 || !mZlib->avail_out);
|
||||
}
|
||||
|
||||
void
|
||||
SpdyStream::CompressToFrame(PRUint16 data)
|
||||
{
|
||||
// convert the data to network byte order and write that
|
||||
// to the compressed stream
|
||||
|
||||
data = PR_htons(data);
|
||||
|
||||
mZlib->next_in = reinterpret_cast<unsigned char *> (&data);
|
||||
mZlib->avail_in = 2;
|
||||
ExecuteCompress(Z_NO_FLUSH);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpdyStream::CompressToFrame(const char *data, PRUint32 len)
|
||||
{
|
||||
// Format calls for a network ordered 16 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 = len;
|
||||
networkLen = PR_htons(len);
|
||||
|
||||
// write out the length
|
||||
mZlib->next_in = reinterpret_cast<unsigned char *> (&networkLen);
|
||||
mZlib->avail_in = 2;
|
||||
ExecuteCompress(Z_NO_FLUSH);
|
||||
|
||||
// write out the data
|
||||
mZlib->next_in = (unsigned char *)data;
|
||||
mZlib->avail_in = len;
|
||||
ExecuteCompress(Z_NO_FLUSH);
|
||||
}
|
||||
|
||||
void
|
||||
SpdyStream::CompressFlushFrame()
|
||||
{
|
||||
mZlib->next_in = (unsigned char *) "";
|
||||
mZlib->avail_in = 0;
|
||||
ExecuteCompress(Z_SYNC_FLUSH);
|
||||
}
|
||||
|
||||
void
|
||||
SpdyStream::Close(nsresult reason)
|
||||
{
|
||||
mTransaction->Close(reason);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsAHttpSegmentReader
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsresult
|
||||
SpdyStream::OnReadSegment(const char *buf,
|
||||
PRUint32 count,
|
||||
PRUint32 *countRead)
|
||||
{
|
||||
LOG3(("SpdyStream::OnReadSegment %p count=%d state=%x",
|
||||
this, count, mUpstreamState));
|
||||
|
||||
NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
NS_ABORT_IF_FALSE(mSegmentReader, "OnReadSegment with null mSegmentReader");
|
||||
|
||||
nsresult rv = NS_ERROR_UNEXPECTED;
|
||||
PRUint32 dataLength;
|
||||
|
||||
switch (mUpstreamState) {
|
||||
case GENERATING_SYN_STREAM:
|
||||
// The buffer is the HTTP request stream, including at least part of the
|
||||
// HTTP request header. This state's job is to build a SYN_STREAM frame
|
||||
// from the header information. count is the number of http bytes available
|
||||
// (which may include more than the header), and in countRead we return
|
||||
// the number of those bytes that we consume (i.e. the portion that are
|
||||
// header bytes)
|
||||
|
||||
rv = ParseHttpRequestHeaders(buf, count, countRead);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
LOG3(("ParseHttpRequestHeaders %p used %d of %d.",
|
||||
this, *countRead, count));
|
||||
if (mSynFrameComplete) {
|
||||
NS_ABORT_IF_FALSE(mTxInlineFrameSize,
|
||||
"OnReadSegment SynFrameComplete 0b");
|
||||
rv = TransmitFrame(nsnull, nsnull);
|
||||
if (rv == NS_BASE_STREAM_WOULD_BLOCK && *countRead)
|
||||
rv = NS_OK;
|
||||
if (mTxInlineFrameSize)
|
||||
ChangeState(SENDING_SYN_STREAM);
|
||||
else
|
||||
ChangeState(GENERATING_REQUEST_BODY);
|
||||
break;
|
||||
}
|
||||
NS_ABORT_IF_FALSE(*countRead == count,
|
||||
"Header parsing not complete but unused data");
|
||||
break;
|
||||
|
||||
case GENERATING_REQUEST_BODY:
|
||||
NS_ABORT_IF_FALSE(!mTxInlineFrameSent,
|
||||
"OnReadSegment in generating_request_body with "
|
||||
"frame in progress");
|
||||
if (count < mChunkSize && count < mRequestBodyLen) {
|
||||
LOG3(("SpdyStream %p id %x has %d to write out of a bodylen %d"
|
||||
" with a chunk size of %d. Waiting for more.",
|
||||
this, mStreamID, count, mChunkSize, mRequestBodyLen));
|
||||
rv = NS_BASE_STREAM_WOULD_BLOCK;
|
||||
break;
|
||||
}
|
||||
|
||||
dataLength = NS_MIN(count, mChunkSize);
|
||||
if (dataLength > mRequestBodyLen)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
mRequestBodyLen -= dataLength;
|
||||
GenerateDataFrameHeader(dataLength, !mRequestBodyLen);
|
||||
ChangeState(SENDING_REQUEST_BODY);
|
||||
// NO BREAK
|
||||
|
||||
case SENDING_REQUEST_BODY:
|
||||
NS_ABORT_IF_FALSE(mTxInlineFrameSize, "OnReadSegment Send Data Header 0b");
|
||||
rv = TransmitFrame(buf, countRead);
|
||||
LOG3(("TransmitFrame() rv=%x returning %d data bytes. "
|
||||
"Header is %d/%d Body is %d/%d.",
|
||||
rv, *countRead,
|
||||
mTxInlineFrameSent, mTxInlineFrameSize,
|
||||
mTxStreamFrameSent, mTxStreamFrameSize));
|
||||
|
||||
if (rv == NS_BASE_STREAM_WOULD_BLOCK && *countRead)
|
||||
rv = NS_OK;
|
||||
|
||||
// If that frame was all sent, look for another one
|
||||
if (!mTxInlineFrameSize)
|
||||
ChangeState(GENERATING_REQUEST_BODY);
|
||||
break;
|
||||
|
||||
case SENDING_SYN_STREAM:
|
||||
rv = NS_BASE_STREAM_WOULD_BLOCK;
|
||||
break;
|
||||
|
||||
case SENDING_FIN_STREAM:
|
||||
NS_ABORT_IF_FALSE(false,
|
||||
"resuming partial fin stream out of OnReadSegment");
|
||||
break;
|
||||
|
||||
default:
|
||||
NS_ABORT_IF_FALSE(false, "SpdyStream::OnReadSegment non-write state");
|
||||
break;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsAHttpSegmentWriter
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsresult
|
||||
SpdyStream::OnWriteSegment(char *buf,
|
||||
PRUint32 count,
|
||||
PRUint32 *countWritten)
|
||||
{
|
||||
LOG3(("SpdyStream::OnWriteSegment %p count=%d state=%x",
|
||||
this, count, mUpstreamState));
|
||||
|
||||
NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
NS_ABORT_IF_FALSE(mSegmentWriter, "OnWriteSegment with null mSegmentWriter");
|
||||
|
||||
return mSegmentWriter->OnWriteSegment(buf, count, countWritten);
|
||||
}
|
||||
|
||||
} // namespace mozilla::net
|
||||
} // namespace mozilla
|
||||
|
|
@ -1,207 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et tw=80 : */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Patrick McManus <mcmanus@ducksong.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef mozilla_net_SpdyStream_h
|
||||
#define mozilla_net_SpdyStream_h
|
||||
|
||||
#include "nsAHttpTransaction.h"
|
||||
|
||||
namespace mozilla { namespace net {
|
||||
|
||||
class SpdyStream : public nsAHttpSegmentReader
|
||||
, public nsAHttpSegmentWriter
|
||||
{
|
||||
public:
|
||||
NS_DECL_NSAHTTPSEGMENTREADER
|
||||
NS_DECL_NSAHTTPSEGMENTWRITER
|
||||
|
||||
SpdyStream(nsAHttpTransaction *,
|
||||
SpdySession *, nsISocketTransport *,
|
||||
PRUint32, z_stream *, PRInt32);
|
||||
~SpdyStream();
|
||||
|
||||
PRUint32 StreamID() { return mStreamID; }
|
||||
|
||||
nsresult ReadSegments(nsAHttpSegmentReader *, PRUint32, PRUint32 *);
|
||||
nsresult WriteSegments(nsAHttpSegmentWriter *, PRUint32, PRUint32 *);
|
||||
|
||||
bool BlockedOnWrite()
|
||||
{
|
||||
return static_cast<bool>(mBlockedOnWrite);
|
||||
}
|
||||
|
||||
bool RequestBlockedOnRead()
|
||||
{
|
||||
return static_cast<bool>(mRequestBlockedOnRead);
|
||||
}
|
||||
|
||||
// returns false if called more than once
|
||||
bool SetFullyOpen()
|
||||
{
|
||||
bool result = !mFullyOpen;
|
||||
mFullyOpen = 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
nsAHttpTransaction *Transaction()
|
||||
{
|
||||
return mTransaction;
|
||||
}
|
||||
|
||||
void Close(nsresult reason);
|
||||
|
||||
void SetRecvdFin(bool aStatus) { mRecvdFin = aStatus ? 1 : 0; }
|
||||
bool RecvdFin() { return mRecvdFin; }
|
||||
|
||||
// The zlib header compression dictionary defined by SPDY,
|
||||
// and hooks to the mozilla allocator for zlib to use.
|
||||
static const char *kDictionary;
|
||||
static void *zlib_allocator(void *, uInt, uInt);
|
||||
static void zlib_destructor(void *, void *);
|
||||
|
||||
private:
|
||||
|
||||
enum stateType {
|
||||
GENERATING_SYN_STREAM,
|
||||
SENDING_SYN_STREAM,
|
||||
GENERATING_REQUEST_BODY,
|
||||
SENDING_REQUEST_BODY,
|
||||
SENDING_FIN_STREAM,
|
||||
UPSTREAM_COMPLETE
|
||||
};
|
||||
|
||||
static PLDHashOperator hdrHashEnumerate(const nsACString &,
|
||||
nsAutoPtr<nsCString> &,
|
||||
void *);
|
||||
|
||||
void ChangeState(enum stateType );
|
||||
nsresult ParseHttpRequestHeaders(const char *, PRUint32, PRUint32 *);
|
||||
nsresult TransmitFrame(const char *, PRUint32 *);
|
||||
void GenerateDataFrameHeader(PRUint32, bool);
|
||||
|
||||
void CompressToFrame(const nsACString &);
|
||||
void CompressToFrame(const nsACString *);
|
||||
void CompressToFrame(const char *, PRUint32);
|
||||
void CompressToFrame(PRUint16);
|
||||
void CompressFlushFrame();
|
||||
void ExecuteCompress(PRUint32);
|
||||
|
||||
// Each stream goes from syn_stream to upstream_complete, perhaps
|
||||
// looping on multiple instances of generating_request_body and
|
||||
// sending_request_body for each SPDY chunk in the upload.
|
||||
enum stateType mUpstreamState;
|
||||
|
||||
// The underlying HTTP transaction
|
||||
nsRefPtr<nsAHttpTransaction> mTransaction;
|
||||
|
||||
// The session that this stream is a subset of
|
||||
SpdySession *mSession;
|
||||
|
||||
// The underlying socket transport object is needed to propogate some events
|
||||
nsISocketTransport *mSocketTransport;
|
||||
|
||||
// These are temporary state variables to hold the argument to
|
||||
// Read/WriteSegments so it can be accessed by On(read/write)segment
|
||||
// further up the stack.
|
||||
nsAHttpSegmentReader *mSegmentReader;
|
||||
nsAHttpSegmentWriter *mSegmentWriter;
|
||||
|
||||
// The 24 bit SPDY stream ID
|
||||
PRUint32 mStreamID;
|
||||
|
||||
// The quanta upstream data frames are chopped into
|
||||
PRUint32 mChunkSize;
|
||||
|
||||
// Flag is set when all http request headers have been read
|
||||
PRUint32 mSynFrameComplete : 1;
|
||||
|
||||
// Flag is set when there is more request data to send and the
|
||||
// stream needs to be rescheduled for writing. Sometimes this
|
||||
// is done as a matter of fairness, not really due to blocking
|
||||
PRUint32 mBlockedOnWrite : 1;
|
||||
|
||||
// Flag is set when the HTTP processor has more data to send
|
||||
// but has blocked in doing so.
|
||||
PRUint32 mRequestBlockedOnRead : 1;
|
||||
|
||||
// Flag is set when a FIN has been placed on a data or syn packet
|
||||
// (i.e after the client has closed)
|
||||
PRUint32 mSentFinOnData : 1;
|
||||
|
||||
// Flag is set after the response frame bearing the fin bit has
|
||||
// been processed. (i.e. after the server has closed).
|
||||
PRUint32 mRecvdFin : 1;
|
||||
|
||||
// Flag is set after syn reply received
|
||||
PRUint32 mFullyOpen : 1;
|
||||
|
||||
// The InlineFrame and associated data is used for composing control
|
||||
// frames and data frame headers.
|
||||
nsAutoArrayPtr<char> mTxInlineFrame;
|
||||
PRUint32 mTxInlineFrameAllocation;
|
||||
PRUint32 mTxInlineFrameSize;
|
||||
PRUint32 mTxInlineFrameSent;
|
||||
|
||||
// mTxStreamFrameSize and mTxStreamFrameSent track the progress of
|
||||
// transmitting a request body data frame. The data frame itself
|
||||
// is never copied into the spdy layer.
|
||||
PRUint32 mTxStreamFrameSize;
|
||||
PRUint32 mTxStreamFrameSent;
|
||||
|
||||
// Compression context and buffer for request header compression.
|
||||
// This is a copy of SpdySession::mUpstreamZlib because it needs
|
||||
// to remain the same in all streams of a session.
|
||||
z_stream *mZlib;
|
||||
nsCString mFlatHttpRequestHeaders;
|
||||
|
||||
// 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
|
||||
// in an extra 0-length runt packet and seems to have some interop
|
||||
// problems with the google servers.
|
||||
PRInt64 mRequestBodyLen;
|
||||
|
||||
// based on nsISupportsPriority definitions
|
||||
PRInt32 mPriority;
|
||||
|
||||
};
|
||||
|
||||
}} // namespace mozilla::net
|
||||
|
||||
#endif // mozilla_net_SpdyStream_h
|
|
@ -77,8 +77,8 @@ public:
|
|||
// after a transaction returned NS_BASE_STREAM_WOULD_BLOCK from its
|
||||
// ReadSegments/WriteSegments methods.
|
||||
//
|
||||
virtual nsresult ResumeSend(nsAHttpTransaction *caller) = 0;
|
||||
virtual nsresult ResumeRecv(nsAHttpTransaction *caller) = 0;
|
||||
virtual nsresult ResumeSend() = 0;
|
||||
virtual nsresult ResumeRecv() = 0;
|
||||
|
||||
//
|
||||
// called by the connection manager to close a transaction being processed
|
||||
|
@ -132,8 +132,8 @@ public:
|
|||
|
||||
#define NS_DECL_NSAHTTPCONNECTION \
|
||||
nsresult OnHeadersAvailable(nsAHttpTransaction *, nsHttpRequestHead *, nsHttpResponseHead *, bool *reset); \
|
||||
nsresult ResumeSend(nsAHttpTransaction *); \
|
||||
nsresult ResumeRecv(nsAHttpTransaction *); \
|
||||
nsresult ResumeSend(); \
|
||||
nsresult ResumeRecv(); \
|
||||
void CloseTransaction(nsAHttpTransaction *, nsresult); \
|
||||
void GetConnectionInfo(nsHttpConnectionInfo **); \
|
||||
nsresult TakeTransport(nsISocketTransport **, \
|
||||
|
|
|
@ -62,7 +62,6 @@ class nsAHttpTransaction : public nsISupports
|
|||
public:
|
||||
// called by the connection when it takes ownership of the transaction.
|
||||
virtual void SetConnection(nsAHttpConnection *) = 0;
|
||||
virtual nsAHttpConnection *Connection() = 0;
|
||||
|
||||
// called by the connection to get security callbacks to set on the
|
||||
// socket transport.
|
||||
|
@ -96,16 +95,10 @@ public:
|
|||
|
||||
// called to retrieve the request headers of the transaction
|
||||
virtual nsHttpRequestHead *RequestHead() = 0;
|
||||
|
||||
// determine the number of real http/1.x transactions on this
|
||||
// abstract object. Pipelines may have multiple, SPDY has 0,
|
||||
// normal http transactions have 1.
|
||||
virtual PRUint32 Http1xTransactionCount() = 0;
|
||||
};
|
||||
|
||||
#define NS_DECL_NSAHTTPTRANSACTION \
|
||||
void SetConnection(nsAHttpConnection *); \
|
||||
nsAHttpConnection *Connection(); \
|
||||
void GetSecurityCallbacks(nsIInterfaceRequestor **, \
|
||||
nsIEventTarget **); \
|
||||
void OnTransportStatus(nsITransport* transport, \
|
||||
|
@ -117,8 +110,7 @@ public:
|
|||
nsresult WriteSegments(nsAHttpSegmentWriter *, PRUint32, PRUint32 *); \
|
||||
void Close(nsresult reason); \
|
||||
void SetSSLConnectFailed(); \
|
||||
nsHttpRequestHead *RequestHead(); \
|
||||
PRUint32 Http1xTransactionCount();
|
||||
nsHttpRequestHead *RequestHead();
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsAHttpSegmentReader
|
||||
|
|
|
@ -131,11 +131,6 @@ typedef PRUint8 nsHttpVersion;
|
|||
// host. Used by a forced reload to reset the connection states.
|
||||
#define NS_HTTP_CLEAR_KEEPALIVES (1<<6)
|
||||
|
||||
// Disallow the use of the SPDY protocol. This is meant for the contexts
|
||||
// such as HTTP upgrade which are nonsensical for SPDY, it is not the
|
||||
// SPDY configuration variable.
|
||||
#define NS_HTTP_DISALLOW_SPDY (1<<7)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// some default values
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
@ -56,7 +56,6 @@ HTTP_ATOM(Accept_Language, "Accept-Language")
|
|||
HTTP_ATOM(Accept_Ranges, "Accept-Ranges")
|
||||
HTTP_ATOM(Age, "Age")
|
||||
HTTP_ATOM(Allow, "Allow")
|
||||
HTTP_ATOM(Alternate_Protocol, "Alternate-Protocol")
|
||||
HTTP_ATOM(Authentication, "Authentication")
|
||||
HTTP_ATOM(Authorization, "Authorization")
|
||||
HTTP_ATOM(Cache_Control, "Cache-Control")
|
||||
|
|
|
@ -209,18 +209,6 @@ nsHttpChannel::Connect(bool firstTime)
|
|||
LOG(("nsHttpChannel::Connect() STS permissions found\n"));
|
||||
return AsyncCall(&nsHttpChannel::HandleAsyncRedirectChannelToHttps);
|
||||
}
|
||||
|
||||
// Check for a previous SPDY Alternate-Protocol directive
|
||||
if (gHttpHandler->IsSpdyEnabled() && mAllowSpdy) {
|
||||
nsCAutoString hostPort;
|
||||
|
||||
if (NS_SUCCEEDED(mURI->GetHostPort(hostPort)) &&
|
||||
gHttpHandler->ConnMgr()->GetSpdyAlternateProtocol(hostPort)) {
|
||||
LOG(("nsHttpChannel::Connect() Alternate-Protocol found\n"));
|
||||
return AsyncCall(
|
||||
&nsHttpChannel::HandleAsyncRedirectChannelToHttps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ensure that we are using a valid hostname
|
||||
|
@ -519,9 +507,6 @@ nsHttpChannel::SetupTransaction()
|
|||
}
|
||||
}
|
||||
|
||||
if (!mAllowSpdy)
|
||||
mCaps |= NS_HTTP_DISALLOW_SPDY;
|
||||
|
||||
// use the URI path if not proxying (transparent proxying such as SSL proxy
|
||||
// does not count here). also, figure out what version we should be speaking.
|
||||
nsCAutoString buf, path;
|
||||
|
@ -649,7 +634,6 @@ nsHttpChannel::SetupTransaction()
|
|||
mCaps |= NS_HTTP_STICKY_CONNECTION;
|
||||
mCaps &= ~NS_HTTP_ALLOW_PIPELINING;
|
||||
mCaps &= ~NS_HTTP_ALLOW_KEEPALIVE;
|
||||
mCaps |= NS_HTTP_DISALLOW_SPDY;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAsyncInputStream> responseStream;
|
||||
|
@ -4106,16 +4090,6 @@ nsHttpChannel::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
|
|||
mSecurityInfo = mTransaction->SecurityInfo();
|
||||
}
|
||||
|
||||
if (gHttpHandler->IsSpdyEnabled() && !mCachePump && NS_FAILED(mStatus) &&
|
||||
(mLoadFlags & LOAD_REPLACE) && mOriginalURI && mAllowSpdy) {
|
||||
// For sanity's sake we may want to cancel an alternate protocol
|
||||
// redirection involving the original host name
|
||||
|
||||
nsCAutoString hostPort;
|
||||
if (NS_SUCCEEDED(mOriginalURI->GetHostPort(hostPort)))
|
||||
gHttpHandler->ConnMgr()->RemoveSpdyAlternateProtocol(hostPort);
|
||||
}
|
||||
|
||||
// don't enter this block if we're reading from the cache...
|
||||
if (NS_SUCCEEDED(mStatus) && !mCachePump && mTransaction) {
|
||||
// mTransactionPump doesn't hit OnInputStreamReady and call this until
|
||||
|
|
|
@ -53,9 +53,6 @@
|
|||
#include "nsProxyRelease.h"
|
||||
#include "prmem.h"
|
||||
#include "nsPreloadedStream.h"
|
||||
#include "SpdySession.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "nsISupportsPriority.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
// defined by the socket transport service while active
|
||||
|
@ -78,7 +75,6 @@ nsHttpConnection::nsHttpConnection()
|
|||
, mConsiderReusedAfterEpoch(0)
|
||||
, mCurrentBytesRead(0)
|
||||
, mMaxBytesRead(0)
|
||||
, mTotalBytesRead(0)
|
||||
, mKeepAlive(true) // assume to keep-alive by default
|
||||
, mKeepAliveMask(true)
|
||||
, mSupportsPipelining(false) // assume low-grade server
|
||||
|
@ -86,13 +82,6 @@ nsHttpConnection::nsHttpConnection()
|
|||
, mCompletedProxyConnect(false)
|
||||
, mLastTransactionExpectedNoContent(false)
|
||||
, mIdleMonitoring(false)
|
||||
, mHttp1xTransactionCount(0)
|
||||
, mNPNComplete(false)
|
||||
, mSetupNPNCalled(false)
|
||||
, mUsingSpdy(false)
|
||||
, mPriority(nsISupportsPriority::PRIORITY_NORMAL)
|
||||
, mReportedSpdy(false)
|
||||
, mEverUsedSpdy(false)
|
||||
{
|
||||
LOG(("Creating nsHttpConnection @%x\n", this));
|
||||
|
||||
|
@ -114,24 +103,6 @@ nsHttpConnection::~nsHttpConnection()
|
|||
// release our reference to the handler
|
||||
nsHttpHandler *handler = gHttpHandler;
|
||||
NS_RELEASE(handler);
|
||||
|
||||
if (!mEverUsedSpdy) {
|
||||
LOG(("nsHttpConnection %p performed %d HTTP/1.x transactions\n",
|
||||
this, mHttp1xTransactionCount));
|
||||
mozilla::Telemetry::Accumulate(
|
||||
mozilla::Telemetry::HTTP_REQUEST_PER_CONN, mHttp1xTransactionCount);
|
||||
}
|
||||
|
||||
if (mTotalBytesRead) {
|
||||
PRUint32 totalKBRead = static_cast<PRUint32>(mTotalBytesRead >> 10);
|
||||
LOG(("nsHttpConnection %p read %dkb on connection spdy=%d\n",
|
||||
this, totalKBRead, mEverUsedSpdy));
|
||||
mozilla::Telemetry::Accumulate(
|
||||
mEverUsedSpdy ?
|
||||
mozilla::Telemetry::SPDY_KBREAD_PER_CONN :
|
||||
mozilla::Telemetry::HTTP_KBREAD_PER_CONN,
|
||||
totalKBRead);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -170,79 +141,9 @@ nsHttpConnection::Init(nsHttpConnectionInfo *info,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
nsHttpConnection::EnsureNPNComplete()
|
||||
{
|
||||
// NPN is only used by SPDY right now.
|
||||
//
|
||||
// If for some reason the components to check on NPN aren't available,
|
||||
// this function will just return true to continue on and disable SPDY
|
||||
|
||||
NS_ABORT_IF_FALSE(mSocketTransport, "EnsureNPNComplete "
|
||||
"socket transport precondition");
|
||||
|
||||
if (mNPNComplete)
|
||||
return true;
|
||||
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsISupports> securityInfo;
|
||||
nsCOMPtr<nsISSLSocketControl> ssl;
|
||||
nsCAutoString negotiatedNPN;
|
||||
|
||||
rv = mSocketTransport->GetSecurityInfo(getter_AddRefs(securityInfo));
|
||||
if (NS_FAILED(rv))
|
||||
goto npnComplete;
|
||||
|
||||
ssl = do_QueryInterface(securityInfo, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
goto npnComplete;
|
||||
|
||||
rv = ssl->GetNegotiatedNPN(negotiatedNPN);
|
||||
if (rv == NS_ERROR_NOT_CONNECTED) {
|
||||
|
||||
// By writing 0 bytes to the socket the SSL handshake machine is
|
||||
// pushed forward.
|
||||
PRUint32 count = 0;
|
||||
rv = mSocketOut->Write("", 0, &count);
|
||||
|
||||
if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK)
|
||||
goto npnComplete;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
goto npnComplete;
|
||||
|
||||
LOG(("nsHttpConnection::EnsureNPNComplete %p negotiated to '%s'",
|
||||
this, negotiatedNPN.get()));
|
||||
|
||||
if (negotiatedNPN.Equals(NS_LITERAL_CSTRING("spdy/2"))) {
|
||||
mUsingSpdy = true;
|
||||
mEverUsedSpdy = true;
|
||||
mIsReused = true; /* all spdy streams are reused */
|
||||
|
||||
// Wrap the old http transaction into the new spdy session
|
||||
// as the first stream
|
||||
mSpdySession = new SpdySession(mTransaction,
|
||||
mSocketTransport,
|
||||
mPriority);
|
||||
mTransaction = mSpdySession;
|
||||
mIdleTimeout = gHttpHandler->SpdyTimeout();
|
||||
}
|
||||
|
||||
mozilla::Telemetry::Accumulate(mozilla::Telemetry::SPDY_NPN_CONNECT,
|
||||
mUsingSpdy);
|
||||
|
||||
npnComplete:
|
||||
LOG(("nsHttpConnection::EnsureNPNComplete setting complete to true"));
|
||||
mNPNComplete = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// called on the socket thread
|
||||
nsresult
|
||||
nsHttpConnection::Activate(nsAHttpTransaction *trans, PRUint8 caps, PRInt32 pri)
|
||||
nsHttpConnection::Activate(nsAHttpTransaction *trans, PRUint8 caps)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
|
@ -250,10 +151,6 @@ nsHttpConnection::Activate(nsAHttpTransaction *trans, PRUint8 caps, PRInt32 pri)
|
|||
LOG(("nsHttpConnection::Activate [this=%x trans=%x caps=%x]\n",
|
||||
this, trans, caps));
|
||||
|
||||
mPriority = pri;
|
||||
if (mTransaction && mUsingSpdy)
|
||||
return AddTransaction(trans, pri);
|
||||
|
||||
NS_ENSURE_ARG_POINTER(trans);
|
||||
NS_ENSURE_TRUE(!mTransaction, NS_ERROR_IN_PROGRESS);
|
||||
|
||||
|
@ -269,8 +166,6 @@ nsHttpConnection::Activate(nsAHttpTransaction *trans, PRUint8 caps, PRInt32 pri)
|
|||
mCallbackTarget = callbackTarget;
|
||||
}
|
||||
|
||||
SetupNPN(caps); // only for spdy
|
||||
|
||||
// take ownership of the transaction
|
||||
mTransaction = trans;
|
||||
|
||||
|
@ -303,95 +198,6 @@ failed_activation:
|
|||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnection::SetupNPN(PRUint8 caps)
|
||||
{
|
||||
if (mSetupNPNCalled) /* do only once */
|
||||
return;
|
||||
mSetupNPNCalled = true;
|
||||
|
||||
// Setup NPN Negotiation if necessary (only for SPDY)
|
||||
if (!mNPNComplete) {
|
||||
|
||||
mNPNComplete = true;
|
||||
|
||||
if (mConnInfo->UsingSSL() &&
|
||||
!(caps & NS_HTTP_DISALLOW_SPDY) &&
|
||||
!mConnInfo->UsingHttpProxy() &&
|
||||
gHttpHandler->IsSpdyEnabled()) {
|
||||
LOG(("nsHttpConnection::Init Setting up SPDY Negotiation"));
|
||||
nsCOMPtr<nsISupports> securityInfo;
|
||||
nsresult rv =
|
||||
mSocketTransport->GetSecurityInfo(getter_AddRefs(securityInfo));
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsISSLSocketControl> ssl =
|
||||
do_QueryInterface(securityInfo, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
nsTArray<nsCString> protocolArray;
|
||||
protocolArray.AppendElement(NS_LITERAL_CSTRING("spdy/2"));
|
||||
protocolArray.AppendElement(NS_LITERAL_CSTRING("http/1.1"));
|
||||
if (NS_SUCCEEDED(ssl->SetNPNList(protocolArray))) {
|
||||
LOG(("nsHttpConnection::Init Setting up SPDY Negotiation OK"));
|
||||
mNPNComplete = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnection::HandleAlternateProtocol(nsHttpResponseHead *responseHead)
|
||||
{
|
||||
// Look for the Alternate-Protocol header. Alternate-Protocol is
|
||||
// essentially a way to rediect future transactions from http to
|
||||
// spdy.
|
||||
//
|
||||
|
||||
if (!gHttpHandler->IsSpdyEnabled() || mUsingSpdy)
|
||||
return;
|
||||
|
||||
const char *val = responseHead->PeekHeader(nsHttp::Alternate_Protocol);
|
||||
if (!val)
|
||||
return;
|
||||
|
||||
// The spec allows redirections to any port, but due to concerns over
|
||||
// silently redirecting to stealth ports we only allow port 443
|
||||
//
|
||||
// Alternate-Protocol: 5678:somethingelse, 443:npn-spdy/2
|
||||
|
||||
if (nsHttp::FindToken(val, "443:npn-spdy/2", HTTP_HEADER_VALUE_SEPS)) {
|
||||
LOG(("Connection %p Transaction %p found Alternate-Protocol "
|
||||
"header %s", this, mTransaction.get(), val));
|
||||
gHttpHandler->ConnMgr()->ReportSpdyAlternateProtocol(this);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpConnection::AddTransaction(nsAHttpTransaction *httpTransaction,
|
||||
PRInt32 priority)
|
||||
{
|
||||
LOG(("nsHttpConnection::AddTransaction for SPDY"));
|
||||
|
||||
NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
NS_ABORT_IF_FALSE(mSpdySession && mUsingSpdy,
|
||||
"AddTransaction to live http connection without spdy");
|
||||
NS_ABORT_IF_FALSE(mTransaction,
|
||||
"AddTransaction to idle http connection");
|
||||
|
||||
if (!mSpdySession->AddStream(httpTransaction, priority)) {
|
||||
NS_ABORT_IF_FALSE(0, "AddStream should never fail due to"
|
||||
"RoomForMore() admission check");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
ResumeSend(httpTransaction);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnection::Close(nsresult reason)
|
||||
{
|
||||
|
@ -431,30 +237,13 @@ nsHttpConnection::ProxyStartSSL()
|
|||
return ssl->ProxyStartSSL();
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnection::DontReuse()
|
||||
{
|
||||
mKeepAliveMask = false;
|
||||
mKeepAlive = false;
|
||||
mIdleTimeout = 0;
|
||||
if (mUsingSpdy)
|
||||
mSpdySession->DontReuse();
|
||||
}
|
||||
|
||||
bool
|
||||
nsHttpConnection::CanReuse()
|
||||
{
|
||||
bool canReuse;
|
||||
|
||||
if (mUsingSpdy)
|
||||
canReuse = mSpdySession->CanReuse();
|
||||
else
|
||||
canReuse = IsKeepAlive();
|
||||
|
||||
canReuse = canReuse &&
|
||||
bool canReuse = IsKeepAlive() &&
|
||||
(NowInSeconds() - mLastReadTime < mIdleTimeout) &&
|
||||
IsAlive();
|
||||
|
||||
|
||||
// An idle persistent connection should not have data waiting to be read
|
||||
// before a request is sent. Data here is likely a 408 timeout response
|
||||
// which we would deal with later on through the restart logic, but that
|
||||
|
@ -462,7 +251,7 @@ nsHttpConnection::CanReuse()
|
|||
// be removed with fixing of 631801
|
||||
|
||||
PRUint32 dataSize;
|
||||
if (canReuse && mSocketIn && !mConnInfo->UsingSSL() && !mUsingSpdy &&
|
||||
if (canReuse && mSocketIn && !mConnInfo->UsingSSL() &&
|
||||
NS_SUCCEEDED(mSocketIn->Available(&dataSize)) && dataSize) {
|
||||
LOG(("nsHttpConnection::CanReuse %p %s"
|
||||
"Socket not reusable because read data pending (%d) on it.\n",
|
||||
|
@ -472,16 +261,6 @@ nsHttpConnection::CanReuse()
|
|||
return canReuse;
|
||||
}
|
||||
|
||||
bool
|
||||
nsHttpConnection::CanDirectlyActivate()
|
||||
{
|
||||
// return true if a new transaction can be addded to ths connection at any
|
||||
// time through Activate(). In practice this means this is a healthy SPDY
|
||||
// connection with room for more concurrent streams.
|
||||
|
||||
return UsingSpdy() && CanReuse() && mSpdySession->RoomForMoreStreams();
|
||||
}
|
||||
|
||||
PRUint32 nsHttpConnection::TimeToLive()
|
||||
{
|
||||
PRInt32 tmp = mIdleTimeout - (NowInSeconds() - mLastReadTime);
|
||||
|
@ -497,10 +276,6 @@ nsHttpConnection::IsAlive()
|
|||
if (!mSocketTransport)
|
||||
return false;
|
||||
|
||||
// SocketTransport::IsAlive can run the SSL state machine, so make sure
|
||||
// the NPN options are set before that happens.
|
||||
SetupNPN(0);
|
||||
|
||||
bool alive;
|
||||
nsresult rv = mSocketTransport->IsAlive(&alive);
|
||||
if (NS_FAILED(rv))
|
||||
|
@ -520,10 +295,6 @@ nsHttpConnection::IsAlive()
|
|||
bool
|
||||
nsHttpConnection::SupportsPipelining(nsHttpResponseHead *responseHead)
|
||||
{
|
||||
// SPDY supports infinite parallelism, so no need to pipeline.
|
||||
if (mUsingSpdy)
|
||||
return false;
|
||||
|
||||
// XXX there should be a strict mode available that disables this
|
||||
// blacklisting.
|
||||
|
||||
|
@ -649,30 +420,20 @@ nsHttpConnection::OnHeadersAvailable(nsAHttpTransaction *trans,
|
|||
if (mKeepAlive) {
|
||||
val = responseHead->PeekHeader(nsHttp::Keep_Alive);
|
||||
|
||||
if (!mUsingSpdy) {
|
||||
const char *cp = PL_strcasestr(val, "timeout=");
|
||||
if (cp)
|
||||
mIdleTimeout = (PRUint32) atoi(cp + 8);
|
||||
else
|
||||
mIdleTimeout = gHttpHandler->IdleTimeout();
|
||||
}
|
||||
else {
|
||||
mIdleTimeout = gHttpHandler->SpdyTimeout();
|
||||
}
|
||||
const char *cp = PL_strcasestr(val, "timeout=");
|
||||
if (cp)
|
||||
mIdleTimeout = (PRUint32) atoi(cp + 8);
|
||||
else
|
||||
mIdleTimeout = gHttpHandler->IdleTimeout();
|
||||
|
||||
LOG(("Connection can be reused [this=%x idle-timeout=%u]\n", this, mIdleTimeout));
|
||||
}
|
||||
|
||||
if (!mProxyConnectStream)
|
||||
HandleAlternateProtocol(responseHead);
|
||||
|
||||
// if we're doing an SSL proxy connect, then we need to check whether or not
|
||||
// the connect was successful. if so, then we have to reset the transaction
|
||||
// and step-up the socket connection to SSL. finally, we have to wake up the
|
||||
// socket write request.
|
||||
if (mProxyConnectStream) {
|
||||
NS_ABORT_IF_FALSE(!mUsingSpdy,
|
||||
"SPDY NPN Complete while using proxy connect stream");
|
||||
mProxyConnectStream = 0;
|
||||
if (responseHead->Status() == 200) {
|
||||
LOG(("proxy CONNECT succeeded! ssl=%s\n",
|
||||
|
@ -745,8 +506,6 @@ nsHttpConnection::TakeTransport(nsISocketTransport **aTransport,
|
|||
nsIAsyncInputStream **aInputStream,
|
||||
nsIAsyncOutputStream **aOutputStream)
|
||||
{
|
||||
if (mUsingSpdy)
|
||||
return NS_ERROR_FAILURE;
|
||||
if (mTransaction && !mTransaction->IsDone())
|
||||
return NS_ERROR_IN_PROGRESS;
|
||||
if (!(mSocketTransport && mSocketIn && mSocketOut))
|
||||
|
@ -794,7 +553,7 @@ nsHttpConnection::PushBack(const char *data, PRUint32 length)
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsHttpConnection::ResumeSend(nsAHttpTransaction *)
|
||||
nsHttpConnection::ResumeSend()
|
||||
{
|
||||
LOG(("nsHttpConnection::ResumeSend [this=%p]\n", this));
|
||||
|
||||
|
@ -808,7 +567,7 @@ nsHttpConnection::ResumeSend(nsAHttpTransaction *)
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsHttpConnection::ResumeRecv(nsAHttpTransaction *)
|
||||
nsHttpConnection::ResumeRecv()
|
||||
{
|
||||
LOG(("nsHttpConnection::ResumeRecv [this=%p]\n", this));
|
||||
|
||||
|
@ -827,8 +586,7 @@ nsHttpConnection::BeginIdleMonitoring()
|
|||
LOG(("nsHttpConnection::BeginIdleMonitoring [this=%p]\n", this));
|
||||
NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
NS_ABORT_IF_FALSE(!mTransaction, "BeginIdleMonitoring() while active");
|
||||
NS_ABORT_IF_FALSE(!mUsingSpdy, "Idle monitoring of spdy not allowed");
|
||||
|
||||
|
||||
LOG(("Entering Idle Monitoring Mode [this=%p]", this));
|
||||
mIdleMonitoring = true;
|
||||
if (mSocketIn)
|
||||
|
@ -870,15 +628,6 @@ nsHttpConnection::CloseTransaction(nsAHttpTransaction *trans, nsresult reason)
|
|||
if (reason == NS_BASE_STREAM_CLOSED)
|
||||
reason = NS_OK;
|
||||
|
||||
if (mUsingSpdy) {
|
||||
DontReuse();
|
||||
// if !mSpdySession then mUsingSpdy must be false for canreuse()
|
||||
mUsingSpdy = false;
|
||||
mSpdySession = nsnull;
|
||||
}
|
||||
|
||||
mHttp1xTransactionCount += mTransaction->Http1xTransactionCount();
|
||||
|
||||
mTransaction->Close(reason);
|
||||
mTransaction = nsnull;
|
||||
|
||||
|
@ -943,8 +692,6 @@ nsHttpConnection::OnSocketWritable()
|
|||
bool again = true;
|
||||
|
||||
do {
|
||||
mSocketOutCondition = NS_OK;
|
||||
|
||||
// if we're doing an SSL proxy connect, then we need to bypass calling
|
||||
// into the transaction.
|
||||
//
|
||||
|
@ -958,26 +705,7 @@ nsHttpConnection::OnSocketWritable()
|
|||
nsIOService::gDefaultSegmentSize,
|
||||
&n);
|
||||
}
|
||||
else if (!EnsureNPNComplete()) {
|
||||
// When SPDY is disabled this branch is not executed because Activate()
|
||||
// sets mNPNComplete to true in that case.
|
||||
|
||||
// We are ready to proceed with SSL but the handshake is not done.
|
||||
// When using NPN to negotiate between HTTPS and SPDY, we need to
|
||||
// see the results of the handshake to know what bytes to send, so
|
||||
// we cannot proceed with the request headers.
|
||||
|
||||
rv = NS_OK;
|
||||
mSocketOutCondition = NS_BASE_STREAM_WOULD_BLOCK;
|
||||
n = 0;
|
||||
}
|
||||
else {
|
||||
if (gHttpHandler->IsSpdyEnabled() && !mReportedSpdy) {
|
||||
mReportedSpdy = true;
|
||||
gHttpHandler->ConnMgr()->
|
||||
ReportSpdyConnection(this, mUsingSpdy);
|
||||
}
|
||||
|
||||
LOG((" writing transaction request stream\n"));
|
||||
rv = mTransaction->ReadSegments(this, nsIOService::gDefaultSegmentSize, &n);
|
||||
}
|
||||
|
@ -1080,7 +808,6 @@ nsHttpConnection::OnSocketReadable()
|
|||
}
|
||||
else {
|
||||
mCurrentBytesRead += n;
|
||||
mTotalBytesRead += n;
|
||||
if (NS_FAILED(mSocketInCondition)) {
|
||||
// continue waiting for the socket if necessary...
|
||||
if (mSocketInCondition == NS_BASE_STREAM_WOULD_BLOCK)
|
||||
|
@ -1104,8 +831,6 @@ nsHttpConnection::SetupProxyConnect()
|
|||
LOG(("nsHttpConnection::SetupProxyConnect [this=%x]\n", this));
|
||||
|
||||
NS_ENSURE_TRUE(!mProxyConnectStream, NS_ERROR_ALREADY_INITIALIZED);
|
||||
NS_ABORT_IF_FALSE(!mUsingSpdy,
|
||||
"SPDY NPN Complete while using proxy connect stream");
|
||||
|
||||
nsCAutoString buf;
|
||||
nsresult rv = nsHttpHandler::GenerateHostPort(
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
#include "nsCOMPtr.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "prinrval.h"
|
||||
#include "SpdySession.h"
|
||||
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsISocketTransport.h"
|
||||
|
@ -93,9 +92,8 @@ public:
|
|||
nsIEventTarget *);
|
||||
|
||||
// Activate causes the given transaction to be processed on this
|
||||
// connection. It fails if there is already an existing transaction unless
|
||||
// a multiplexing protocol such as SPDY is being used
|
||||
nsresult Activate(nsAHttpTransaction *, PRUint8 caps, PRInt32 pri);
|
||||
// connection. It fails if there is already an existing transaction.
|
||||
nsresult Activate(nsAHttpTransaction *, PRUint8 caps);
|
||||
|
||||
// Close the underlying socket transport.
|
||||
void Close(nsresult reason);
|
||||
|
@ -104,15 +102,15 @@ public:
|
|||
// XXX document when these are ok to call
|
||||
|
||||
bool SupportsPipelining() { return mSupportsPipelining; }
|
||||
bool IsKeepAlive() { return mUsingSpdy ||
|
||||
(mKeepAliveMask && mKeepAlive); }
|
||||
bool IsKeepAlive() { return mKeepAliveMask && mKeepAlive; }
|
||||
bool CanReuse(); // can this connection be reused?
|
||||
bool CanDirectlyActivate();
|
||||
|
||||
// Returns time in seconds for how long connection can be reused.
|
||||
PRUint32 TimeToLive();
|
||||
|
||||
void DontReuse();
|
||||
void DontReuse() { mKeepAliveMask = false;
|
||||
mKeepAlive = false;
|
||||
mIdleTimeout = 0; }
|
||||
void DropTransport() { DontReuse(); mSocketTransport = 0; }
|
||||
|
||||
bool LastTransactionExpectedNoContent()
|
||||
|
@ -142,8 +140,8 @@ public:
|
|||
void SetIsReusedAfter(PRUint32 afterMilliseconds);
|
||||
void SetIdleTimeout(PRUint16 val) {mIdleTimeout = val;}
|
||||
nsresult PushBack(const char *data, PRUint32 length);
|
||||
nsresult ResumeSend(nsAHttpTransaction *caller);
|
||||
nsresult ResumeRecv(nsAHttpTransaction *caller);
|
||||
nsresult ResumeSend();
|
||||
nsresult ResumeRecv();
|
||||
PRInt64 MaxBytesRead() {return mMaxBytesRead;}
|
||||
|
||||
static NS_METHOD ReadFromStream(nsIInputStream *, void *, const char *,
|
||||
|
@ -156,8 +154,6 @@ public:
|
|||
void BeginIdleMonitoring();
|
||||
void EndIdleMonitoring();
|
||||
|
||||
bool UsingSpdy() { return mUsingSpdy; }
|
||||
|
||||
private:
|
||||
// called to cause the underlying socket to start speaking SSL
|
||||
nsresult ProxyStartSSL();
|
||||
|
@ -171,18 +167,6 @@ private:
|
|||
bool IsAlive();
|
||||
bool SupportsPipelining(nsHttpResponseHead *);
|
||||
|
||||
// Makes certain the SSL handshake is complete and NPN negotiation
|
||||
// has had a chance to happen
|
||||
bool EnsureNPNComplete();
|
||||
void SetupNPN(PRUint8 caps);
|
||||
|
||||
// Inform the connection manager of any SPDY Alternate-Protocol
|
||||
// redirections
|
||||
void HandleAlternateProtocol(nsHttpResponseHead *);
|
||||
|
||||
// Directly Add a transaction to an active connection for SPDY
|
||||
nsresult AddTransaction(nsAHttpTransaction *, PRInt32);
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsISocketTransport> mSocketTransport;
|
||||
nsCOMPtr<nsIAsyncInputStream> mSocketIn;
|
||||
|
@ -210,7 +194,6 @@ private:
|
|||
PRIntervalTime mConsiderReusedAfterEpoch;
|
||||
PRInt64 mCurrentBytesRead; // data read per activation
|
||||
PRInt64 mMaxBytesRead; // max read in 1 activation
|
||||
PRInt64 mTotalBytesRead; // total data read
|
||||
|
||||
nsRefPtr<nsIAsyncInputStream> mInputOverflow;
|
||||
|
||||
|
@ -221,21 +204,6 @@ private:
|
|||
bool mCompletedProxyConnect;
|
||||
bool mLastTransactionExpectedNoContent;
|
||||
bool mIdleMonitoring;
|
||||
|
||||
// The number of <= HTTP/1.1 transactions performed on this connection. This
|
||||
// excludes spdy transactions.
|
||||
PRUint32 mHttp1xTransactionCount;
|
||||
|
||||
// SPDY related
|
||||
bool mNPNComplete;
|
||||
bool mSetupNPNCalled;
|
||||
bool mUsingSpdy;
|
||||
nsRefPtr<mozilla::net::SpdySession> mSpdySession;
|
||||
PRInt32 mPriority;
|
||||
bool mReportedSpdy;
|
||||
|
||||
// mUsingSpdy is cleared when mSpdySession is freed, this is permanent
|
||||
bool mEverUsedSpdy;
|
||||
};
|
||||
|
||||
#endif // nsHttpConnection_h__
|
||||
|
|
|
@ -124,9 +124,7 @@ public:
|
|||
PRInt32 DefaultPort() const { return mUsingSSL ? NS_HTTPS_DEFAULT_PORT : NS_HTTP_DEFAULT_PORT; }
|
||||
void SetAnonymous(bool anon)
|
||||
{ mHashKey.SetCharAt(anon ? 'A' : '.', 2); }
|
||||
bool GetAnonymous() { return mHashKey.CharAt(2) == 'A'; }
|
||||
bool ShouldForceConnectMethod();
|
||||
const nsCString &GetHost() { return mHost; }
|
||||
|
||||
private:
|
||||
nsrefcnt mRef;
|
||||
|
|
|
@ -48,10 +48,6 @@
|
|||
|
||||
#include "nsIObserverService.h"
|
||||
|
||||
#include "nsISSLSocketControl.h"
|
||||
#include "prnetdb.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
// defined by the socket transport service while active
|
||||
|
@ -98,7 +94,6 @@ nsHttpConnectionMgr::nsHttpConnectionMgr()
|
|||
{
|
||||
LOG(("Creating nsHttpConnectionMgr @%x\n", this));
|
||||
mCT.Init();
|
||||
mAlternateProtocolHash.Init(16);
|
||||
}
|
||||
|
||||
nsHttpConnectionMgr::~nsHttpConnectionMgr()
|
||||
|
@ -145,7 +140,6 @@ nsHttpConnectionMgr::Init(PRUint16 maxConns,
|
|||
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
mSpdyPreferredHash.Init();
|
||||
|
||||
mMaxConns = maxConns;
|
||||
mMaxConnsPerHost = maxConnsPerHost;
|
||||
|
@ -235,13 +229,8 @@ nsHttpConnectionMgr::PruneDeadConnectionsAfter(PRUint32 timeInSeconds)
|
|||
}
|
||||
|
||||
void
|
||||
nsHttpConnectionMgr::ConditionallyStopPruneDeadConnectionsTimer()
|
||||
nsHttpConnectionMgr::StopPruneDeadConnectionsTimer()
|
||||
{
|
||||
// Leave the timer in place if there are connections that potentially
|
||||
// need management
|
||||
if (mNumIdleConns || (mNumActiveConns && gHttpHandler->IsSpdyEnabled()))
|
||||
return;
|
||||
|
||||
LOG(("nsHttpConnectionMgr::StopPruneDeadConnectionsTimer\n"));
|
||||
|
||||
// Reset mTimeOfNextWakeUp so that we can find a new shortest value.
|
||||
|
@ -400,50 +389,6 @@ nsHttpConnectionMgr::ProcessPendingQ(nsHttpConnectionInfo *ci)
|
|||
return rv;
|
||||
}
|
||||
|
||||
// Given a nsHttpConnectionInfo find the connection entry object that
|
||||
// contains either the nshttpconnection or nshttptransaction parameter.
|
||||
// Normally this is done by the hashkey lookup of connectioninfo,
|
||||
// but if spdy coalescing is in play it might be found in a redirected
|
||||
// entry
|
||||
nsHttpConnectionMgr::nsConnectionEntry *
|
||||
nsHttpConnectionMgr::LookupConnectionEntry(nsHttpConnectionInfo *ci,
|
||||
nsHttpConnection *conn,
|
||||
nsHttpTransaction *trans)
|
||||
{
|
||||
if (!ci)
|
||||
return nsnull;
|
||||
|
||||
nsConnectionEntry *ent = mCT.Get(ci->HashKey());
|
||||
|
||||
// If there is no sign of coalescing (or it is disabled) then just
|
||||
// return the primary hash lookup
|
||||
if (!gHttpHandler->IsSpdyEnabled() || !gHttpHandler->CoalesceSpdy() ||
|
||||
!ent || !ent->mUsingSpdy || ent->mCoalescingKey.IsEmpty())
|
||||
return ent;
|
||||
|
||||
// If there is no preferred coalescing entry for this host (or the
|
||||
// preferred entry is the one that matched the mCT hash lookup) then
|
||||
// there is only option
|
||||
nsConnectionEntry *preferred = mSpdyPreferredHash.Get(ent->mCoalescingKey);
|
||||
if (!preferred || (preferred == ent))
|
||||
return ent;
|
||||
|
||||
if (conn) {
|
||||
// The connection could be either in preferred or ent. It is most
|
||||
// likely the only active connection in preferred - so start with that.
|
||||
if (preferred->mActiveConns.Contains(conn))
|
||||
return preferred;
|
||||
if (preferred->mIdleConns.Contains(conn))
|
||||
return preferred;
|
||||
}
|
||||
|
||||
if (trans && preferred->mPendingQ.Contains(trans))
|
||||
return preferred;
|
||||
|
||||
// Neither conn nor trans found in preferred, use the default entry
|
||||
return ent;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpConnectionMgr::CloseIdleConnection(nsHttpConnection *conn)
|
||||
{
|
||||
|
@ -451,11 +396,11 @@ nsHttpConnectionMgr::CloseIdleConnection(nsHttpConnection *conn)
|
|||
LOG(("nsHttpConnectionMgr::CloseIdleConnection %p conn=%p",
|
||||
this, conn));
|
||||
|
||||
if (!conn->ConnectionInfo())
|
||||
nsHttpConnectionInfo *ci = conn->ConnectionInfo();
|
||||
if (!ci)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
nsConnectionEntry *ent = LookupConnectionEntry(conn->ConnectionInfo(),
|
||||
conn, nsnull);
|
||||
nsConnectionEntry *ent = mCT.Get(ci->HashKey());
|
||||
|
||||
if (!ent || !ent->mIdleConns.RemoveElement(conn))
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
@ -463,241 +408,11 @@ nsHttpConnectionMgr::CloseIdleConnection(nsHttpConnection *conn)
|
|||
conn->Close(NS_ERROR_ABORT);
|
||||
NS_RELEASE(conn);
|
||||
mNumIdleConns--;
|
||||
ConditionallyStopPruneDeadConnectionsTimer();
|
||||
if (0 == mNumIdleConns)
|
||||
StopPruneDeadConnectionsTimer();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnectionMgr::ReportSpdyConnection(nsHttpConnection *conn,
|
||||
bool usingSpdy)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
|
||||
nsConnectionEntry *ent = LookupConnectionEntry(conn->ConnectionInfo(),
|
||||
conn, nsnull);
|
||||
|
||||
NS_ABORT_IF_FALSE(ent, "no connection entry");
|
||||
if (!ent)
|
||||
return;
|
||||
|
||||
ent->mTestedSpdy = true;
|
||||
|
||||
if (!usingSpdy) {
|
||||
if (ent->mUsingSpdy)
|
||||
conn->DontReuse();
|
||||
return;
|
||||
}
|
||||
|
||||
ent->mUsingSpdy = true;
|
||||
|
||||
PRUint32 ttl = conn->TimeToLive();
|
||||
PRUint64 timeOfExpire = NowInSeconds() + ttl;
|
||||
if (!mTimer || timeOfExpire < mTimeOfNextWakeUp)
|
||||
PruneDeadConnectionsAfter(ttl);
|
||||
|
||||
// Lookup preferred directly from the hash instead of using
|
||||
// GetSpdyPreferred() because we want to avoid the cert compatibility
|
||||
// check at this point because the cert is never part of the hash
|
||||
// lookup. Filtering on that has to be done at the time of use
|
||||
// rather than the time of registration (i.e. now).
|
||||
nsConnectionEntry *preferred =
|
||||
mSpdyPreferredHash.Get(ent->mCoalescingKey);
|
||||
|
||||
LOG(("ReportSpdyConnection %s %s ent=%p ispreferred=%d\n",
|
||||
ent->mConnInfo->Host(), ent->mCoalescingKey.get(),
|
||||
ent, preferred));
|
||||
|
||||
if (!preferred) {
|
||||
ent->mSpdyPreferred = true;
|
||||
SetSpdyPreferred(ent);
|
||||
preferred = ent;
|
||||
}
|
||||
else if (preferred != ent) {
|
||||
// A different hostname is the preferred spdy host for this
|
||||
// IP address.
|
||||
ent->mUsingSpdy = true;
|
||||
conn->DontReuse();
|
||||
}
|
||||
|
||||
ProcessSpdyPendingQ();
|
||||
}
|
||||
|
||||
bool
|
||||
nsHttpConnectionMgr::GetSpdyAlternateProtocol(nsACString &hostPortKey)
|
||||
{
|
||||
// The Alternate Protocol hash is protected under the monitor because
|
||||
// it is read from both the main and the network thread.
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
return mAlternateProtocolHash.Contains(hostPortKey);
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnectionMgr::ReportSpdyAlternateProtocol(nsHttpConnection *conn)
|
||||
{
|
||||
// Check network.http.spdy.use-alternate-protocol pref
|
||||
if (!gHttpHandler->UseAlternateProtocol())
|
||||
return;
|
||||
|
||||
// For now lets not bypass proxies due to the alternate-protocol header
|
||||
if (conn->ConnectionInfo()->UsingHttpProxy())
|
||||
return;
|
||||
|
||||
nsCString hostPortKey(conn->ConnectionInfo()->Host());
|
||||
if (conn->ConnectionInfo()->Port() != 80) {
|
||||
hostPortKey.Append(NS_LITERAL_CSTRING(":"));
|
||||
hostPortKey.AppendInt(conn->ConnectionInfo()->Port());
|
||||
}
|
||||
|
||||
// The Alternate Protocol hash is protected under the monitor because
|
||||
// it is read from both the main and the network thread.
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
// Check to see if this is already present
|
||||
if (mAlternateProtocolHash.Contains(hostPortKey))
|
||||
return;
|
||||
|
||||
if (mAlternateProtocolHash.mHashTable.entryCount > 2000)
|
||||
PL_DHashTableEnumerate(&mAlternateProtocolHash.mHashTable,
|
||||
&nsHttpConnectionMgr::TrimAlternateProtocolHash,
|
||||
this);
|
||||
|
||||
mAlternateProtocolHash.Put(hostPortKey);
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnectionMgr::RemoveSpdyAlternateProtocol(nsACString &hostPortKey)
|
||||
{
|
||||
// The Alternate Protocol hash is protected under the monitor because
|
||||
// it is read from both the main and the network thread.
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
return mAlternateProtocolHash.Remove(hostPortKey);
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
nsHttpConnectionMgr::TrimAlternateProtocolHash(PLDHashTable *table,
|
||||
PLDHashEntryHdr *hdr,
|
||||
PRUint32 number,
|
||||
void *closure)
|
||||
{
|
||||
nsHttpConnectionMgr *self = (nsHttpConnectionMgr *) closure;
|
||||
|
||||
if (self->mAlternateProtocolHash.mHashTable.entryCount > 2000)
|
||||
return PL_DHASH_REMOVE;
|
||||
return PL_DHASH_STOP;
|
||||
}
|
||||
|
||||
nsHttpConnectionMgr::nsConnectionEntry *
|
||||
nsHttpConnectionMgr::GetSpdyPreferred(nsConnectionEntry *aOriginalEntry)
|
||||
{
|
||||
if (!gHttpHandler->IsSpdyEnabled() ||
|
||||
!gHttpHandler->CoalesceSpdy() ||
|
||||
aOriginalEntry->mCoalescingKey.IsEmpty())
|
||||
return nsnull;
|
||||
|
||||
nsConnectionEntry *preferred =
|
||||
mSpdyPreferredHash.Get(aOriginalEntry->mCoalescingKey);
|
||||
|
||||
// if there is no redirection no cert validation is required
|
||||
if (preferred == aOriginalEntry)
|
||||
return aOriginalEntry;
|
||||
|
||||
// if there is no preferred host or it is no longer using spdy
|
||||
// then skip pooling
|
||||
if (!preferred || !preferred->mUsingSpdy)
|
||||
return nsnull;
|
||||
|
||||
// if there is not an active spdy session in this entry then
|
||||
// we cannot pool because the cert upon activation may not
|
||||
// be the same as the old one. Active sessions are prohibited
|
||||
// from changing certs.
|
||||
|
||||
nsHttpConnection *activeSpdy = nsnull;
|
||||
|
||||
for (PRUint32 index = 0; index < preferred->mActiveConns.Length(); ++index) {
|
||||
if (preferred->mActiveConns[index]->CanDirectlyActivate()) {
|
||||
activeSpdy = preferred->mActiveConns[index];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!activeSpdy) {
|
||||
// remove the preferred status of this entry if it cannot be
|
||||
// used for pooling.
|
||||
preferred->mSpdyPreferred = false;
|
||||
RemoveSpdyPreferred(preferred->mCoalescingKey);
|
||||
LOG(("nsHttpConnectionMgr::GetSpdyPreferredConnection "
|
||||
"preferred host mapping %s to %s removed due to inactivity.\n",
|
||||
aOriginalEntry->mConnInfo->Host(),
|
||||
preferred->mConnInfo->Host()));
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// Check that the server cert supports redirection
|
||||
nsresult rv;
|
||||
bool isJoined = false;
|
||||
|
||||
nsCOMPtr<nsISupports> securityInfo;
|
||||
nsCOMPtr<nsISSLSocketControl> sslSocketControl;
|
||||
nsCAutoString negotiatedNPN;
|
||||
|
||||
activeSpdy->GetSecurityInfo(getter_AddRefs(securityInfo));
|
||||
if (!securityInfo)
|
||||
return nsnull;
|
||||
|
||||
sslSocketControl = do_QueryInterface(securityInfo, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return nsnull;
|
||||
|
||||
rv = sslSocketControl->JoinConnection(NS_LITERAL_CSTRING("spdy/2"),
|
||||
aOriginalEntry->mConnInfo->GetHost(),
|
||||
aOriginalEntry->mConnInfo->Port(),
|
||||
&isJoined);
|
||||
|
||||
if (NS_FAILED(rv) || !isJoined) {
|
||||
LOG(("nsHttpConnectionMgr::GetSpdyPreferredConnection "
|
||||
"Host %s cannot be confirmed to be joined "
|
||||
"with %s connections",
|
||||
preferred->mConnInfo->Host(), aOriginalEntry->mConnInfo->Host()));
|
||||
mozilla::Telemetry::Accumulate(mozilla::Telemetry::SPDY_NPN_JOIN,
|
||||
false);
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// IP pooling confirmed
|
||||
LOG(("nsHttpConnectionMgr::GetSpdyPreferredConnection "
|
||||
"Host %s has cert valid for %s connections",
|
||||
preferred->mConnInfo->Host(), aOriginalEntry->mConnInfo->Host()));
|
||||
mozilla::Telemetry::Accumulate(mozilla::Telemetry::SPDY_NPN_JOIN, true);
|
||||
return preferred;
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnectionMgr::SetSpdyPreferred(nsConnectionEntry *ent)
|
||||
{
|
||||
if (!gHttpHandler->CoalesceSpdy())
|
||||
return;
|
||||
|
||||
if (ent->mCoalescingKey.IsEmpty())
|
||||
return;
|
||||
|
||||
mSpdyPreferredHash.Put(ent->mCoalescingKey, ent);
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnectionMgr::RemoveSpdyPreferred(nsACString &aHashKey)
|
||||
{
|
||||
if (!gHttpHandler->CoalesceSpdy())
|
||||
return;
|
||||
|
||||
if (aHashKey.IsEmpty())
|
||||
return;
|
||||
|
||||
mSpdyPreferredHash.Remove(aHashKey);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// enumeration callbacks
|
||||
|
||||
|
@ -734,7 +449,8 @@ nsHttpConnectionMgr::PurgeExcessIdleConnectionsCB(const nsACString &key,
|
|||
conn->Close(NS_ERROR_ABORT);
|
||||
NS_RELEASE(conn);
|
||||
self->mNumIdleConns--;
|
||||
self->ConditionallyStopPruneDeadConnectionsTimer();
|
||||
if (0 == self->mNumIdleConns)
|
||||
self->StopPruneDeadConnectionsTimer();
|
||||
}
|
||||
return PL_DHASH_STOP;
|
||||
}
|
||||
|
@ -750,7 +466,6 @@ nsHttpConnectionMgr::PruneDeadConnectionsCB(const nsACString &key,
|
|||
|
||||
// Find out how long it will take for next idle connection to not be reusable
|
||||
// anymore.
|
||||
bool liveConnections = false;
|
||||
PRUint32 timeToNextExpire = PR_UINT32_MAX;
|
||||
PRInt32 count = ent->mIdleConns.Length();
|
||||
if (count > 0) {
|
||||
|
@ -763,33 +478,14 @@ nsHttpConnectionMgr::PruneDeadConnectionsCB(const nsACString &key,
|
|||
self->mNumIdleConns--;
|
||||
} else {
|
||||
timeToNextExpire = NS_MIN(timeToNextExpire, conn->TimeToLive());
|
||||
liveConnections = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ent->mUsingSpdy) {
|
||||
for (PRUint32 index = 0; index < ent->mActiveConns.Length(); ++index) {
|
||||
nsHttpConnection *conn = ent->mActiveConns[index];
|
||||
if (conn->UsingSpdy()) {
|
||||
if (!conn->CanReuse()) {
|
||||
// marking it dont reuse will create an active tear down if
|
||||
// the spdy session is idle.
|
||||
conn->DontReuse();
|
||||
}
|
||||
else {
|
||||
timeToNextExpire = NS_MIN(timeToNextExpire,
|
||||
conn->TimeToLive());
|
||||
liveConnections = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If time to next expire found is shorter than time to next wake-up, we need to
|
||||
// change the time for next wake-up.
|
||||
if (liveConnections) {
|
||||
PRUint32 now = NowInSeconds();
|
||||
PRUint32 now = NowInSeconds();
|
||||
if (0 < ent->mIdleConns.Length()) {
|
||||
PRUint64 timeOfNextExpire = now + timeToNextExpire;
|
||||
// If pruning of dead connections is not already scheduled to happen
|
||||
// or time found for next connection to expire is is before
|
||||
|
@ -798,8 +494,8 @@ nsHttpConnectionMgr::PruneDeadConnectionsCB(const nsACString &key,
|
|||
if (!self->mTimer || timeOfNextExpire < self->mTimeOfNextWakeUp) {
|
||||
self->PruneDeadConnectionsAfter(timeToNextExpire);
|
||||
}
|
||||
} else {
|
||||
self->ConditionallyStopPruneDeadConnectionsTimer();
|
||||
} else if (0 == self->mNumIdleConns) {
|
||||
self->StopPruneDeadConnectionsTimer();
|
||||
}
|
||||
#ifdef DEBUG
|
||||
count = ent->mActiveConns.Length();
|
||||
|
@ -815,10 +511,7 @@ nsHttpConnectionMgr::PruneDeadConnectionsCB(const nsACString &key,
|
|||
if (ent->mIdleConns.Length() == 0 &&
|
||||
ent->mActiveConns.Length() == 0 &&
|
||||
ent->mHalfOpens.Length() == 0 &&
|
||||
ent->mPendingQ.Length() == 0 &&
|
||||
((!ent->mTestedSpdy && !ent->mUsingSpdy) ||
|
||||
!gHttpHandler->IsSpdyEnabled() ||
|
||||
self->mCT.Count() > 300)) {
|
||||
ent->mPendingQ.Length() == 0) {
|
||||
LOG((" removing empty connection entry\n"));
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
@ -864,7 +557,8 @@ nsHttpConnectionMgr::ShutdownPassCB(const nsACString &key,
|
|||
}
|
||||
// If all idle connections are removed,
|
||||
// we can stop pruning dead connections.
|
||||
self->ConditionallyStopPruneDeadConnectionsTimer();
|
||||
if (0 == self->mNumIdleConns)
|
||||
self->StopPruneDeadConnectionsTimer();
|
||||
|
||||
// close all pending transactions
|
||||
while (ent->mPendingQ.Length()) {
|
||||
|
@ -888,19 +582,15 @@ nsHttpConnectionMgr::ShutdownPassCB(const nsACString &key,
|
|||
bool
|
||||
nsHttpConnectionMgr::ProcessPendingQForEntry(nsConnectionEntry *ent)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
LOG(("nsHttpConnectionMgr::ProcessPendingQForEntry [ci=%s]\n",
|
||||
ent->mConnInfo->HashKey().get()));
|
||||
|
||||
if (gHttpHandler->IsSpdyEnabled())
|
||||
ProcessSpdyPendingQ(ent);
|
||||
|
||||
PRUint32 i, count = ent->mPendingQ.Length();
|
||||
PRInt32 i, count = ent->mPendingQ.Length();
|
||||
if (count > 0) {
|
||||
LOG((" pending-count=%u\n", count));
|
||||
nsHttpTransaction *trans = nsnull;
|
||||
nsHttpConnection *conn = nsnull;
|
||||
for (i = 0; i < count; ++i) {
|
||||
for (i=0; i<count; ++i) {
|
||||
trans = ent->mPendingQ[i];
|
||||
|
||||
// When this transaction has already established a half-open
|
||||
|
@ -919,13 +609,6 @@ nsHttpConnectionMgr::ProcessPendingQForEntry(nsConnectionEntry *ent)
|
|||
GetConnection(ent, trans, alreadyHalfOpen, &conn);
|
||||
if (conn)
|
||||
break;
|
||||
|
||||
// Check to see if a pending transaction was dispatched with the
|
||||
// coalesce logic
|
||||
if (count != ent->mPendingQ.Length()) {
|
||||
count = ent->mPendingQ.Length();
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
if (conn) {
|
||||
LOG((" dispatching pending transaction...\n"));
|
||||
|
@ -1053,8 +736,7 @@ nsHttpConnectionMgr::GetConnection(nsConnectionEntry *ent,
|
|||
LOG(("nsHttpConnectionMgr::GetConnection [ci=%s caps=%x]\n",
|
||||
ent->mConnInfo->HashKey().get(), PRUint32(trans->Caps())));
|
||||
|
||||
// First, see if an existing connection can be used - either an idle
|
||||
// persistent connection or an active spdy session may be reused instead of
|
||||
// First, see if an idle persistent connection may be reused instead of
|
||||
// establishing a new socket. We do not need to check the connection limits
|
||||
// yet as they govern the maximum number of open connections and reusing
|
||||
// an old connection never increases that.
|
||||
|
@ -1062,18 +744,8 @@ nsHttpConnectionMgr::GetConnection(nsConnectionEntry *ent,
|
|||
*result = nsnull;
|
||||
|
||||
nsHttpConnection *conn = nsnull;
|
||||
bool addConnToActiveList = true;
|
||||
|
||||
if (trans->Caps() & NS_HTTP_ALLOW_KEEPALIVE) {
|
||||
|
||||
// if willing to use spdy look for an active spdy connections
|
||||
// before considering idle http ones.
|
||||
if (gHttpHandler->IsSpdyEnabled()) {
|
||||
conn = GetSpdyPreferredConn(ent);
|
||||
if (conn)
|
||||
addConnToActiveList = false;
|
||||
}
|
||||
|
||||
// search the idle connection list. Each element in the list
|
||||
// has a reference, so if we remove it from the list into a local
|
||||
// ptr, that ptr now owns the reference
|
||||
|
@ -1096,7 +768,8 @@ nsHttpConnectionMgr::GetConnection(nsConnectionEntry *ent,
|
|||
|
||||
// If there are no idle connections left at all, we need to make
|
||||
// sure that we are not pruning dead connections anymore.
|
||||
ConditionallyStopPruneDeadConnectionsTimer();
|
||||
if (0 == mNumIdleConns)
|
||||
StopPruneDeadConnectionsTimer();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1107,19 +780,6 @@ nsHttpConnectionMgr::GetConnection(nsConnectionEntry *ent,
|
|||
if (onlyReusedConnection)
|
||||
return;
|
||||
|
||||
if (gHttpHandler->IsSpdyEnabled() &&
|
||||
ent->mConnInfo->UsingSSL() &&
|
||||
!ent->mConnInfo->UsingHttpProxy())
|
||||
{
|
||||
// If this is a possible Spdy connection we need to limit the number
|
||||
// of connections outstanding to 1 while we wait for the spdy/https
|
||||
// ReportSpdyConnection()
|
||||
|
||||
if ((!ent->mTestedSpdy || ent->mUsingSpdy) &&
|
||||
(ent->mHalfOpens.Length() || ent->mActiveConns.Length()))
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we need to purge an idle connection. Note that we may have
|
||||
// removed one above; if so, this will be a no-op. We do this before
|
||||
// checking the active connection limit to catch the case where we do
|
||||
|
@ -1139,24 +799,17 @@ nsHttpConnectionMgr::GetConnection(nsConnectionEntry *ent,
|
|||
return;
|
||||
}
|
||||
|
||||
LOG(("nsHttpConnectionMgr::GetConnection Open Connection "
|
||||
"%s %s ent=%p spdy=%d",
|
||||
ent->mConnInfo->Host(), ent->mCoalescingKey.get(),
|
||||
ent, ent->mUsingSpdy));
|
||||
|
||||
nsresult rv = CreateTransport(ent, trans);
|
||||
if (NS_FAILED(rv))
|
||||
trans->Close(rv);
|
||||
return;
|
||||
}
|
||||
|
||||
if (addConnToActiveList) {
|
||||
// hold an owning ref to this connection
|
||||
ent->mActiveConns.AppendElement(conn);
|
||||
mNumActiveConns++;
|
||||
}
|
||||
|
||||
// hold an owning ref to this connection
|
||||
ent->mActiveConns.AppendElement(conn);
|
||||
mNumActiveConns++;
|
||||
NS_ADDREF(conn);
|
||||
|
||||
*result = conn;
|
||||
}
|
||||
|
||||
|
@ -1197,25 +850,12 @@ nsHttpConnectionMgr::CreateTransport(nsConnectionEntry *ent,
|
|||
|
||||
nsresult
|
||||
nsHttpConnectionMgr::DispatchTransaction(nsConnectionEntry *ent,
|
||||
nsHttpTransaction *aTrans,
|
||||
nsAHttpTransaction *trans,
|
||||
PRUint8 caps,
|
||||
nsHttpConnection *conn)
|
||||
{
|
||||
LOG(("nsHttpConnectionMgr::DispatchTransaction [ci=%s trans=%x caps=%x conn=%x]\n",
|
||||
ent->mConnInfo->HashKey().get(), aTrans, caps, conn));
|
||||
nsresult rv;
|
||||
|
||||
PRInt32 priority = aTrans->Priority();
|
||||
|
||||
if (conn->UsingSpdy()) {
|
||||
LOG(("Spdy Dispatch Transaction via Activate(). Transaction host = %s,"
|
||||
"Connection host = %s\n",
|
||||
aTrans->ConnectionInfo()->Host(),
|
||||
conn->ConnectionInfo()->Host()));
|
||||
rv = conn->Activate(aTrans, caps, priority);
|
||||
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "SPDY Cannot Fail Dispatch");
|
||||
return rv;
|
||||
}
|
||||
ent->mConnInfo->HashKey().get(), trans, caps, conn));
|
||||
|
||||
nsConnectionHandle *handle = new nsConnectionHandle(conn);
|
||||
if (!handle)
|
||||
|
@ -1223,8 +863,6 @@ nsHttpConnectionMgr::DispatchTransaction(nsConnectionEntry *ent,
|
|||
NS_ADDREF(handle);
|
||||
|
||||
nsHttpPipeline *pipeline = nsnull;
|
||||
nsAHttpTransaction *trans = aTrans;
|
||||
|
||||
if (conn->SupportsPipelining() && (caps & NS_HTTP_ALLOW_PIPELINING)) {
|
||||
LOG((" looking to build pipeline...\n"));
|
||||
if (BuildPipeline(ent, trans, &pipeline))
|
||||
|
@ -1234,7 +872,7 @@ nsHttpConnectionMgr::DispatchTransaction(nsConnectionEntry *ent,
|
|||
// give the transaction the indirect reference to the connection.
|
||||
trans->SetConnection(handle);
|
||||
|
||||
rv = conn->Activate(trans, caps, priority);
|
||||
nsresult rv = conn->Activate(trans, caps);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG((" conn->Activate failed [rv=%x]\n", rv));
|
||||
|
@ -1329,17 +967,6 @@ nsHttpConnectionMgr::ProcessNewTransaction(nsHttpTransaction *trans)
|
|||
mCT.Put(ci->HashKey(), ent);
|
||||
}
|
||||
|
||||
// SPDY coalescing of hostnames means we might redirect from this
|
||||
// connection entry onto the preferred one.
|
||||
nsConnectionEntry *preferredEntry = GetSpdyPreferred(ent);
|
||||
if (preferredEntry && (preferredEntry != ent)) {
|
||||
LOG(("nsHttpConnectionMgr::ProcessNewTransaction trans=%p "
|
||||
"redirected via coalescing from %s to %s\n", trans,
|
||||
ent->mConnInfo->Host(), preferredEntry->mConnInfo->Host()));
|
||||
|
||||
ent = preferredEntry;
|
||||
}
|
||||
|
||||
// If we are doing a force reload then close out any existing conns
|
||||
// to this host so that changes in DNS, LBs, etc.. are reflected
|
||||
if (caps & NS_HTTP_CLEAR_KEEPALIVES)
|
||||
|
@ -1379,82 +1006,6 @@ nsHttpConnectionMgr::ProcessNewTransaction(nsHttpTransaction *trans)
|
|||
return rv;
|
||||
}
|
||||
|
||||
// This function tries to dispatch the pending spdy transactions on
|
||||
// the connection entry sent in as an argument. It will do so on the
|
||||
// active spdy connection either in that same entry or in the
|
||||
// redirected 'preferred' entry for the same coalescing hash key if
|
||||
// coalescing is enabled.
|
||||
|
||||
void
|
||||
nsHttpConnectionMgr::ProcessSpdyPendingQ(nsConnectionEntry *ent)
|
||||
{
|
||||
nsHttpConnection *conn = GetSpdyPreferredConn(ent);
|
||||
if (!conn)
|
||||
return;
|
||||
|
||||
for (PRInt32 index = ent->mPendingQ.Length() - 1;
|
||||
index >= 0 && conn->CanDirectlyActivate();
|
||||
--index) {
|
||||
nsHttpTransaction *trans = ent->mPendingQ[index];
|
||||
|
||||
if (!(trans->Caps() & NS_HTTP_ALLOW_KEEPALIVE) ||
|
||||
trans->Caps() & NS_HTTP_DISALLOW_SPDY)
|
||||
continue;
|
||||
|
||||
ent->mPendingQ.RemoveElementAt(index);
|
||||
|
||||
nsresult rv2 = DispatchTransaction(ent, trans, trans->Caps(), conn);
|
||||
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv2), "Dispatch SPDY Transaction");
|
||||
NS_RELEASE(trans);
|
||||
}
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
nsHttpConnectionMgr::ProcessSpdyPendingQCB(const nsACString &key,
|
||||
nsAutoPtr<nsConnectionEntry> &ent,
|
||||
void *closure)
|
||||
{
|
||||
nsHttpConnectionMgr *self = (nsHttpConnectionMgr *) closure;
|
||||
self->ProcessSpdyPendingQ(ent);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnectionMgr::ProcessSpdyPendingQ()
|
||||
{
|
||||
mCT.Enumerate(ProcessSpdyPendingQCB, this);
|
||||
}
|
||||
|
||||
nsHttpConnection *
|
||||
nsHttpConnectionMgr::GetSpdyPreferredConn(nsConnectionEntry *ent)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
NS_ABORT_IF_FALSE(ent, "no connection entry");
|
||||
|
||||
nsConnectionEntry *preferred = GetSpdyPreferred(ent);
|
||||
|
||||
// this entry is spdy-enabled if it is involved in a redirect
|
||||
if (preferred)
|
||||
ent->mUsingSpdy = true;
|
||||
else
|
||||
preferred = ent;
|
||||
|
||||
nsHttpConnection *conn = nsnull;
|
||||
|
||||
if (preferred->mUsingSpdy) {
|
||||
for (PRUint32 index = 0;
|
||||
index < preferred->mActiveConns.Length();
|
||||
++index) {
|
||||
if (preferred->mActiveConns[index]->CanDirectlyActivate()) {
|
||||
conn = preferred->mActiveConns[index];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return conn;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
|
@ -1490,9 +1041,8 @@ nsHttpConnectionMgr::OnMsgReschedTransaction(PRInt32 priority, void *param)
|
|||
nsHttpTransaction *trans = (nsHttpTransaction *) param;
|
||||
trans->SetPriority(priority);
|
||||
|
||||
nsConnectionEntry *ent = LookupConnectionEntry(trans->ConnectionInfo(),
|
||||
nsnull, trans);
|
||||
|
||||
nsHttpConnectionInfo *ci = trans->ConnectionInfo();
|
||||
nsConnectionEntry *ent = mCT.Get(ci->HashKey());
|
||||
if (ent) {
|
||||
PRInt32 index = ent->mPendingQ.IndexOf(trans);
|
||||
if (index >= 0) {
|
||||
|
@ -1519,9 +1069,8 @@ nsHttpConnectionMgr::OnMsgCancelTransaction(PRInt32 reason, void *param)
|
|||
if (conn && !trans->IsDone())
|
||||
conn->CloseTransaction(trans, reason);
|
||||
else {
|
||||
nsConnectionEntry *ent = LookupConnectionEntry(trans->ConnectionInfo(),
|
||||
nsnull, trans);
|
||||
|
||||
nsHttpConnectionInfo *ci = trans->ConnectionInfo();
|
||||
nsConnectionEntry *ent = mCT.Get(ci->HashKey());
|
||||
if (ent) {
|
||||
PRInt32 index = ent->mPendingQ.IndexOf(trans);
|
||||
if (index >= 0) {
|
||||
|
@ -1560,10 +1109,7 @@ nsHttpConnectionMgr::OnMsgPruneDeadConnections(PRInt32, void *)
|
|||
|
||||
// Reset mTimeOfNextWakeUp so that we can find a new shortest value.
|
||||
mTimeOfNextWakeUp = LL_MAXUINT;
|
||||
|
||||
// check canreuse() for all idle connections plus any active connections on
|
||||
// connection entries that are using spdy.
|
||||
if (mNumIdleConns || (mNumActiveConns && gHttpHandler->IsSpdyEnabled()))
|
||||
if (mNumIdleConns > 0)
|
||||
mCT.Enumerate(PruneDeadConnectionsCB, this);
|
||||
}
|
||||
|
||||
|
@ -1588,26 +1134,17 @@ nsHttpConnectionMgr::OnMsgReclaimConnection(PRInt32, void *param)
|
|||
// 3) post event to process the pending transaction queue
|
||||
//
|
||||
|
||||
nsConnectionEntry *ent = LookupConnectionEntry(conn->ConnectionInfo(),
|
||||
conn, nsnull);
|
||||
nsHttpConnectionInfo *ci = nsnull;
|
||||
nsHttpConnectionInfo *ci = conn->ConnectionInfo();
|
||||
NS_ADDREF(ci);
|
||||
|
||||
if (!ent) {
|
||||
// this should never happen
|
||||
NS_ASSERTION(ent, "no connection entry");
|
||||
NS_ADDREF(ci = conn->ConnectionInfo());
|
||||
}
|
||||
else {
|
||||
NS_ADDREF(ci = ent->mConnInfo);
|
||||
nsConnectionEntry *ent = mCT.Get(ci->HashKey());
|
||||
|
||||
NS_ASSERTION(ent, "no connection entry");
|
||||
if (ent) {
|
||||
// If the connection is in the active list, remove that entry
|
||||
// and the reference held by the mActiveConns list.
|
||||
// This is never the final reference on conn as the event context
|
||||
// is also holding one that is released at the end of this function.
|
||||
|
||||
if (ent->mUsingSpdy)
|
||||
conn->DontReuse();
|
||||
|
||||
if (ent->mActiveConns.RemoveElement(conn)) {
|
||||
nsHttpConnection *temp = conn;
|
||||
NS_RELEASE(temp);
|
||||
|
@ -1636,7 +1173,7 @@ nsHttpConnectionMgr::OnMsgReclaimConnection(PRInt32, void *param)
|
|||
conn->BeginIdleMonitoring();
|
||||
|
||||
// If the added connection was first idle connection or has shortest
|
||||
// time to live among the watched connections, pruning dead
|
||||
// time to live among the idle connections, pruning dead
|
||||
// connections needs to be done when it can't be reused anymore.
|
||||
PRUint32 timeToLive = conn->TimeToLive();
|
||||
if(!mTimer || NowInSeconds() + timeToLive < mTimeOfNextWakeUp)
|
||||
|
@ -1686,15 +1223,6 @@ nsHttpConnectionMgr::OnMsgUpdateParam(PRInt32, void *param)
|
|||
}
|
||||
}
|
||||
|
||||
// nsHttpConnectionMgr::nsConnectionEntry
|
||||
nsHttpConnectionMgr::nsConnectionEntry::~nsConnectionEntry()
|
||||
{
|
||||
if (mSpdyPreferred)
|
||||
gHttpHandler->ConnMgr()->RemoveSpdyPreferred(mCoalescingKey);
|
||||
|
||||
NS_RELEASE(mConnInfo);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpConnectionMgr::nsConnectionHandle
|
||||
|
||||
|
@ -1718,15 +1246,15 @@ nsHttpConnectionMgr::nsConnectionHandle::OnHeadersAvailable(nsAHttpTransaction *
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsHttpConnectionMgr::nsConnectionHandle::ResumeSend(nsAHttpTransaction *caller)
|
||||
nsHttpConnectionMgr::nsConnectionHandle::ResumeSend()
|
||||
{
|
||||
return mConn->ResumeSend(caller);
|
||||
return mConn->ResumeSend();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpConnectionMgr::nsConnectionHandle::ResumeRecv(nsAHttpTransaction *caller)
|
||||
nsHttpConnectionMgr::nsConnectionHandle::ResumeRecv()
|
||||
{
|
||||
return mConn->ResumeRecv(caller);
|
||||
return mConn->ResumeRecv();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1888,14 +1416,10 @@ nsHalfOpenSocket::SetupStreams(nsISocketTransport **transport,
|
|||
nsresult
|
||||
nsHttpConnectionMgr::nsHalfOpenSocket::SetupPrimaryStreams()
|
||||
{
|
||||
NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
|
||||
nsresult rv;
|
||||
|
||||
rv = SetupStreams(getter_AddRefs(mSocketTransport),
|
||||
getter_AddRefs(mStreamIn),
|
||||
getter_AddRefs(mStreamOut),
|
||||
false);
|
||||
nsresult rv = SetupStreams(getter_AddRefs(mSocketTransport),
|
||||
getter_AddRefs(mStreamIn),
|
||||
getter_AddRefs(mStreamOut),
|
||||
false);
|
||||
LOG(("nsHalfOpenSocket::SetupPrimaryStream [this=%p ent=%s rv=%x]",
|
||||
this, mEnt->mConnInfo->Host(), rv));
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -1932,7 +1456,6 @@ nsHttpConnectionMgr::nsHalfOpenSocket::SetupBackupTimer()
|
|||
{
|
||||
PRUint16 timeout = gHttpHandler->GetIdleSynTimeout();
|
||||
NS_ABORT_IF_FALSE(!mSynTimer, "timer already initd");
|
||||
|
||||
if (timeout) {
|
||||
// Setup the timer that will establish a backup socket
|
||||
// if we do not get a writable event on the main one.
|
||||
|
@ -2098,48 +1621,12 @@ nsHttpConnectionMgr::nsHalfOpenSocket::OnTransportStatus(nsITransport *trans,
|
|||
PRUint64 progress,
|
||||
PRUint64 progressMax)
|
||||
{
|
||||
NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
|
||||
if (mTransaction)
|
||||
mTransaction->OnTransportStatus(trans, status, progress);
|
||||
|
||||
if (trans != mSocketTransport)
|
||||
return NS_OK;
|
||||
|
||||
// if we are doing spdy coalescing and haven't recorded the ip address
|
||||
// for this entry before then make the hash key if our dns lookup
|
||||
// just completed
|
||||
|
||||
if (status == nsISocketTransport::STATUS_CONNECTED_TO &&
|
||||
gHttpHandler->IsSpdyEnabled() &&
|
||||
gHttpHandler->CoalesceSpdy() &&
|
||||
mEnt && mEnt->mConnInfo && mEnt->mConnInfo->UsingSSL() &&
|
||||
!mEnt->mConnInfo->UsingHttpProxy() &&
|
||||
mEnt->mCoalescingKey.IsEmpty()) {
|
||||
|
||||
PRNetAddr addr;
|
||||
nsresult rv = mSocketTransport->GetPeerAddr(&addr);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mEnt->mCoalescingKey.SetCapacity(72);
|
||||
PR_NetAddrToString(&addr, mEnt->mCoalescingKey.BeginWriting(), 64);
|
||||
mEnt->mCoalescingKey.SetLength(
|
||||
strlen(mEnt->mCoalescingKey.BeginReading()));
|
||||
|
||||
if (mEnt->mConnInfo->GetAnonymous())
|
||||
mEnt->mCoalescingKey.AppendLiteral("~A:");
|
||||
else
|
||||
mEnt->mCoalescingKey.AppendLiteral("~.:");
|
||||
mEnt->mCoalescingKey.AppendInt(mEnt->mConnInfo->Port());
|
||||
|
||||
LOG(("nsHttpConnectionMgr::nsHalfOpenSocket::OnTransportStatus "
|
||||
"STATUS_CONNECTED_TO Established New Coalescing Key for host "
|
||||
"%s [%s]", mEnt->mConnInfo->Host(),
|
||||
mEnt->mCoalescingKey.get()));
|
||||
|
||||
gHttpHandler->ConnMgr()->ProcessSpdyPendingQ(mEnt);
|
||||
}
|
||||
}
|
||||
|
||||
switch (status) {
|
||||
case nsISocketTransport::STATUS_CONNECTING_TO:
|
||||
// Passed DNS resolution, now trying to connect, start the backup timer
|
||||
|
|
|
@ -45,15 +45,12 @@
|
|||
#include "nsTArray.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "nsISocketTransportService.h"
|
||||
#include "nsHashSets.h"
|
||||
|
||||
#include "nsIObserver.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsIX509Cert3.h"
|
||||
|
||||
class nsHttpPipeline;
|
||||
|
||||
|
@ -99,9 +96,8 @@ public:
|
|||
// given time.
|
||||
void PruneDeadConnectionsAfter(PRUint32 time);
|
||||
|
||||
// Stops timer scheduled for next pruning of dead connections if
|
||||
// there are no more idle connections or active spdy ones
|
||||
void ConditionallyStopPruneDeadConnectionsTimer();
|
||||
// Stops timer scheduled for next pruning of dead connections.
|
||||
void StopPruneDeadConnectionsTimer();
|
||||
|
||||
// adds a transaction to the list of managed transactions.
|
||||
nsresult AddTransaction(nsHttpTransaction *, PRInt32 priority);
|
||||
|
@ -134,11 +130,6 @@ public:
|
|||
// been initialized.
|
||||
nsresult UpdateParam(nsParamName name, PRUint16 value);
|
||||
|
||||
// Lookup/Cancel HTTP->SPDY redirections
|
||||
bool GetSpdyAlternateProtocol(nsACString &key);
|
||||
void ReportSpdyAlternateProtocol(nsHttpConnection *);
|
||||
void RemoveSpdyAlternateProtocol(nsACString &key);
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// NOTE: functions below may be called only on the socket thread.
|
||||
//-------------------------------------------------------------------------
|
||||
|
@ -156,11 +147,6 @@ public:
|
|||
// that the network peer has closed the transport.
|
||||
nsresult CloseIdleConnection(nsHttpConnection *);
|
||||
|
||||
// The connection manager needs to know when a normal HTTP connection has been
|
||||
// upgraded to SPDY because the dispatch and idle semantics are a little
|
||||
// bit different.
|
||||
void ReportSpdyConnection(nsHttpConnection *, bool usingSpdy);
|
||||
|
||||
private:
|
||||
virtual ~nsHttpConnectionMgr();
|
||||
class nsHalfOpenSocket;
|
||||
|
@ -174,39 +160,17 @@ private:
|
|||
struct nsConnectionEntry
|
||||
{
|
||||
nsConnectionEntry(nsHttpConnectionInfo *ci)
|
||||
: mConnInfo(ci),
|
||||
mUsingSpdy(false),
|
||||
mTestedSpdy(false),
|
||||
mSpdyPreferred(false)
|
||||
: mConnInfo(ci)
|
||||
{
|
||||
NS_ADDREF(mConnInfo);
|
||||
}
|
||||
~nsConnectionEntry();
|
||||
~nsConnectionEntry() { NS_RELEASE(mConnInfo); }
|
||||
|
||||
nsHttpConnectionInfo *mConnInfo;
|
||||
nsTArray<nsHttpTransaction*> mPendingQ; // pending transaction queue
|
||||
nsTArray<nsHttpConnection*> mActiveConns; // active connections
|
||||
nsTArray<nsHttpConnection*> mIdleConns; // idle persistent connections
|
||||
nsTArray<nsHalfOpenSocket*> mHalfOpens;
|
||||
|
||||
// Spdy sometimes resolves the address in the socket manager in order
|
||||
// to re-coalesce sharded HTTP hosts. The dotted decimal address is
|
||||
// combined with the Anonymous flag from the connection information
|
||||
// to build the hash key for hosts in the same ip pool.
|
||||
//
|
||||
// When a set of hosts are coalesced together one of them is marked
|
||||
// mSpdyPreferred. The mapping is maintained in the connection mananger
|
||||
// mSpdyPreferred hash.
|
||||
//
|
||||
nsCString mCoalescingKey;
|
||||
|
||||
// To have the UsingSpdy flag means some host with the same hash information
|
||||
// has done NPN=spdy/2 at some point. It does not mean every connection
|
||||
// is currently using spdy.
|
||||
bool mUsingSpdy;
|
||||
|
||||
bool mTestedSpdy;
|
||||
bool mSpdyPreferred;
|
||||
};
|
||||
|
||||
// nsConnectionHandle
|
||||
|
@ -309,7 +273,7 @@ private:
|
|||
bool AtActiveConnectionLimit(nsConnectionEntry *, PRUint8 caps);
|
||||
void GetConnection(nsConnectionEntry *, nsHttpTransaction *,
|
||||
bool, nsHttpConnection **);
|
||||
nsresult DispatchTransaction(nsConnectionEntry *, nsHttpTransaction *,
|
||||
nsresult DispatchTransaction(nsConnectionEntry *, nsAHttpTransaction *,
|
||||
PRUint8 caps, nsHttpConnection *);
|
||||
bool BuildPipeline(nsConnectionEntry *, nsAHttpTransaction *, nsHttpPipeline **);
|
||||
nsresult ProcessNewTransaction(nsHttpTransaction *);
|
||||
|
@ -319,23 +283,7 @@ private:
|
|||
void AddActiveConn(nsHttpConnection *, nsConnectionEntry *);
|
||||
void StartedConnect();
|
||||
void RecvdConnect();
|
||||
|
||||
// Manage the preferred spdy connection entry for this address
|
||||
nsConnectionEntry *GetSpdyPreferred(nsConnectionEntry *aOriginalEntry);
|
||||
void SetSpdyPreferred(nsConnectionEntry *ent);
|
||||
void RemoveSpdyPreferred(nsACString &aDottedDecimal);
|
||||
nsHttpConnection *GetSpdyPreferredConn(nsConnectionEntry *ent);
|
||||
nsDataHashtable<nsCStringHashKey, nsConnectionEntry *> mSpdyPreferredHash;
|
||||
nsConnectionEntry *LookupConnectionEntry(nsHttpConnectionInfo *ci,
|
||||
nsHttpConnection *conn,
|
||||
nsHttpTransaction *trans);
|
||||
|
||||
void ProcessSpdyPendingQ(nsConnectionEntry *ent);
|
||||
void ProcessSpdyPendingQ();
|
||||
static PLDHashOperator ProcessSpdyPendingQCB(
|
||||
const nsACString &key, nsAutoPtr<nsConnectionEntry> &ent,
|
||||
void *closure);
|
||||
|
||||
|
||||
// message handlers have this signature
|
||||
typedef void (nsHttpConnectionMgr:: *nsConnEventHandler)(PRInt32, void *);
|
||||
|
||||
|
@ -413,13 +361,6 @@ private:
|
|||
// nsConnectionEntry object.
|
||||
//
|
||||
nsClassHashtable<nsCStringHashKey, nsConnectionEntry> mCT;
|
||||
|
||||
// this table is protected by the monitor
|
||||
nsCStringHashSet mAlternateProtocolHash;
|
||||
static PLDHashOperator TrimAlternateProtocolHash(PLDHashTable *table,
|
||||
PLDHashEntryHdr *hdr,
|
||||
PRUint32 number,
|
||||
void *closure);
|
||||
};
|
||||
|
||||
#endif // !nsHttpConnectionMgr_h__
|
||||
|
|
|
@ -174,7 +174,6 @@ nsHttpHandler::nsHttpHandler()
|
|||
, mReferrerLevel(0xff) // by default we always send a referrer
|
||||
, mFastFallbackToIPv4(false)
|
||||
, mIdleTimeout(10)
|
||||
, mSpdyTimeout(180)
|
||||
, mMaxRequestAttempts(10)
|
||||
, mMaxRequestDelay(10)
|
||||
, mIdleSynTimeout(250)
|
||||
|
@ -199,9 +198,6 @@ nsHttpHandler::nsHttpHandler()
|
|||
, mSendSecureXSiteReferrer(true)
|
||||
, mEnablePersistentHttpsCaching(false)
|
||||
, mDoNotTrackEnabled(false)
|
||||
, mEnableSpdy(false)
|
||||
, mCoalesceSpdy(true)
|
||||
, mUseAlternateProtocol(false)
|
||||
{
|
||||
#if defined(PR_LOGGING)
|
||||
gHttpLog = PR_NewLogModule("nsHttp");
|
||||
|
@ -1088,31 +1084,6 @@ nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
|
|||
mPhishyUserPassLength = (PRUint8) clamped(val, 0, 0xff);
|
||||
}
|
||||
|
||||
if (PREF_CHANGED(HTTP_PREF("spdy.enabled"))) {
|
||||
rv = prefs->GetBoolPref(HTTP_PREF("spdy.enabled"), &cVar);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mEnableSpdy = cVar;
|
||||
}
|
||||
|
||||
if (PREF_CHANGED(HTTP_PREF("spdy.coalesce-hostnames"))) {
|
||||
rv = prefs->GetBoolPref(HTTP_PREF("spdy.coalesce-hostnames"), &cVar);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mCoalesceSpdy = cVar;
|
||||
}
|
||||
|
||||
if (PREF_CHANGED(HTTP_PREF("spdy.use-alternate-protocol"))) {
|
||||
rv = prefs->GetBoolPref(HTTP_PREF("spdy.use-alternate-protocol"),
|
||||
&cVar);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mUseAlternateProtocol = cVar;
|
||||
}
|
||||
|
||||
if (PREF_CHANGED(HTTP_PREF("spdy.timeout"))) {
|
||||
rv = prefs->GetIntPref(HTTP_PREF("spdy.timeout"), &val);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mSpdyTimeout = (PRUint16) clamped(val, 1, 0xffff);
|
||||
}
|
||||
|
||||
//
|
||||
// INTL options
|
||||
//
|
||||
|
|
|
@ -101,7 +101,6 @@ public:
|
|||
bool SendSecureXSiteReferrer() { return mSendSecureXSiteReferrer; }
|
||||
PRUint8 RedirectionLimit() { return mRedirectionLimit; }
|
||||
PRUint16 IdleTimeout() { return mIdleTimeout; }
|
||||
PRUint16 SpdyTimeout() { return mSpdyTimeout; }
|
||||
PRUint16 MaxRequestAttempts() { return mMaxRequestAttempts; }
|
||||
const char *DefaultSocketType() { return mDefaultSocketType.get(); /* ok to return null */ }
|
||||
nsIIDNService *IDNConverter() { return mIDNConverter; }
|
||||
|
@ -113,10 +112,6 @@ public:
|
|||
|
||||
bool IsPersistentHttpsCachingEnabled() { return mEnablePersistentHttpsCaching; }
|
||||
|
||||
bool IsSpdyEnabled() { return mEnableSpdy; }
|
||||
bool CoalesceSpdy() { return mCoalesceSpdy; }
|
||||
bool UseAlternateProtocol() { return mUseAlternateProtocol; }
|
||||
|
||||
bool PromptTempRedirect() { return mPromptTempRedirect; }
|
||||
|
||||
nsHttpAuthCache *AuthCache() { return &mAuthCache; }
|
||||
|
@ -269,7 +264,6 @@ private:
|
|||
bool mFastFallbackToIPv4;
|
||||
|
||||
PRUint16 mIdleTimeout;
|
||||
PRUint16 mSpdyTimeout;
|
||||
PRUint16 mMaxRequestAttempts;
|
||||
PRUint16 mMaxRequestDelay;
|
||||
PRUint16 mIdleSynTimeout;
|
||||
|
@ -337,11 +331,6 @@ private:
|
|||
|
||||
// For broadcasting the preference to not be tracked
|
||||
bool mDoNotTrackEnabled;
|
||||
|
||||
// Try to use SPDY features instead of HTTP/1.1 over SSL
|
||||
bool mEnableSpdy;
|
||||
bool mCoalesceSpdy;
|
||||
bool mUseAlternateProtocol;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
@ -101,7 +101,6 @@ nsHttpPipeline::nsHttpPipeline()
|
|||
, mPushBackBuf(nsnull)
|
||||
, mPushBackLen(0)
|
||||
, mPushBackMax(0)
|
||||
, mHttp1xTransactionCount(0)
|
||||
, mReceivingFromProgress(0)
|
||||
, mSendingToProgress(0)
|
||||
, mSuppressSendEvents(true)
|
||||
|
@ -129,7 +128,7 @@ nsHttpPipeline::AddTransaction(nsAHttpTransaction *trans)
|
|||
trans->SetConnection(this);
|
||||
|
||||
if (mRequestQ.Length() == 1)
|
||||
mConnection->ResumeSend(trans);
|
||||
mConnection->ResumeSend();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -168,19 +167,19 @@ nsHttpPipeline::OnHeadersAvailable(nsAHttpTransaction *trans,
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsHttpPipeline::ResumeSend(nsAHttpTransaction *trans)
|
||||
nsHttpPipeline::ResumeSend()
|
||||
{
|
||||
if (mConnection)
|
||||
return mConnection->ResumeSend(trans);
|
||||
return mConnection->ResumeSend();
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpPipeline::ResumeRecv(nsAHttpTransaction *trans)
|
||||
nsHttpPipeline::ResumeRecv()
|
||||
{
|
||||
NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
NS_ASSERTION(mConnection, "no connection");
|
||||
return mConnection->ResumeRecv(trans);
|
||||
return mConnection->ResumeRecv();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -356,12 +355,6 @@ nsHttpPipeline::RequestHead()
|
|||
return nsnull;
|
||||
}
|
||||
|
||||
PRUint32
|
||||
nsHttpPipeline::Http1xTransactionCount()
|
||||
{
|
||||
return mHttp1xTransactionCount;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpPipeline::nsAHttpConnection
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -381,15 +374,6 @@ nsHttpPipeline::SetConnection(nsAHttpConnection *conn)
|
|||
Request(i)->SetConnection(this);
|
||||
}
|
||||
|
||||
nsAHttpConnection *
|
||||
nsHttpPipeline::Connection()
|
||||
{
|
||||
LOG(("nsHttpPipeline::Connection [this=%x conn=%x]\n", this, mConnection));
|
||||
|
||||
NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
return mConnection;
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpPipeline::GetSecurityCallbacks(nsIInterfaceRequestor **result,
|
||||
nsIEventTarget **target)
|
||||
|
@ -621,7 +605,6 @@ nsHttpPipeline::WriteSegments(nsAHttpSegmentWriter *writer,
|
|||
NS_RELEASE(trans);
|
||||
mResponseQ.RemoveElementAt(0);
|
||||
mResponseIsPartial = false;
|
||||
++mHttp1xTransactionCount;
|
||||
|
||||
// ask the connection manager to add additional transactions
|
||||
// to our pipeline.
|
||||
|
|
|
@ -112,9 +112,6 @@ private:
|
|||
PRUint32 mPushBackLen;
|
||||
PRUint32 mPushBackMax;
|
||||
|
||||
// The number of transactions completed on this pipeline.
|
||||
PRUint32 mHttp1xTransactionCount;
|
||||
|
||||
// For support of OnTransportStatus()
|
||||
PRUint64 mReceivingFromProgress;
|
||||
PRUint64 mSendingToProgress;
|
||||
|
|
|
@ -305,12 +305,6 @@ nsHttpTransaction::Init(PRUint8 caps,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAHttpConnection *
|
||||
nsHttpTransaction::Connection()
|
||||
{
|
||||
return mConnection;
|
||||
}
|
||||
|
||||
nsHttpResponseHead *
|
||||
nsHttpTransaction::TakeResponseHead()
|
||||
{
|
||||
|
@ -336,12 +330,6 @@ nsHttpTransaction::RequestHead()
|
|||
return mRequestHead;
|
||||
}
|
||||
|
||||
PRUint32
|
||||
nsHttpTransaction::Http1xTransactionCount()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// nsHttpTransaction::nsAHttpTransaction
|
||||
//----------------------------------------------------------------------------
|
||||
|
@ -1299,7 +1287,7 @@ NS_IMETHODIMP
|
|||
nsHttpTransaction::OnInputStreamReady(nsIAsyncInputStream *out)
|
||||
{
|
||||
if (mConnection) {
|
||||
nsresult rv = mConnection->ResumeSend(this);
|
||||
nsresult rv = mConnection->ResumeSend();
|
||||
if (NS_FAILED(rv))
|
||||
NS_ERROR("ResumeSend failed");
|
||||
}
|
||||
|
@ -1315,7 +1303,7 @@ NS_IMETHODIMP
|
|||
nsHttpTransaction::OnOutputStreamReady(nsIAsyncOutputStream *out)
|
||||
{
|
||||
if (mConnection) {
|
||||
nsresult rv = mConnection->ResumeRecv(this);
|
||||
nsresult rv = mConnection->ResumeRecv();
|
||||
if (NS_FAILED(rv))
|
||||
NS_ERROR("ResumeRecv failed");
|
||||
}
|
||||
|
|
|
@ -120,6 +120,7 @@ public:
|
|||
|
||||
nsIInterfaceRequestor *Callbacks() { return mCallbacks; }
|
||||
nsIEventTarget *ConsumerTarget() { return mConsumerTarget; }
|
||||
nsAHttpConnection *Connection() { return mConnection; }
|
||||
|
||||
// Called to take ownership of the response headers; the transaction
|
||||
// will drop any reference to the response headers after this call.
|
||||
|
@ -130,7 +131,7 @@ public:
|
|||
|
||||
bool SSLConnectFailed() { return mSSLConnectFailed; }
|
||||
|
||||
// SetPriority() may only be used by the connection manager.
|
||||
// These methods may only be used by the connection manager.
|
||||
void SetPriority(PRInt32 priority) { mPriority = priority; }
|
||||
PRInt32 Priority() { return mPriority; }
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ interface nsIProxyInfo;
|
|||
* The callback interface for nsIHttpChannelInternal::HTTPUpgrade()
|
||||
*/
|
||||
|
||||
[scriptable, uuid(4b967b6d-cd1c-49ae-a457-23ff76f5a2e8)]
|
||||
[scriptable, uuid(5644af88-09e1-4fbd-83da-f012b3b30180)]
|
||||
interface nsIHttpUpgradeListener : nsISupports
|
||||
{
|
||||
void onTransportAvailable(in nsISocketTransport aTransport,
|
||||
|
@ -181,11 +181,4 @@ interface nsIHttpChannelInternal : nsISupports
|
|||
void HTTPUpgrade(in ACString aProtocolName,
|
||||
in nsIHttpUpgradeListener aListener);
|
||||
|
||||
/**
|
||||
* Enable/Disable Spdy negotiation on per channel basis.
|
||||
* The network.http.spdy.enabled preference is still a pre-requisite
|
||||
* for starting spdy.
|
||||
*/
|
||||
attribute boolean allowSpdy;
|
||||
|
||||
};
|
||||
|
|
|
@ -42,47 +42,11 @@
|
|||
|
||||
interface nsIInterfaceRequestor;
|
||||
|
||||
%{C++
|
||||
#include "nsTArray.h"
|
||||
class nsCString;
|
||||
%}
|
||||
[ref] native nsCStringTArrayRef(nsTArray<nsCString>);
|
||||
|
||||
[scriptable, uuid(753f0f13-681d-4de3-a6c6-11aa7e0b3afd)]
|
||||
[scriptable, uuid(a092097c-8386-4f1b-97b1-90eb70008c2d)]
|
||||
interface nsISSLSocketControl : nsISupports {
|
||||
attribute nsIInterfaceRequestor notificationCallbacks;
|
||||
|
||||
void proxyStartSSL();
|
||||
void StartTLS();
|
||||
|
||||
/* NPN (Next Protocol Negotiation) is a mechanism for
|
||||
negotiating the protocol to be spoken inside the SSL
|
||||
tunnel during the SSL handshake. The NPNList is the list
|
||||
of offered client side protocols. setNPNList() needs to
|
||||
be called before any data is read or written (including the
|
||||
handshake to be setup correctly. */
|
||||
|
||||
[noscript] void setNPNList(in nsCStringTArrayRef aNPNList);
|
||||
|
||||
/* negotiatedNPN is '' if no NPN list was provided by the client,
|
||||
* or if the server did not select any protocol choice from that
|
||||
* list. That also includes the case where the server does not
|
||||
* implement NPN.
|
||||
*
|
||||
* If negotiatedNPN is read before NPN has progressed to the point
|
||||
* where this information is available NS_ERROR_NOT_CONNECTED is
|
||||
* raised.
|
||||
*/
|
||||
readonly attribute ACString negotiatedNPN;
|
||||
|
||||
/* Determine if a potential SSL connection to hostname:port with
|
||||
* a desired NPN negotiated protocol of npnProtocol can use the socket
|
||||
* associated with this object instead of making a new one.
|
||||
*/
|
||||
boolean joinConnection(
|
||||
in ACString npnProtocol, /* e.g. "spdy/2" */
|
||||
in ACString hostname,
|
||||
in long port);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -365,81 +365,10 @@ PSM_SSL_BlacklistDigiNotar(CERTCertificate * serverCert,
|
|||
return 0;
|
||||
}
|
||||
|
||||
// This function assumes that we will only use the SPDY connection coalescing
|
||||
// feature on connections where we have negotiated SPDY using NPN. If we ever
|
||||
// talk SPDY without having negotiated it with SPDY, this code will give wrong
|
||||
// and perhaps unsafe results.
|
||||
//
|
||||
// Returns SECSuccess on the initial handshake of all connections, on
|
||||
// renegotiations for any connections where we did not negotiate SPDY, or on any
|
||||
// SPDY connection where the server's certificate did not change.
|
||||
//
|
||||
// Prohibit changing the server cert only if we negotiated SPDY,
|
||||
// in order to support SPDY's cross-origin connection pooling.
|
||||
|
||||
static SECStatus
|
||||
BlockServerCertChangeForSpdy(nsNSSSocketInfo *infoObject,
|
||||
CERTCertificate *serverCert)
|
||||
{
|
||||
// Get the existing cert. If there isn't one, then there is
|
||||
// no cert change to worry about.
|
||||
nsCOMPtr<nsIX509Cert> cert;
|
||||
nsCOMPtr<nsIX509Cert2> cert2;
|
||||
|
||||
nsRefPtr<nsSSLStatus> status = infoObject->SSLStatus();
|
||||
if (!status) {
|
||||
// If we didn't have a status, then this is the
|
||||
// first handshake on this connection, not a
|
||||
// renegotiation.
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
status->GetServerCert(getter_AddRefs(cert));
|
||||
cert2 = do_QueryInterface(cert);
|
||||
if (!cert2) {
|
||||
NS_NOTREACHED("every nsSSLStatus must have a cert"
|
||||
"that implements nsIX509Cert2");
|
||||
PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
// Filter out sockets that did not neogtiate SPDY via NPN
|
||||
nsCAutoString negotiatedNPN;
|
||||
nsresult rv = infoObject->GetNegotiatedNPN(negotiatedNPN);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"GetNegotiatedNPN() failed during renegotiation");
|
||||
|
||||
if (NS_SUCCEEDED(rv) && !negotiatedNPN.Equals(NS_LITERAL_CSTRING("spdy/2")))
|
||||
return SECSuccess;
|
||||
|
||||
// If GetNegotiatedNPN() failed we will assume spdy for safety's safe
|
||||
if (NS_FAILED(rv))
|
||||
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
|
||||
("BlockServerCertChangeForSpdy failed GetNegotiatedNPN() call."
|
||||
" Assuming spdy.\n"));
|
||||
|
||||
// Check to see if the cert has actually changed
|
||||
CERTCertificate * c = cert2->GetCert();
|
||||
NS_ASSERTION(c, "very bad and hopefully impossible state");
|
||||
bool sameCert = CERT_CompareCerts(c, serverCert);
|
||||
CERT_DestroyCertificate(c);
|
||||
if (sameCert)
|
||||
return SECSuccess;
|
||||
|
||||
// Report an error - changed cert is confirmed
|
||||
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
|
||||
("SPDY Refused to allow new cert during renegotiation\n"));
|
||||
PR_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED, 0);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
SSLServerCertVerificationJob::AuthCertificate(
|
||||
nsNSSShutDownPreventionLock const & nssShutdownPreventionLock)
|
||||
{
|
||||
if (BlockServerCertChangeForSpdy(mSocketInfo, mCert) != SECSuccess)
|
||||
return SECFailure;
|
||||
|
||||
if (mCert->serialNumber.data &&
|
||||
mCert->issuerName &&
|
||||
!strcmp(mCert->issuerName,
|
||||
|
|
|
@ -53,7 +53,6 @@
|
|||
#include "nsProxyRelease.h"
|
||||
#include "PSMRunnable.h"
|
||||
#include "nsIConsoleService.h"
|
||||
#include "nsIHttpChannelInternal.h"
|
||||
|
||||
#include "ssl.h"
|
||||
#include "ocsp.h"
|
||||
|
@ -136,16 +135,6 @@ nsHTTPDownloadEvent::Run()
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// Do not use SPDY for internal security operations. It could result
|
||||
// in the silent upgrade to ssl, which in turn could require an SSL
|
||||
// operation to fufill something like a CRL fetch, which is an
|
||||
// endless loop.
|
||||
nsCOMPtr<nsIHttpChannelInternal> internalChannel = do_QueryInterface(chan);
|
||||
if (internalChannel) {
|
||||
rv = internalChannel->SetAllowSpdy(false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> hchan = do_QueryInterface(chan);
|
||||
NS_ENSURE_STATE(hchan);
|
||||
|
||||
|
@ -955,21 +944,6 @@ void PR_CALLBACK HandshakeCallback(PRFileDesc* fd, void* client_data) {
|
|||
status->mKeyLength = keyLength;
|
||||
status->mSecretKeyLength = encryptBits;
|
||||
status->mCipherName.Assign(cipherName);
|
||||
|
||||
// Get the NPN value. Do this on the stack and copy it into
|
||||
// a string rather than preallocating the string because right
|
||||
// now we expect NPN to fail more often than it succeeds.
|
||||
SSLNextProtoState state;
|
||||
unsigned char npnbuf[256];
|
||||
unsigned int npnlen;
|
||||
|
||||
if (SSL_GetNextProto(fd, &state, npnbuf, &npnlen, 256) == SECSuccess &&
|
||||
state == SSL_NEXT_PROTO_NEGOTIATED)
|
||||
infoObject->SetNegotiatedNPN(reinterpret_cast<char *>(npnbuf), npnlen);
|
||||
else
|
||||
infoObject->SetNegotiatedNPN(nsnull, 0);
|
||||
|
||||
infoObject->SetHandshakeCompleted();
|
||||
}
|
||||
|
||||
PORT_Free(cipherName);
|
||||
|
|
|
@ -169,11 +169,7 @@ nsNSSSocketInfo::nsNSSSocketInfo()
|
|||
mRememberClientAuthCertificate(false),
|
||||
mHandshakeStartTime(0),
|
||||
mPort(0),
|
||||
mIsCertIssuerBlacklisted(false),
|
||||
mNPNCompleted(false),
|
||||
mHandshakeCompleted(false),
|
||||
mJoined(false),
|
||||
mSentClientCert(false)
|
||||
mIsCertIssuerBlacklisted(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -439,89 +435,6 @@ nsNSSSocketInfo::GetErrorMessage(PRUnichar** aText)
|
|||
return *aText != nsnull ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
void
|
||||
nsNSSSocketInfo::SetNegotiatedNPN(const char *value, PRUint32 length)
|
||||
{
|
||||
if (!value)
|
||||
mNegotiatedNPN.Truncate();
|
||||
else
|
||||
mNegotiatedNPN.Assign(value, length);
|
||||
mNPNCompleted = true;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNSSSocketInfo::GetNegotiatedNPN(nsACString &aNegotiatedNPN)
|
||||
{
|
||||
if (!mNPNCompleted)
|
||||
return NS_ERROR_NOT_CONNECTED;
|
||||
|
||||
aNegotiatedNPN = mNegotiatedNPN;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNSSSocketInfo::JoinConnection(const nsACString & npnProtocol,
|
||||
const nsACString & hostname,
|
||||
PRInt32 port,
|
||||
bool *_retval NS_OUTPARAM)
|
||||
{
|
||||
*_retval = false;
|
||||
|
||||
// Different ports may not be joined together
|
||||
if (port != mPort)
|
||||
return NS_OK;
|
||||
|
||||
// Make sure NPN has been completed and matches requested npnProtocol
|
||||
if (!mNPNCompleted || !mNegotiatedNPN.Equals(npnProtocol))
|
||||
return NS_OK;
|
||||
|
||||
// If this is the same hostname then the certicate status does not
|
||||
// need to be considered. They are joinable.
|
||||
if (mHostName && hostname.Equals(mHostName)) {
|
||||
*_retval = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Before checking the server certificate we need to make sure the
|
||||
// handshake has completed.
|
||||
if (!mHandshakeCompleted || !SSLStatus() || !SSLStatus()->mServerCert)
|
||||
return NS_OK;
|
||||
|
||||
// If the cert has error bits (e.g. it is untrusted) then do not join.
|
||||
// The value of mHaveCertErrorBits is only reliable because we know that
|
||||
// the handshake completed.
|
||||
if (SSLStatus()->mHaveCertErrorBits)
|
||||
return NS_OK;
|
||||
|
||||
// If the connection is using client certificates then do not join
|
||||
// because the user decides on whether to send client certs to hosts on a
|
||||
// per-domain basis.
|
||||
if (mSentClientCert)
|
||||
return NS_OK;
|
||||
|
||||
// Ensure that the server certificate covers the hostname that would
|
||||
// like to join this connection
|
||||
|
||||
CERTCertificate *nssCert = nsnull;
|
||||
CERTCertificateCleaner nsscertCleaner(nssCert);
|
||||
|
||||
nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(SSLStatus()->mServerCert);
|
||||
if (cert2)
|
||||
nssCert = cert2->GetCert();
|
||||
|
||||
if (!nssCert)
|
||||
return NS_OK;
|
||||
|
||||
if (CERT_VerifyCertName(nssCert, PromiseFlatCString(hostname).get()) !=
|
||||
SECSuccess)
|
||||
return NS_OK;
|
||||
|
||||
// All tests pass - this is joinable
|
||||
mJoined = true;
|
||||
*_retval = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
formatPlainErrorMessage(nsXPIDLCString const & host, PRInt32 port,
|
||||
PRErrorCode err, nsString &returnedMessage);
|
||||
|
@ -613,36 +526,6 @@ nsNSSSocketInfo::StartTLS()
|
|||
return ActivateSSL();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNSSSocketInfo::SetNPNList(nsTArray<nsCString> &protocolArray)
|
||||
{
|
||||
nsNSSShutDownPreventionLock locker;
|
||||
if (isAlreadyShutDown())
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
if (!mFd)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// the npn list is a concatenated list of 8 bit byte strings.
|
||||
nsCString npnList;
|
||||
|
||||
for (PRUint32 index = 0; index < protocolArray.Length(); ++index) {
|
||||
if (protocolArray[index].IsEmpty() ||
|
||||
protocolArray[index].Length() > 255)
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
|
||||
npnList.Append(protocolArray[index].Length());
|
||||
npnList.Append(protocolArray[index]);
|
||||
}
|
||||
|
||||
if (SSL_SetNextProtoNego(
|
||||
mFd,
|
||||
reinterpret_cast<const unsigned char *>(npnList.get()),
|
||||
npnList.Length()) != SECSuccess)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static NS_DEFINE_CID(kNSSCertificateCID, NS_X509CERT_CID);
|
||||
#define NSSSOCKETINFOMAGIC { 0xa9863a23, 0x26b8, 0x4a9c, \
|
||||
{ 0x83, 0xf1, 0xe9, 0xda, 0xdb, 0x36, 0xb8, 0x30 } }
|
||||
|
@ -2892,9 +2775,9 @@ public:
|
|||
CERTCertificate * serverCert)
|
||||
: mRV(SECFailure)
|
||||
, mErrorCodeToReport(SEC_ERROR_NO_MEMORY)
|
||||
, mCANames(caNames)
|
||||
, mPRetCert(pRetCert)
|
||||
, mPRetKey(pRetKey)
|
||||
, mCANames(caNames)
|
||||
, mSocketInfo(info)
|
||||
, mServerCert(serverCert)
|
||||
{
|
||||
|
@ -2902,12 +2785,12 @@ public:
|
|||
|
||||
SECStatus mRV; // out
|
||||
PRErrorCode mErrorCodeToReport; // out
|
||||
CERTCertificate** const mPRetCert; // in/out
|
||||
SECKEYPrivateKey** const mPRetKey; // in/out
|
||||
protected:
|
||||
virtual void RunOnTargetThread();
|
||||
private:
|
||||
CERTDistNames* const mCANames; // in
|
||||
CERTCertificate** const mPRetCert; // in/out
|
||||
SECKEYPrivateKey** const mPRetKey; // in/out
|
||||
nsNSSSocketInfo * const mSocketInfo; // in
|
||||
CERTCertificate * const mServerCert; // in
|
||||
};
|
||||
|
@ -2950,18 +2833,6 @@ SECStatus nsNSS_SSLGetClientAuthData(void* arg, PRFileDesc* socket,
|
|||
return SECFailure;
|
||||
}
|
||||
|
||||
if (info->GetJoined()) {
|
||||
// We refuse to send a client certificate when there are multiple hostnames
|
||||
// joined on this connection, because we only show the user one hostname
|
||||
// (mHostName) in the client certificate UI.
|
||||
|
||||
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
|
||||
("[%p] Not returning client cert due to previous join\n", socket));
|
||||
*pRetCert = nsnull;
|
||||
*pRetKey = nsnull;
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
// XXX: This should be done asynchronously; see bug 696976
|
||||
nsRefPtr<ClientAuthDataRunnable> runnable =
|
||||
new ClientAuthDataRunnable(caNames, pRetCert, pRetKey, info, serverCert);
|
||||
|
@ -2973,9 +2844,6 @@ SECStatus nsNSS_SSLGetClientAuthData(void* arg, PRFileDesc* socket,
|
|||
|
||||
if (runnable->mRV != SECSuccess) {
|
||||
PR_SetError(runnable->mErrorCodeToReport, 0);
|
||||
} else if (*runnable->mPRetCert || *runnable->mPRetKey) {
|
||||
// Make joinConnection prohibit joining after we've sent a client cert
|
||||
info->SetSentClientCert();
|
||||
}
|
||||
|
||||
return runnable->mRV;
|
||||
|
|
|
@ -153,12 +153,6 @@ public:
|
|||
mIsCertIssuerBlacklisted = true;
|
||||
}
|
||||
|
||||
void SetNegotiatedNPN(const char *value, PRUint32 length);
|
||||
void SetHandshakeCompleted() { mHandshakeCompleted = true; }
|
||||
|
||||
bool GetJoined() { return mJoined; }
|
||||
void SetSentClientCert() { mSentClientCert = true; }
|
||||
|
||||
// XXX: These are only used on for diagnostic purposes
|
||||
enum CertVerificationState {
|
||||
before_cert_verification,
|
||||
|
@ -214,12 +208,6 @@ protected:
|
|||
|
||||
nsresult ActivateSSL();
|
||||
|
||||
nsCString mNegotiatedNPN;
|
||||
bool mNPNCompleted;
|
||||
bool mHandshakeCompleted;
|
||||
bool mJoined;
|
||||
bool mSentClientCert;
|
||||
|
||||
private:
|
||||
virtual void virtualDestroyNSSReference();
|
||||
void destructorSafeDestroyNSSReference();
|
||||
|
|
|
@ -74,9 +74,6 @@ public:
|
|||
bool mIsUntrusted;
|
||||
|
||||
bool mHaveKeyLengthAndCipher;
|
||||
|
||||
/* mHaveCertErrrorBits is relied on to determine whether or not a SPDY
|
||||
connection is eligible for joining in nsNSSSocketInfo::JoinConnection() */
|
||||
bool mHaveCertErrorBits;
|
||||
};
|
||||
|
||||
|
|
|
@ -141,8 +141,6 @@ HISTOGRAM(HTTP_SUBITEM_OPEN_LATENCY_TIME, 1, 30000, 50, EXPONENTIAL, "HTTP subit
|
|||
HISTOGRAM(HTTP_SUBITEM_FIRST_BYTE_LATENCY_TIME, 1, 30000, 50, EXPONENTIAL, "HTTP subitem: Page start -> first byte received for subitem reply (ms)")
|
||||
HISTOGRAM(HTTP_REQUEST_PER_PAGE, 1, 1000, 50, EXPONENTIAL, "HTTP: Requests per page (count)")
|
||||
HISTOGRAM(HTTP_REQUEST_PER_PAGE_FROM_CACHE, 1, 101, 102, LINEAR, "HTTP: Requests serviced from cache (%)")
|
||||
HISTOGRAM(HTTP_REQUEST_PER_CONN, 1, 1000, 50, EXPONENTIAL, "HTTP: requests per connection")
|
||||
HISTOGRAM(HTTP_KBREAD_PER_CONN, 1, 3000, 50, EXPONENTIAL, "HTTP: KB read per connection")
|
||||
|
||||
#define _HTTP_HIST(name, label) \
|
||||
HISTOGRAM(name, 1, 30000, 50, EXPONENTIAL, "HTTP " label) \
|
||||
|
@ -164,26 +162,6 @@ HISTOGRAM(HTTP_KBREAD_PER_CONN, 1, 3000, 50, EXPONENTIAL, "HTTP: KB read per con
|
|||
HTTP_HISTOGRAMS(PAGE, "page: ")
|
||||
HTTP_HISTOGRAMS(SUB, "subitem: ")
|
||||
|
||||
HISTOGRAM(SPDY_PARALLEL_STREAMS, 1, 1000, 50, EXPONENTIAL, "SPDY: Streams concurrent active per connection")
|
||||
HISTOGRAM(SPDY_REQUEST_PER_CONN, 1, 1000, 50, EXPONENTIAL, "SPDY: Streams created per connection")
|
||||
HISTOGRAM(SPDY_SERVER_INITIATED_STREAMS, 1, 100000, 250, EXPONENTIAL, "SPDY: Streams recevied per connection")
|
||||
HISTOGRAM(SPDY_CHUNK_RECVD, 1, 1000, 100, EXPONENTIAL, "SPDY: Recvd Chunk Size (rounded to KB)")
|
||||
HISTOGRAM(SPDY_SYN_SIZE, 20, 20000, 50, EXPONENTIAL, "SPDY: SYN Frame Header Size")
|
||||
HISTOGRAM(SPDY_SYN_RATIO, 1, 99, 20, LINEAR, "SPDY: SYN Frame Header Ratio (lower better)")
|
||||
HISTOGRAM(SPDY_SYN_REPLY_SIZE, 16, 20000, 50, EXPONENTIAL, "SPDY: SYN Reply Header Size")
|
||||
HISTOGRAM(SPDY_SYN_REPLY_RATIO, 1, 99, 20, LINEAR, "SPDY: SYN Reply Header Ratio (lower better)")
|
||||
HISTOGRAM(SPDY_NPN_CONNECT, 0, 1, 2, BOOLEAN, "SPDY: NPN Negotiated")
|
||||
HISTOGRAM(SPDY_NPN_JOIN, 0, 1, 2, BOOLEAN, "SPDY: Coalesce Succeeded")
|
||||
HISTOGRAM(SPDY_KBREAD_PER_CONN, 1, 3000, 50, EXPONENTIAL, "SPDY: KB read per connection")
|
||||
|
||||
HISTOGRAM(SPDY_SETTINGS_UL_BW, 1, 10000, 100, EXPONENTIAL, "SPDY: Settings Upload Bandwidth")
|
||||
HISTOGRAM(SPDY_SETTINGS_DL_BW, 1, 10000, 100, EXPONENTIAL, "SPDY: Settings Download Bandwidth")
|
||||
HISTOGRAM(SPDY_SETTINGS_RTT, 1, 1000, 100, EXPONENTIAL, "SPDY: Settings RTT")
|
||||
HISTOGRAM(SPDY_SETTINGS_MAX_STREAMS, 1, 5000, 100, EXPONENTIAL, "SPDY: Settings Max Streams parameter")
|
||||
HISTOGRAM(SPDY_SETTINGS_CWND, 1, 500, 50, EXPONENTIAL, "SPDY: Settings CWND (packets)")
|
||||
HISTOGRAM(SPDY_SETTINGS_RETRANS, 1, 100, 50, EXPONENTIAL, "SPDY: Retransmission Rate")
|
||||
HISTOGRAM(SPDY_SETTINGS_IW, 1, 1000, 50, EXPONENTIAL, "SPDY: Settings IW (rounded to KB)")
|
||||
|
||||
#undef _HTTP_HIST
|
||||
#undef HTTP_HISTOGRAMS
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче