bug 752648 - fix regression with restarting due to tls intolerance r=honzab
authorPatrick McManus <mcmanus@ducksong.com>
Mon, 14 May 2012 13:25:28 -0400
changeset 93881 90ef8e055139dd29bb37482e69fdb601d022c6be
parent 93880 d0f6caf941d106a9ccab935b8f4069b99e121afd
child 93882 35365a9750f321aed82e6c8dd26a73f47450bcc6
push id9365
push usermcmanus@ducksong.com
push dateMon, 14 May 2012 18:49:16 +0000
treeherdermozilla-inbound@90ef8e055139 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershonzab
bugs752648
milestone15.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 752648 - fix regression with restarting due to tls intolerance r=honzab
netwerk/protocol/http/SpdySession.h
netwerk/protocol/http/nsAHttpConnection.h
netwerk/protocol/http/nsHttpConnection.cpp
netwerk/protocol/http/nsHttpConnection.h
netwerk/protocol/http/nsHttpConnectionMgr.h
netwerk/protocol/http/nsHttpPipeline.h
netwerk/protocol/http/nsHttpTransaction.cpp
--- a/netwerk/protocol/http/SpdySession.h
+++ b/netwerk/protocol/http/SpdySession.h
@@ -61,17 +61,17 @@ class SpdyStream;
 class SpdySession : public nsAHttpTransaction
                   , public nsAHttpConnection
                   , public nsAHttpSegmentReader
                   , public nsAHttpSegmentWriter
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSAHTTPTRANSACTION
-  NS_DECL_NSAHTTPCONNECTION
+  NS_DECL_NSAHTTPCONNECTION(mConnection)
   NS_DECL_NSAHTTPSEGMENTREADER
   NS_DECL_NSAHTTPSEGMENTWRITER
 
   SpdySession(nsAHttpTransaction *, nsISocketTransport *, PRInt32);
   ~SpdySession();
 
   bool AddStream(nsAHttpTransaction *, PRInt32);
   bool CanReuse() { return !mShouldGoAway && !mClosed; }
--- a/netwerk/protocol/http/nsAHttpConnection.h
+++ b/netwerk/protocol/http/nsAHttpConnection.h
@@ -148,19 +148,23 @@ public:
 
     // Cancel and reschedule transactions deeper than the current response.
     // Returns the number of canceled transactions.
     virtual PRUint32 CancelPipeline(nsresult originalReason) = 0;
 
     // Read and write class of transaction that is carried on this connection
     virtual nsAHttpTransaction::Classifier Classification() = 0;
     virtual void Classify(nsAHttpTransaction::Classifier newclass) = 0;
+
+    // The number of transaction bytes written out on this HTTP Connection, does
+    // not count CONNECT tunnel setup
+    virtual PRInt64 BytesWritten() = 0;
 };
 
-#define NS_DECL_NSAHTTPCONNECTION \
+#define NS_DECL_NSAHTTPCONNECTION(fwdObject)                    \
     nsresult OnHeadersAvailable(nsAHttpTransaction *, nsHttpRequestHead *, nsHttpResponseHead *, bool *reset); \
     nsresult ResumeSend(); \
     nsresult ResumeRecv(); \
     void CloseTransaction(nsAHttpTransaction *, nsresult); \
     void GetConnectionInfo(nsHttpConnectionInfo **); \
     nsresult TakeTransport(nsISocketTransport **,    \
                            nsIAsyncInputStream **,   \
                            nsIAsyncOutputStream **); \
@@ -171,11 +175,13 @@ public:
     nsresult PushBack(const char *, PRUint32); \
     bool IsProxyConnectInProgress(); \
     bool LastTransactionExpectedNoContent(); \
     void SetLastTransactionExpectedNoContent(bool); \
     nsHttpConnection *TakeHttpConnection(); \
     nsISocketTransport *Transport();        \
     PRUint32 CancelPipeline(nsresult originalReason);   \
     nsAHttpTransaction::Classifier Classification();    \
-    void Classify(nsAHttpTransaction::Classifier);
+    void Classify(nsAHttpTransaction::Classifier);      \
+    PRInt64 BytesWritten() \
+    {     return fwdObject ? (fwdObject)->BytesWritten() : 0; }
 
 #endif // nsAHttpConnection_h__
--- a/netwerk/protocol/http/nsHttpConnection.cpp
+++ b/netwerk/protocol/http/nsHttpConnection.cpp
@@ -74,16 +74,17 @@ using namespace mozilla::net;
 nsHttpConnection::nsHttpConnection()
     : mTransaction(nsnull)
     , mIdleTimeout(0)
     , mConsiderReusedAfterInterval(0)
     , mConsiderReusedAfterEpoch(0)
     , mCurrentBytesRead(0)
     , mMaxBytesRead(0)
     , mTotalBytesRead(0)
+    , mTotalBytesWritten(0)
     , mKeepAlive(true) // assume to keep-alive by default
     , mKeepAliveMask(true)
     , mSupportsPipelining(false) // assume low-grade server
     , mIsReused(false)
     , mCompletedProxyConnect(false)
     , mLastTransactionExpectedNoContent(false)
     , mIdleMonitoring(false)
     , mProxyConnectInProgress(false)
@@ -1189,18 +1190,21 @@ nsHttpConnection::OnReadSegment(const ch
         return NS_ERROR_FAILURE; // stop iterating
     }
 
     nsresult rv = mSocketOut->Write(buf, count, countRead);
     if (NS_FAILED(rv))
         mSocketOutCondition = rv;
     else if (*countRead == 0)
         mSocketOutCondition = NS_BASE_STREAM_CLOSED;
-    else
+    else {
         mSocketOutCondition = NS_OK; // reset condition
+        if (!mProxyConnectInProgress)
+            mTotalBytesWritten += *countRead;
+    }
 
     return mSocketOutCondition;
 }
 
 nsresult
 nsHttpConnection::OnSocketWritable()
 {
     LOG(("nsHttpConnection::OnSocketWritable [this=%p] host=%s\n",
--- a/netwerk/protocol/http/nsHttpConnection.h
+++ b/netwerk/protocol/http/nsHttpConnection.h
@@ -177,16 +177,18 @@ public:
     void Classify(nsAHttpTransaction::Classifier newclass)
     {
         mClassification = newclass;
     }
 
     // When the connection is active this is called every second
     void  ReadTimeoutTick();
 
+    PRInt64 BytesWritten() { return mTotalBytesWritten; }
+
 private:
     // called to cause the underlying socket to start speaking SSL
     nsresult ProxyStartSSL();
 
     nsresult OnTransactionDone(nsresult reason);
     nsresult OnSocketWritable();
     nsresult OnSocketReadable();
 
@@ -234,16 +236,17 @@ private:
     PRIntervalTime                  mLastReadTime;
     PRIntervalTime                  mMaxHangTime;    // max download time before dropping keep-alive status
     PRIntervalTime                  mIdleTimeout;    // value of keep-alive: timeout=
     PRIntervalTime                  mConsiderReusedAfterInterval;
     PRIntervalTime                  mConsiderReusedAfterEpoch;
     PRInt64                         mCurrentBytesRead;   // data read per activation
     PRInt64                         mMaxBytesRead;       // max read in 1 activation
     PRInt64                         mTotalBytesRead;     // total data read
+    PRInt64                         mTotalBytesWritten;  // does not include CONNECT tunnel
 
     nsRefPtr<nsIAsyncInputStream>   mInputOverflow;
 
     PRIntervalTime                  mRtt;
 
     bool                            mKeepAlive;
     bool                            mKeepAliveMask;
     bool                            mSupportsPipelining;
--- a/netwerk/protocol/http/nsHttpConnectionMgr.h
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.h
@@ -374,17 +374,17 @@ private:
     // layer of indirection greatly simplifies consumer code, avoiding the
     // need for consumer code to know when to give the connection back to the
     // connection manager.
     //
     class nsConnectionHandle : public nsAHttpConnection
     {
     public:
         NS_DECL_ISUPPORTS
-        NS_DECL_NSAHTTPCONNECTION
+        NS_DECL_NSAHTTPCONNECTION(mConn)
 
         nsConnectionHandle(nsHttpConnection *conn) { NS_ADDREF(mConn = conn); }
         virtual ~nsConnectionHandle();
 
         nsHttpConnection *mConn;
     };
 
     // nsHalfOpenSocket is used to hold the state of an opening TCP socket
--- a/netwerk/protocol/http/nsHttpPipeline.h
+++ b/netwerk/protocol/http/nsHttpPipeline.h
@@ -48,17 +48,17 @@
 #include "nsCOMPtr.h"
 
 class nsHttpPipeline : public nsAHttpConnection
                      , public nsAHttpTransaction
                      , public nsAHttpSegmentReader
 {
 public:
     NS_DECL_ISUPPORTS
-    NS_DECL_NSAHTTPCONNECTION
+    NS_DECL_NSAHTTPCONNECTION(mConnection)
     NS_DECL_NSAHTTPTRANSACTION
     NS_DECL_NSAHTTPSEGMENTREADER
 
     nsHttpPipeline();
     virtual ~nsHttpPipeline();
 
 private:
     nsresult FillSendBuf();
--- a/netwerk/protocol/http/nsHttpTransaction.cpp
+++ b/netwerk/protocol/http/nsHttpTransaction.cpp
@@ -720,17 +720,25 @@ nsHttpTransaction::Close(nsresult reason
     // have dire consequences including repeated purchases, etc.
     //
     // NOTE: because of the way SSL proxy CONNECT is implemented, it is
     // possible that the transaction may have received data without having
     // sent any data.  for this reason, mSendData == FALSE does not imply
     // mReceivedData == FALSE.  (see bug 203057 for more info.)
     //
     if (reason == NS_ERROR_NET_RESET || reason == NS_OK) {
-        if (!mReceivedData && (!mSentData || connReused || mPipelinePosition)) {
+
+        // reallySentData is meant to separate the instances where data has
+        // been sent by this transaction but buffered at a higher level while
+        // a TLS session (perhaps via a tunnel) is setup.
+        bool reallySentData =
+            mSentData && (!mConnection || mConnection->BytesWritten());
+        
+        if (!mReceivedData &&
+            (!reallySentData || connReused || mPipelinePosition)) {
             // if restarting fails, then we must proceed to close the pipe,
             // which will notify the channel that the transaction failed.
             
             if (mPipelinePosition) {
                 gHttpHandler->ConnMgr()->PipelineFeedbackInfo(
                     mConnInfo, nsHttpConnectionMgr::RedCanceledPipeline,
                     nsnull, 0);
             }