bug 752648 - fix regression with restarting due to tls intolerance r=honzab a=akeybl
authorPatrick McManus <mcmanus@ducksong.com>
Mon, 14 May 2012 13:25:28 -0400
changeset 95778 bac25b8ea4e73fe45e1df0e7f8155422306f92a0
parent 95777 4e6bac3417e0601f9fffe68717eb17a876b74bd4
child 95779 e443c52f571c655685858d0f55ea20997b1bcacc
push id886
push userlsblakk@mozilla.com
push dateMon, 04 Jun 2012 19:57:52 +0000
treeherdermozilla-beta@bbd8d5efd6d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershonzab, akeybl
bugs752648
milestone14.0a2
bug 752648 - fix regression with restarting due to tls intolerance r=honzab a=akeybl
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)
@@ -1186,18 +1187,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
@@ -354,17 +354,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);
             }