1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=8 et tw=80 : */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 // HttpLog.h should generally be included first
8 #include "HttpLog.h"
9 
10 #include "Http2Session.h"
11 #include "nsHttp.h"
12 #include "nsHttpHandler.h"
13 #include "nsHttpRequestHead.h"
14 #include "TCPFastOpen.h"
15 #include "nsISocketProvider.h"
16 #include "nsISocketProviderService.h"
17 #include "nsISSLSocketControl.h"
18 #include "nsISocketTransport.h"
19 #include "nsISupportsPriority.h"
20 #include "nsNetAddr.h"
21 #include "prerror.h"
22 #include "prio.h"
23 #include "TunnelUtils.h"
24 #include "nsNetCID.h"
25 #include "nsServiceManagerUtils.h"
26 #include "nsComponentManagerUtils.h"
27 #include "nsSocketTransportService2.h"
28 
29 namespace mozilla {
30 namespace net {
31 
32 static PRDescIdentity sLayerIdentity;
33 static PRIOMethods sLayerMethods;
34 static PRIOMethods *sLayerMethodsPtr = nullptr;
35 
TLSFilterTransaction(nsAHttpTransaction * aWrapped,const char * aTLSHost,int32_t aTLSPort,nsAHttpSegmentReader * aReader,nsAHttpSegmentWriter * aWriter)36 TLSFilterTransaction::TLSFilterTransaction(nsAHttpTransaction *aWrapped,
37                                            const char *aTLSHost,
38                                            int32_t aTLSPort,
39                                            nsAHttpSegmentReader *aReader,
40                                            nsAHttpSegmentWriter *aWriter)
41     : mTransaction(aWrapped),
42       mEncryptedTextUsed(0),
43       mEncryptedTextSize(0),
44       mSegmentReader(aReader),
45       mSegmentWriter(aWriter),
46       mForce(false),
47       mNudgeCounter(0) {
48   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
49   LOG(("TLSFilterTransaction ctor %p\n", this));
50 
51   nsCOMPtr<nsISocketProvider> provider;
52   nsCOMPtr<nsISocketProviderService> spserv =
53       do_GetService(NS_SOCKETPROVIDERSERVICE_CONTRACTID);
54 
55   if (spserv) {
56     spserv->GetSocketProvider("ssl", getter_AddRefs(provider));
57   }
58 
59   // Install an NSPR layer to handle getpeername() with a failure. This is kind
60   // of silly, but the default one used by the pipe asserts when called and the
61   // nss code calls it to see if we are connected to a real socket or not.
62   if (!sLayerMethodsPtr) {
63     // one time initialization
64     sLayerIdentity = PR_GetUniqueIdentity("TLSFilterTransaction Layer");
65     sLayerMethods = *PR_GetDefaultIOMethods();
66     sLayerMethods.getpeername = GetPeerName;
67     sLayerMethods.getsocketoption = GetSocketOption;
68     sLayerMethods.setsocketoption = SetSocketOption;
69     sLayerMethods.read = FilterRead;
70     sLayerMethods.write = FilterWrite;
71     sLayerMethods.send = FilterSend;
72     sLayerMethods.recv = FilterRecv;
73     sLayerMethods.close = FilterClose;
74     sLayerMethodsPtr = &sLayerMethods;
75   }
76 
77   mFD = PR_CreateIOLayerStub(sLayerIdentity, &sLayerMethods);
78 
79   if (provider && mFD) {
80     mFD->secret = reinterpret_cast<PRFilePrivate *>(this);
81     provider->AddToSocket(PR_AF_INET, aTLSHost, aTLSPort, nullptr,
82                           OriginAttributes(), 0, 0, mFD,
83                           getter_AddRefs(mSecInfo));
84   }
85 
86   if (mTransaction) {
87     nsCOMPtr<nsIInterfaceRequestor> callbacks;
88     mTransaction->GetSecurityCallbacks(getter_AddRefs(callbacks));
89     nsCOMPtr<nsISSLSocketControl> secCtrl(do_QueryInterface(mSecInfo));
90     if (secCtrl) {
91       secCtrl->SetNotificationCallbacks(callbacks);
92     }
93   }
94 }
95 
~TLSFilterTransaction()96 TLSFilterTransaction::~TLSFilterTransaction() {
97   LOG(("TLSFilterTransaction dtor %p\n", this));
98   Cleanup();
99 }
100 
Cleanup()101 void TLSFilterTransaction::Cleanup() {
102   if (mTransaction) {
103     mTransaction->Close(NS_ERROR_ABORT);
104     mTransaction = nullptr;
105   }
106 
107   if (mFD) {
108     PR_Close(mFD);
109     mFD = nullptr;
110   }
111   mSecInfo = nullptr;
112   if (mTimer) {
113     mTimer->Cancel();
114     mTimer = nullptr;
115   }
116 }
117 
Close(nsresult aReason)118 void TLSFilterTransaction::Close(nsresult aReason) {
119   if (!mTransaction) {
120     return;
121   }
122 
123   if (mTimer) {
124     mTimer->Cancel();
125     mTimer = nullptr;
126   }
127   mTransaction->Close(aReason);
128   mTransaction = nullptr;
129 }
130 
OnReadSegment(const char * aData,uint32_t aCount,uint32_t * outCountRead)131 nsresult TLSFilterTransaction::OnReadSegment(const char *aData, uint32_t aCount,
132                                              uint32_t *outCountRead) {
133   LOG(("TLSFilterTransaction %p OnReadSegment %d (buffered %d)\n", this, aCount,
134        mEncryptedTextUsed));
135 
136   mReadSegmentBlocked = false;
137   MOZ_ASSERT(mSegmentReader);
138   if (!mSecInfo) {
139     return NS_ERROR_FAILURE;
140   }
141 
142   nsresult rv;
143   *outCountRead = 0;
144 
145   // get rid of buffer first
146   if (mEncryptedTextUsed) {
147     rv = mSegmentReader->CommitToSegmentSize(mEncryptedTextUsed, mForce);
148     if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
149       return rv;
150     }
151 
152     uint32_t amt;
153     rv = mSegmentReader->OnReadSegment(mEncryptedText.get(), mEncryptedTextUsed,
154                                        &amt);
155     if (NS_FAILED(rv)) {
156       return rv;
157     }
158 
159     mEncryptedTextUsed -= amt;
160     if (mEncryptedTextUsed) {
161       memmove(mEncryptedText.get(), &mEncryptedText[amt], mEncryptedTextUsed);
162       return NS_OK;
163     }
164   }
165 
166   // encrypt for network write
167   // write aData down the SSL layer into the FilterWrite() method where it will
168   // be queued into mEncryptedText. We need to copy it like this in order to
169   // guarantee atomic writes
170 
171   EnsureBuffer(mEncryptedText, aCount + 4096, 0, mEncryptedTextSize);
172 
173   while (aCount > 0) {
174     int32_t written = PR_Write(mFD, aData, aCount);
175     LOG(("TLSFilterTransaction %p OnReadSegment PRWrite(%d) = %d %d\n", this,
176          aCount, written, PR_GetError() == PR_WOULD_BLOCK_ERROR));
177 
178     if (written < 1) {
179       if (*outCountRead) {
180         return NS_OK;
181       }
182       // mTransaction ReadSegments actually obscures this code, so
183       // keep it in a member var for this::ReadSegments to insepct. Similar
184       // to nsHttpConnection::mSocketOutCondition
185       mReadSegmentBlocked = (PR_GetError() == PR_WOULD_BLOCK_ERROR);
186       return mReadSegmentBlocked ? NS_BASE_STREAM_WOULD_BLOCK
187                                  : NS_ERROR_FAILURE;
188     }
189     aCount -= written;
190     aData += written;
191     *outCountRead += written;
192     mNudgeCounter = 0;
193   }
194 
195   LOG(("TLSFilterTransaction %p OnReadSegment2 (buffered %d)\n", this,
196        mEncryptedTextUsed));
197 
198   uint32_t amt = 0;
199   if (mEncryptedTextUsed) {
200     // If we are tunneled on spdy CommitToSegmentSize will prevent partial
201     // writes that could interfere with multiplexing. H1 is fine with
202     // partial writes.
203     rv = mSegmentReader->CommitToSegmentSize(mEncryptedTextUsed, mForce);
204     if (rv != NS_BASE_STREAM_WOULD_BLOCK) {
205       rv = mSegmentReader->OnReadSegment(mEncryptedText.get(),
206                                          mEncryptedTextUsed, &amt);
207     }
208 
209     if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
210       // return OK because all the data was consumed and stored in this buffer
211       Connection()->TransactionHasDataToWrite(this);
212       return NS_OK;
213     } else if (NS_FAILED(rv)) {
214       return rv;
215     }
216   }
217 
218   if (amt == mEncryptedTextUsed) {
219     mEncryptedText = nullptr;
220     mEncryptedTextUsed = 0;
221     mEncryptedTextSize = 0;
222   } else {
223     memmove(mEncryptedText.get(), &mEncryptedText[amt],
224             mEncryptedTextUsed - amt);
225     mEncryptedTextUsed -= amt;
226   }
227   return NS_OK;
228 }
229 
FilterOutput(const char * aBuf,int32_t aAmount)230 int32_t TLSFilterTransaction::FilterOutput(const char *aBuf, int32_t aAmount) {
231   EnsureBuffer(mEncryptedText, mEncryptedTextUsed + aAmount, mEncryptedTextUsed,
232                mEncryptedTextSize);
233   memcpy(&mEncryptedText[mEncryptedTextUsed], aBuf, aAmount);
234   mEncryptedTextUsed += aAmount;
235   return aAmount;
236 }
237 
CommitToSegmentSize(uint32_t size,bool forceCommitment)238 nsresult TLSFilterTransaction::CommitToSegmentSize(uint32_t size,
239                                                    bool forceCommitment) {
240   if (!mSegmentReader) {
241     return NS_ERROR_FAILURE;
242   }
243 
244   // pad the commit by a little bit to leave room for encryption overhead
245   // this isn't foolproof and we may still have to buffer, but its a good start
246   mForce = forceCommitment;
247   return mSegmentReader->CommitToSegmentSize(size + 1024, forceCommitment);
248 }
249 
OnWriteSegment(char * aData,uint32_t aCount,uint32_t * outCountRead)250 nsresult TLSFilterTransaction::OnWriteSegment(char *aData, uint32_t aCount,
251                                               uint32_t *outCountRead) {
252   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
253   MOZ_ASSERT(mSegmentWriter);
254   LOG(("TLSFilterTransaction::OnWriteSegment %p max=%d\n", this, aCount));
255   if (!mSecInfo) {
256     return NS_ERROR_FAILURE;
257   }
258 
259   // this will call through to FilterInput to get data from the higher
260   // level connection before removing the local TLS layer
261   mFilterReadCode = NS_OK;
262   int32_t bytesRead = PR_Read(mFD, aData, aCount);
263   if (bytesRead == -1) {
264     if (PR_GetError() == PR_WOULD_BLOCK_ERROR) {
265       return NS_BASE_STREAM_WOULD_BLOCK;
266     }
267     return NS_ERROR_FAILURE;
268   }
269   *outCountRead = bytesRead;
270 
271   if (NS_SUCCEEDED(mFilterReadCode) && !bytesRead) {
272     LOG(
273         ("TLSFilterTransaction::OnWriteSegment %p "
274          "Second layer of TLS stripping results in STREAM_CLOSED\n",
275          this));
276     mFilterReadCode = NS_BASE_STREAM_CLOSED;
277   }
278 
279   LOG(("TLSFilterTransaction::OnWriteSegment %p rv=%" PRIx32 " didread=%d "
280        "2 layers of ssl stripped to plaintext\n",
281        this, static_cast<uint32_t>(mFilterReadCode), bytesRead));
282   return mFilterReadCode;
283 }
284 
FilterInput(char * aBuf,int32_t aAmount)285 int32_t TLSFilterTransaction::FilterInput(char *aBuf, int32_t aAmount) {
286   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
287   MOZ_ASSERT(mSegmentWriter);
288   LOG(("TLSFilterTransaction::FilterInput max=%d\n", aAmount));
289 
290   uint32_t outCountRead = 0;
291   mFilterReadCode =
292       mSegmentWriter->OnWriteSegment(aBuf, aAmount, &outCountRead);
293   if (NS_SUCCEEDED(mFilterReadCode) && outCountRead) {
294     LOG(("TLSFilterTransaction::FilterInput rv=%" PRIx32
295          " read=%d input from net "
296          "1 layer stripped, 1 still on\n",
297          static_cast<uint32_t>(mFilterReadCode), outCountRead));
298     if (mReadSegmentBlocked) {
299       mNudgeCounter = 0;
300     }
301   }
302   if (mFilterReadCode == NS_BASE_STREAM_WOULD_BLOCK) {
303     PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
304     return -1;
305   }
306   return outCountRead;
307 }
308 
ReadSegments(nsAHttpSegmentReader * aReader,uint32_t aCount,uint32_t * outCountRead)309 nsresult TLSFilterTransaction::ReadSegments(nsAHttpSegmentReader *aReader,
310                                             uint32_t aCount,
311                                             uint32_t *outCountRead) {
312   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
313   LOG(("TLSFilterTransaction::ReadSegments %p max=%d\n", this, aCount));
314 
315   if (!mTransaction) {
316     return NS_ERROR_UNEXPECTED;
317   }
318 
319   mReadSegmentBlocked = false;
320   mSegmentReader = aReader;
321   nsresult rv = mTransaction->ReadSegments(this, aCount, outCountRead);
322   LOG(("TLSFilterTransaction %p called trans->ReadSegments rv=%" PRIx32 " %d\n",
323        this, static_cast<uint32_t>(rv), *outCountRead));
324   if (NS_SUCCEEDED(rv) && mReadSegmentBlocked) {
325     rv = NS_BASE_STREAM_WOULD_BLOCK;
326     LOG(("TLSFilterTransaction %p read segment blocked found rv=%" PRIx32 "\n",
327          this, static_cast<uint32_t>(rv)));
328     Unused << Connection()->ForceSend();
329   }
330 
331   return rv;
332 }
333 
WriteSegments(nsAHttpSegmentWriter * aWriter,uint32_t aCount,uint32_t * outCountWritten)334 nsresult TLSFilterTransaction::WriteSegments(nsAHttpSegmentWriter *aWriter,
335                                              uint32_t aCount,
336                                              uint32_t *outCountWritten) {
337   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
338   LOG(("TLSFilterTransaction::WriteSegments %p max=%d\n", this, aCount));
339 
340   if (!mTransaction) {
341     return NS_ERROR_UNEXPECTED;
342   }
343 
344   mSegmentWriter = aWriter;
345   nsresult rv = mTransaction->WriteSegments(this, aCount, outCountWritten);
346   if (NS_SUCCEEDED(rv) && NS_FAILED(mFilterReadCode) && !(*outCountWritten)) {
347     // nsPipe turns failures into silent OK.. undo that!
348     rv = mFilterReadCode;
349     if (Connection() && (mFilterReadCode == NS_BASE_STREAM_WOULD_BLOCK)) {
350       Unused << Connection()->ResumeRecv();
351     }
352   }
353   LOG(("TLSFilterTransaction %p called trans->WriteSegments rv=%" PRIx32
354        " %d\n",
355        this, static_cast<uint32_t>(rv), *outCountWritten));
356   return rv;
357 }
358 
GetTransactionSecurityInfo(nsISupports ** outSecInfo)359 nsresult TLSFilterTransaction::GetTransactionSecurityInfo(
360     nsISupports **outSecInfo) {
361   if (!mSecInfo) {
362     return NS_ERROR_FAILURE;
363   }
364 
365   nsCOMPtr<nsISupports> temp(mSecInfo);
366   temp.forget(outSecInfo);
367   return NS_OK;
368 }
369 
NudgeTunnel(NudgeTunnelCallback * aCallback)370 nsresult TLSFilterTransaction::NudgeTunnel(NudgeTunnelCallback *aCallback) {
371   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
372   LOG(("TLSFilterTransaction %p NudgeTunnel\n", this));
373   mNudgeCallback = nullptr;
374 
375   if (!mSecInfo) {
376     return NS_ERROR_FAILURE;
377   }
378 
379   nsCOMPtr<nsISSLSocketControl> ssl(do_QueryInterface(mSecInfo));
380   nsresult rv = ssl ? ssl->DriveHandshake() : NS_ERROR_FAILURE;
381   if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) {
382     // fatal handshake failure
383     LOG(("TLSFilterTransaction %p Fatal Handshake Failure: %d\n", this,
384          PR_GetError()));
385     return NS_ERROR_FAILURE;
386   }
387 
388   uint32_t notUsed;
389   Unused << OnReadSegment("", 0, &notUsed);
390 
391   // The SSL Layer does some unusual things with PR_Poll that makes it a bad
392   // match for multiplexed SSL sessions. We work around this by manually polling
393   // for the moment during the brief handshake phase or otherwise blocked on
394   // write. Thankfully this is a pretty unusual state. NSPR doesn't help us here
395   // - asserting when polling without the NSPR IO layer on the bottom of the
396   // stack. As a follow-on we can do some NSPR and maybe libssl changes to make
397   // this more event driven, but this is acceptable for getting started.
398 
399   uint32_t counter = mNudgeCounter++;
400   uint32_t delay;
401 
402   if (!counter) {
403     delay = 0;
404   } else if (counter < 8) {  // up to 48ms at 6
405     delay = 6;
406   } else if (counter < 34) {  // up to 499 ms at 17ms
407     delay = 17;
408   } else {  // after that at 51ms (3 old windows ticks)
409     delay = 51;
410   }
411 
412   if (!mTimer) {
413     mTimer = NS_NewTimer();
414   }
415 
416   mNudgeCallback = aCallback;
417   if (!mTimer || NS_FAILED(mTimer->InitWithCallback(this, delay,
418                                                     nsITimer::TYPE_ONE_SHOT))) {
419     return StartTimerCallback();
420   }
421 
422   LOG(("TLSFilterTransaction %p NudgeTunnel timer started\n", this));
423   return NS_OK;
424 }
425 
426 NS_IMETHODIMP
Notify(nsITimer * timer)427 TLSFilterTransaction::Notify(nsITimer *timer) {
428   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
429   LOG(("TLSFilterTransaction %p NudgeTunnel notify\n", this));
430 
431   if (timer != mTimer) {
432     return NS_ERROR_UNEXPECTED;
433   }
434   DebugOnly<nsresult> rv = StartTimerCallback();
435   MOZ_ASSERT(NS_SUCCEEDED(rv));
436   return NS_OK;
437 }
438 
439 NS_IMETHODIMP
GetName(nsACString & aName)440 TLSFilterTransaction::GetName(nsACString &aName) {
441   aName.AssignLiteral("TLSFilterTransaction");
442   return NS_OK;
443 }
444 
StartTimerCallback()445 nsresult TLSFilterTransaction::StartTimerCallback() {
446   LOG(("TLSFilterTransaction %p NudgeTunnel StartTimerCallback %p\n", this,
447        mNudgeCallback.get()));
448 
449   if (mNudgeCallback) {
450     // This class can be called re-entrantly, so cleanup m* before ->on()
451     RefPtr<NudgeTunnelCallback> cb(mNudgeCallback);
452     mNudgeCallback = nullptr;
453     cb->OnTunnelNudged(this);
454   }
455   return NS_OK;
456 }
457 
GetPeerName(PRFileDesc * aFD,PRNetAddr * addr)458 PRStatus TLSFilterTransaction::GetPeerName(PRFileDesc *aFD, PRNetAddr *addr) {
459   NetAddr peeraddr;
460   TLSFilterTransaction *self =
461       reinterpret_cast<TLSFilterTransaction *>(aFD->secret);
462 
463   if (!self->mTransaction ||
464       NS_FAILED(self->mTransaction->Connection()->Transport()->GetPeerAddr(
465           &peeraddr))) {
466     return PR_FAILURE;
467   }
468   NetAddrToPRNetAddr(&peeraddr, addr);
469   return PR_SUCCESS;
470 }
471 
GetSocketOption(PRFileDesc * aFD,PRSocketOptionData * aOpt)472 PRStatus TLSFilterTransaction::GetSocketOption(PRFileDesc *aFD,
473                                                PRSocketOptionData *aOpt) {
474   if (aOpt->option == PR_SockOpt_Nonblocking) {
475     aOpt->value.non_blocking = PR_TRUE;
476     return PR_SUCCESS;
477   }
478   return PR_FAILURE;
479 }
480 
SetSocketOption(PRFileDesc * aFD,const PRSocketOptionData * aOpt)481 PRStatus TLSFilterTransaction::SetSocketOption(PRFileDesc *aFD,
482                                                const PRSocketOptionData *aOpt) {
483   return PR_FAILURE;
484 }
485 
FilterClose(PRFileDesc * aFD)486 PRStatus TLSFilterTransaction::FilterClose(PRFileDesc *aFD) {
487   return PR_SUCCESS;
488 }
489 
FilterWrite(PRFileDesc * aFD,const void * aBuf,int32_t aAmount)490 int32_t TLSFilterTransaction::FilterWrite(PRFileDesc *aFD, const void *aBuf,
491                                           int32_t aAmount) {
492   TLSFilterTransaction *self =
493       reinterpret_cast<TLSFilterTransaction *>(aFD->secret);
494   return self->FilterOutput(static_cast<const char *>(aBuf), aAmount);
495 }
496 
FilterSend(PRFileDesc * aFD,const void * aBuf,int32_t aAmount,int,PRIntervalTime)497 int32_t TLSFilterTransaction::FilterSend(PRFileDesc *aFD, const void *aBuf,
498                                          int32_t aAmount, int, PRIntervalTime) {
499   return FilterWrite(aFD, aBuf, aAmount);
500 }
501 
FilterRead(PRFileDesc * aFD,void * aBuf,int32_t aAmount)502 int32_t TLSFilterTransaction::FilterRead(PRFileDesc *aFD, void *aBuf,
503                                          int32_t aAmount) {
504   TLSFilterTransaction *self =
505       reinterpret_cast<TLSFilterTransaction *>(aFD->secret);
506   return self->FilterInput(static_cast<char *>(aBuf), aAmount);
507 }
508 
FilterRecv(PRFileDesc * aFD,void * aBuf,int32_t aAmount,int,PRIntervalTime)509 int32_t TLSFilterTransaction::FilterRecv(PRFileDesc *aFD, void *aBuf,
510                                          int32_t aAmount, int, PRIntervalTime) {
511   return FilterRead(aFD, aBuf, aAmount);
512 }
513 
514 /////
515 // The other methods of TLSFilterTransaction just call mTransaction->method
516 /////
517 
SetConnection(nsAHttpConnection * aConnection)518 void TLSFilterTransaction::SetConnection(nsAHttpConnection *aConnection) {
519   if (!mTransaction) {
520     return;
521   }
522 
523   mTransaction->SetConnection(aConnection);
524 }
525 
Connection()526 nsAHttpConnection *TLSFilterTransaction::Connection() {
527   if (!mTransaction) {
528     return nullptr;
529   }
530   return mTransaction->Connection();
531 }
532 
GetSecurityCallbacks(nsIInterfaceRequestor ** outCB)533 void TLSFilterTransaction::GetSecurityCallbacks(nsIInterfaceRequestor **outCB) {
534   if (!mTransaction) {
535     return;
536   }
537   mTransaction->GetSecurityCallbacks(outCB);
538 }
539 
OnTransportStatus(nsITransport * aTransport,nsresult aStatus,int64_t aProgress)540 void TLSFilterTransaction::OnTransportStatus(nsITransport *aTransport,
541                                              nsresult aStatus,
542                                              int64_t aProgress) {
543   if (!mTransaction) {
544     return;
545   }
546   mTransaction->OnTransportStatus(aTransport, aStatus, aProgress);
547 }
548 
ConnectionInfo()549 nsHttpConnectionInfo *TLSFilterTransaction::ConnectionInfo() {
550   if (!mTransaction) {
551     return nullptr;
552   }
553   return mTransaction->ConnectionInfo();
554 }
555 
IsDone()556 bool TLSFilterTransaction::IsDone() {
557   if (!mTransaction) {
558     return true;
559   }
560   return mTransaction->IsDone();
561 }
562 
Status()563 nsresult TLSFilterTransaction::Status() {
564   if (!mTransaction) {
565     return NS_ERROR_UNEXPECTED;
566   }
567 
568   return mTransaction->Status();
569 }
570 
Caps()571 uint32_t TLSFilterTransaction::Caps() {
572   if (!mTransaction) {
573     return 0;
574   }
575 
576   return mTransaction->Caps();
577 }
578 
SetDNSWasRefreshed()579 void TLSFilterTransaction::SetDNSWasRefreshed() {
580   if (!mTransaction) {
581     return;
582   }
583 
584   mTransaction->SetDNSWasRefreshed();
585 }
586 
SetProxyConnectFailed()587 void TLSFilterTransaction::SetProxyConnectFailed() {
588   if (!mTransaction) {
589     return;
590   }
591 
592   mTransaction->SetProxyConnectFailed();
593 }
594 
RequestHead()595 nsHttpRequestHead *TLSFilterTransaction::RequestHead() {
596   if (!mTransaction) {
597     return nullptr;
598   }
599 
600   return mTransaction->RequestHead();
601 }
602 
Http1xTransactionCount()603 uint32_t TLSFilterTransaction::Http1xTransactionCount() {
604   if (!mTransaction) {
605     return 0;
606   }
607 
608   return mTransaction->Http1xTransactionCount();
609 }
610 
TakeSubTransactions(nsTArray<RefPtr<nsAHttpTransaction>> & outTransactions)611 nsresult TLSFilterTransaction::TakeSubTransactions(
612     nsTArray<RefPtr<nsAHttpTransaction> > &outTransactions) {
613   LOG(("TLSFilterTransaction::TakeSubTransactions [this=%p] mTransaction %p\n",
614        this, mTransaction.get()));
615 
616   if (!mTransaction) {
617     return NS_ERROR_UNEXPECTED;
618   }
619 
620   if (mTransaction->TakeSubTransactions(outTransactions) ==
621       NS_ERROR_NOT_IMPLEMENTED) {
622     outTransactions.AppendElement(mTransaction);
623   }
624   mTransaction = nullptr;
625 
626   return NS_OK;
627 }
628 
SetProxiedTransaction(nsAHttpTransaction * aTrans)629 nsresult TLSFilterTransaction::SetProxiedTransaction(
630     nsAHttpTransaction *aTrans) {
631   LOG(("TLSFilterTransaction::SetProxiedTransaction [this=%p] aTrans=%p\n",
632        this, aTrans));
633 
634   mTransaction = aTrans;
635   nsCOMPtr<nsIInterfaceRequestor> callbacks;
636   mTransaction->GetSecurityCallbacks(getter_AddRefs(callbacks));
637   nsCOMPtr<nsISSLSocketControl> secCtrl(do_QueryInterface(mSecInfo));
638   if (secCtrl && callbacks) {
639     secCtrl->SetNotificationCallbacks(callbacks);
640   }
641 
642   return NS_OK;
643 }
644 
IsNullTransaction()645 bool TLSFilterTransaction::IsNullTransaction() {
646   if (!mTransaction) {
647     return false;
648   }
649   return mTransaction->IsNullTransaction();
650 }
651 
QueryNullTransaction()652 NullHttpTransaction *TLSFilterTransaction::QueryNullTransaction() {
653   if (!mTransaction) {
654     return nullptr;
655   }
656   return mTransaction->QueryNullTransaction();
657 }
658 
QueryHttpTransaction()659 nsHttpTransaction *TLSFilterTransaction::QueryHttpTransaction() {
660   if (!mTransaction) {
661     return nullptr;
662   }
663   return mTransaction->QueryHttpTransaction();
664 }
665 
666 class SocketInWrapper : public nsIAsyncInputStream,
667                         public nsAHttpSegmentWriter {
668   NS_DECL_THREADSAFE_ISUPPORTS
669   NS_FORWARD_NSIASYNCINPUTSTREAM(mStream->)
670 
SocketInWrapper(nsIAsyncInputStream * aWrapped,TLSFilterTransaction * aFilter)671   SocketInWrapper(nsIAsyncInputStream *aWrapped, TLSFilterTransaction *aFilter)
672       : mStream(aWrapped), mTLSFilter(aFilter) {}
673 
Close()674   NS_IMETHOD Close() override {
675     mTLSFilter = nullptr;
676     return mStream->Close();
677   }
678 
Available(uint64_t * _retval)679   NS_IMETHOD Available(uint64_t *_retval) override {
680     return mStream->Available(_retval);
681   }
682 
IsNonBlocking(bool * _retval)683   NS_IMETHOD IsNonBlocking(bool *_retval) override {
684     return mStream->IsNonBlocking(_retval);
685   }
686 
ReadSegments(nsWriteSegmentFun aWriter,void * aClosure,uint32_t aCount,uint32_t * _retval)687   NS_IMETHOD ReadSegments(nsWriteSegmentFun aWriter, void *aClosure,
688                           uint32_t aCount, uint32_t *_retval) override {
689     return mStream->ReadSegments(aWriter, aClosure, aCount, _retval);
690   }
691 
692   // finally, ones that don't get forwarded :)
693   NS_IMETHOD Read(char *aBuf, uint32_t aCount, uint32_t *_retval) override;
694   virtual nsresult OnWriteSegment(char *segment, uint32_t count,
695                                   uint32_t *countWritten) override;
696 
697  private:
~SocketInWrapper()698   virtual ~SocketInWrapper(){};
699 
700   nsCOMPtr<nsIAsyncInputStream> mStream;
701   RefPtr<TLSFilterTransaction> mTLSFilter;
702 };
703 
OnWriteSegment(char * segment,uint32_t count,uint32_t * countWritten)704 nsresult SocketInWrapper::OnWriteSegment(char *segment, uint32_t count,
705                                          uint32_t *countWritten) {
706   LOG(("SocketInWrapper OnWriteSegment %d %p filter=%p\n", count, this,
707        mTLSFilter.get()));
708 
709   nsresult rv = mStream->Read(segment, count, countWritten);
710   LOG(("SocketInWrapper OnWriteSegment %p wrapped read %" PRIx32 " %d\n", this,
711        static_cast<uint32_t>(rv), *countWritten));
712   return rv;
713 }
714 
715 NS_IMETHODIMP
Read(char * aBuf,uint32_t aCount,uint32_t * _retval)716 SocketInWrapper::Read(char *aBuf, uint32_t aCount, uint32_t *_retval) {
717   LOG(("SocketInWrapper Read %d %p filter=%p\n", aCount, this,
718        mTLSFilter.get()));
719 
720   if (!mTLSFilter) {
721     return NS_ERROR_UNEXPECTED;  // protect potentially dangling mTLSFilter
722   }
723 
724   // mTLSFilter->mSegmentWriter MUST be this at ctor time
725   return mTLSFilter->OnWriteSegment(aBuf, aCount, _retval);
726 }
727 
728 class SocketOutWrapper : public nsIAsyncOutputStream,
729                          public nsAHttpSegmentReader {
730   NS_DECL_THREADSAFE_ISUPPORTS
731   NS_FORWARD_NSIASYNCOUTPUTSTREAM(mStream->)
732 
SocketOutWrapper(nsIAsyncOutputStream * aWrapped,TLSFilterTransaction * aFilter)733   SocketOutWrapper(nsIAsyncOutputStream *aWrapped,
734                    TLSFilterTransaction *aFilter)
735       : mStream(aWrapped), mTLSFilter(aFilter) {}
736 
Close()737   NS_IMETHOD Close() override {
738     mTLSFilter = nullptr;
739     return mStream->Close();
740   }
741 
Flush()742   NS_IMETHOD Flush() override { return mStream->Flush(); }
743 
IsNonBlocking(bool * _retval)744   NS_IMETHOD IsNonBlocking(bool *_retval) override {
745     return mStream->IsNonBlocking(_retval);
746   }
747 
WriteSegments(nsReadSegmentFun aReader,void * aClosure,uint32_t aCount,uint32_t * _retval)748   NS_IMETHOD WriteSegments(nsReadSegmentFun aReader, void *aClosure,
749                            uint32_t aCount, uint32_t *_retval) override {
750     return mStream->WriteSegments(aReader, aClosure, aCount, _retval);
751   }
752 
WriteFrom(nsIInputStream * aFromStream,uint32_t aCount,uint32_t * _retval)753   NS_IMETHOD WriteFrom(nsIInputStream *aFromStream, uint32_t aCount,
754                        uint32_t *_retval) override {
755     return mStream->WriteFrom(aFromStream, aCount, _retval);
756   }
757 
758   // finally, ones that don't get forwarded :)
759   NS_IMETHOD Write(const char *aBuf, uint32_t aCount,
760                    uint32_t *_retval) override;
761   virtual nsresult OnReadSegment(const char *segment, uint32_t count,
762                                  uint32_t *countRead) override;
763 
764  private:
~SocketOutWrapper()765   virtual ~SocketOutWrapper(){};
766 
767   nsCOMPtr<nsIAsyncOutputStream> mStream;
768   RefPtr<TLSFilterTransaction> mTLSFilter;
769 };
770 
OnReadSegment(const char * segment,uint32_t count,uint32_t * countWritten)771 nsresult SocketOutWrapper::OnReadSegment(const char *segment, uint32_t count,
772                                          uint32_t *countWritten) {
773   return mStream->Write(segment, count, countWritten);
774 }
775 
776 NS_IMETHODIMP
Write(const char * aBuf,uint32_t aCount,uint32_t * _retval)777 SocketOutWrapper::Write(const char *aBuf, uint32_t aCount, uint32_t *_retval) {
778   LOG(("SocketOutWrapper Write %d %p filter=%p\n", aCount, this,
779        mTLSFilter.get()));
780 
781   // mTLSFilter->mSegmentReader MUST be this at ctor time
782   if (!mTLSFilter) {
783     return NS_ERROR_UNEXPECTED;  // protect potentially dangling mTLSFilter
784   }
785 
786   return mTLSFilter->OnReadSegment(aBuf, aCount, _retval);
787 }
788 
newIODriver(nsIAsyncInputStream * aSocketIn,nsIAsyncOutputStream * aSocketOut,nsIAsyncInputStream ** outSocketIn,nsIAsyncOutputStream ** outSocketOut)789 void TLSFilterTransaction::newIODriver(nsIAsyncInputStream *aSocketIn,
790                                        nsIAsyncOutputStream *aSocketOut,
791                                        nsIAsyncInputStream **outSocketIn,
792                                        nsIAsyncOutputStream **outSocketOut) {
793   SocketInWrapper *inputWrapper = new SocketInWrapper(aSocketIn, this);
794   mSegmentWriter = inputWrapper;
795   nsCOMPtr<nsIAsyncInputStream> newIn(inputWrapper);
796   newIn.forget(outSocketIn);
797 
798   SocketOutWrapper *outputWrapper = new SocketOutWrapper(aSocketOut, this);
799   mSegmentReader = outputWrapper;
800   nsCOMPtr<nsIAsyncOutputStream> newOut(outputWrapper);
801   newOut.forget(outSocketOut);
802 }
803 
QuerySpdyConnectTransaction()804 SpdyConnectTransaction *TLSFilterTransaction::QuerySpdyConnectTransaction() {
805   if (!mTransaction) {
806     return nullptr;
807   }
808   return mTransaction->QuerySpdyConnectTransaction();
809 }
810 
811 class SocketTransportShim : public nsISocketTransport {
812  public:
813   NS_DECL_THREADSAFE_ISUPPORTS
814   NS_DECL_NSITRANSPORT
815   NS_DECL_NSISOCKETTRANSPORT
816 
SocketTransportShim(nsISocketTransport * aWrapped)817   explicit SocketTransportShim(nsISocketTransport *aWrapped)
818       : mWrapped(aWrapped){};
819 
820  private:
~SocketTransportShim()821   virtual ~SocketTransportShim(){};
822 
823   nsCOMPtr<nsISocketTransport> mWrapped;
824 };
825 
826 class OutputStreamShim : public nsIAsyncOutputStream {
827  public:
828   NS_DECL_THREADSAFE_ISUPPORTS
829   NS_DECL_NSIOUTPUTSTREAM
830   NS_DECL_NSIASYNCOUTPUTSTREAM
831 
832   friend class SpdyConnectTransaction;
833 
OutputStreamShim(SpdyConnectTransaction * aTrans)834   explicit OutputStreamShim(SpdyConnectTransaction *aTrans)
835       : mCallback(nullptr), mStatus(NS_OK) {
836     mWeakTrans = do_GetWeakReference(aTrans);
837   }
838 
839  private:
~OutputStreamShim()840   virtual ~OutputStreamShim(){};
841 
842   nsWeakPtr mWeakTrans;  // SpdyConnectTransaction *
843   nsIOutputStreamCallback *mCallback;
844   nsresult mStatus;
845 };
846 
847 class InputStreamShim : public nsIAsyncInputStream {
848  public:
849   NS_DECL_THREADSAFE_ISUPPORTS
850   NS_DECL_NSIINPUTSTREAM
851   NS_DECL_NSIASYNCINPUTSTREAM
852 
853   friend class SpdyConnectTransaction;
854 
InputStreamShim(SpdyConnectTransaction * aTrans)855   explicit InputStreamShim(SpdyConnectTransaction *aTrans)
856       : mCallback(nullptr), mStatus(NS_OK) {
857     mWeakTrans = do_GetWeakReference(aTrans);
858   }
859 
860  private:
~InputStreamShim()861   virtual ~InputStreamShim(){};
862 
863   nsWeakPtr mWeakTrans;  // SpdyConnectTransaction *
864   nsIInputStreamCallback *mCallback;
865   nsresult mStatus;
866 };
867 
SpdyConnectTransaction(nsHttpConnectionInfo * ci,nsIInterfaceRequestor * callbacks,uint32_t caps,nsHttpTransaction * trans,nsAHttpConnection * session)868 SpdyConnectTransaction::SpdyConnectTransaction(nsHttpConnectionInfo *ci,
869                                                nsIInterfaceRequestor *callbacks,
870                                                uint32_t caps,
871                                                nsHttpTransaction *trans,
872                                                nsAHttpConnection *session)
873     : NullHttpTransaction(ci, callbacks, caps | NS_HTTP_ALLOW_KEEPALIVE),
874       mConnectStringOffset(0),
875       mSession(session),
876       mSegmentReader(nullptr),
877       mInputDataSize(0),
878       mInputDataUsed(0),
879       mInputDataOffset(0),
880       mOutputDataSize(0),
881       mOutputDataUsed(0),
882       mOutputDataOffset(0),
883       mForcePlainText(false) {
884   LOG(("SpdyConnectTransaction ctor %p\n", this));
885 
886   mTimestampSyn = TimeStamp::Now();
887   mRequestHead = new nsHttpRequestHead();
888   DebugOnly<nsresult> rv =
889       nsHttpConnection::MakeConnectString(trans, mRequestHead, mConnectString);
890   MOZ_ASSERT(NS_SUCCEEDED(rv));
891   mDrivingTransaction = trans;
892 }
893 
~SpdyConnectTransaction()894 SpdyConnectTransaction::~SpdyConnectTransaction() {
895   LOG(("SpdyConnectTransaction dtor %p\n", this));
896 
897   if (mDrivingTransaction) {
898     // requeue it I guess. This should be gone.
899     Unused << gHttpHandler->InitiateTransaction(
900         mDrivingTransaction, mDrivingTransaction->Priority());
901   }
902 }
903 
ForcePlainText()904 void SpdyConnectTransaction::ForcePlainText() {
905   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
906   MOZ_ASSERT(!mInputDataUsed && !mInputDataSize && !mInputDataOffset);
907   MOZ_ASSERT(!mForcePlainText);
908   MOZ_ASSERT(!mTunnelTransport, "call before mapstreamtohttpconnection");
909 
910   mForcePlainText = true;
911 }
912 
MapStreamToHttpConnection(nsISocketTransport * aTransport,nsHttpConnectionInfo * aConnInfo)913 void SpdyConnectTransaction::MapStreamToHttpConnection(
914     nsISocketTransport *aTransport, nsHttpConnectionInfo *aConnInfo) {
915   mConnInfo = aConnInfo;
916 
917   mTunnelTransport = new SocketTransportShim(aTransport);
918   mTunnelStreamIn = new InputStreamShim(this);
919   mTunnelStreamOut = new OutputStreamShim(this);
920   mTunneledConn = new nsHttpConnection();
921 
922   // this new http connection has a specific hashkey (i.e. to a particular
923   // host via the tunnel) and is associated with the tunnel streams
924   LOG(("SpdyConnectTransaction new httpconnection %p %s\n", mTunneledConn.get(),
925        aConnInfo->HashKey().get()));
926 
927   nsCOMPtr<nsIInterfaceRequestor> callbacks;
928   GetSecurityCallbacks(getter_AddRefs(callbacks));
929   mTunneledConn->SetTransactionCaps(Caps());
930   MOZ_ASSERT(aConnInfo->UsingHttpsProxy());
931   TimeDuration rtt = TimeStamp::Now() - mTimestampSyn;
932   DebugOnly<nsresult> rv = mTunneledConn->Init(
933       aConnInfo, gHttpHandler->ConnMgr()->MaxRequestDelay(), mTunnelTransport,
934       mTunnelStreamIn, mTunnelStreamOut, true, callbacks,
935       PR_MillisecondsToInterval(static_cast<uint32_t>(rtt.ToMilliseconds())));
936   MOZ_ASSERT(NS_SUCCEEDED(rv));
937   if (mForcePlainText) {
938     mTunneledConn->ForcePlainText();
939   } else {
940     mTunneledConn->SetupSecondaryTLS();
941     mTunneledConn->SetInSpdyTunnel(true);
942   }
943 
944   // make the originating transaction stick to the tunneled conn
945   RefPtr<nsAHttpConnection> wrappedConn =
946       gHttpHandler->ConnMgr()->MakeConnectionHandle(mTunneledConn);
947   mDrivingTransaction->SetConnection(wrappedConn);
948   mDrivingTransaction->MakeSticky();
949 
950   // jump the priority and start the dispatcher
951   Unused << gHttpHandler->InitiateTransaction(
952       mDrivingTransaction, nsISupportsPriority::PRIORITY_HIGHEST - 60);
953   mDrivingTransaction = nullptr;
954 }
955 
Flush(uint32_t count,uint32_t * countRead)956 nsresult SpdyConnectTransaction::Flush(uint32_t count, uint32_t *countRead) {
957   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
958   LOG(("SpdyConnectTransaction::Flush %p count %d avail %d\n", this, count,
959        mOutputDataUsed - mOutputDataOffset));
960 
961   if (!mSegmentReader) {
962     return NS_ERROR_UNEXPECTED;
963   }
964 
965   *countRead = 0;
966   count = std::min(count, (mOutputDataUsed - mOutputDataOffset));
967   if (count) {
968     nsresult rv;
969     rv = mSegmentReader->OnReadSegment(&mOutputData[mOutputDataOffset], count,
970                                        countRead);
971     if (NS_FAILED(rv) && (rv != NS_BASE_STREAM_WOULD_BLOCK)) {
972       LOG(("SpdyConnectTransaction::Flush %p Error %" PRIx32 "\n", this,
973            static_cast<uint32_t>(rv)));
974       CreateShimError(rv);
975       return rv;
976     }
977   }
978 
979   mOutputDataOffset += *countRead;
980   if (mOutputDataOffset == mOutputDataUsed) {
981     mOutputDataOffset = mOutputDataUsed = 0;
982   }
983   if (!(*countRead)) {
984     return NS_BASE_STREAM_WOULD_BLOCK;
985   }
986 
987   if (mOutputDataUsed != mOutputDataOffset) {
988     LOG(("SpdyConnectTransaction::Flush %p Incomplete %d\n", this,
989          mOutputDataUsed - mOutputDataOffset));
990     mSession->TransactionHasDataToWrite(this);
991   }
992 
993   return NS_OK;
994 }
995 
ReadSegments(nsAHttpSegmentReader * reader,uint32_t count,uint32_t * countRead)996 nsresult SpdyConnectTransaction::ReadSegments(nsAHttpSegmentReader *reader,
997                                               uint32_t count,
998                                               uint32_t *countRead) {
999   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
1000   LOG(("SpdyConnectTransaction::ReadSegments %p count %d conn %p\n", this,
1001        count, mTunneledConn.get()));
1002 
1003   mSegmentReader = reader;
1004 
1005   // spdy stream carrying tunnel is not setup yet.
1006   if (!mTunneledConn) {
1007     uint32_t toWrite = mConnectString.Length() - mConnectStringOffset;
1008     toWrite = std::min(toWrite, count);
1009     *countRead = toWrite;
1010     if (toWrite) {
1011       nsresult rv = mSegmentReader->OnReadSegment(
1012           mConnectString.BeginReading() + mConnectStringOffset, toWrite,
1013           countRead);
1014       if (NS_FAILED(rv) && (rv != NS_BASE_STREAM_WOULD_BLOCK)) {
1015         LOG(
1016             ("SpdyConnectTransaction::ReadSegments %p OnReadSegmentError "
1017              "%" PRIx32 "\n",
1018              this, static_cast<uint32_t>(rv)));
1019         CreateShimError(rv);
1020       } else {
1021         mConnectStringOffset += toWrite;
1022         if (mConnectString.Length() == mConnectStringOffset) {
1023           mConnectString.Truncate();
1024           mConnectStringOffset = 0;
1025         }
1026       }
1027       return rv;
1028     }
1029     return NS_BASE_STREAM_WOULD_BLOCK;
1030   }
1031 
1032   if (mForcePlainText) {
1033     // this path just ignores sending the request so that we can
1034     // send a synthetic reply in writesegments()
1035     LOG(
1036         ("SpdyConnectTransaciton::ReadSegments %p dropping %d output bytes "
1037          "due to synthetic reply\n",
1038          this, mOutputDataUsed - mOutputDataOffset));
1039     *countRead = mOutputDataUsed - mOutputDataOffset;
1040     mOutputDataOffset = mOutputDataUsed = 0;
1041     mTunneledConn->DontReuse();
1042     return NS_OK;
1043   }
1044 
1045   *countRead = 0;
1046   Unused << Flush(count, countRead);
1047   if (!mTunnelStreamOut->mCallback) {
1048     return NS_BASE_STREAM_WOULD_BLOCK;
1049   }
1050 
1051   nsresult rv =
1052       mTunnelStreamOut->mCallback->OnOutputStreamReady(mTunnelStreamOut);
1053   if (NS_FAILED(rv)) {
1054     return rv;
1055   }
1056 
1057   uint32_t subtotal;
1058   count -= *countRead;
1059   rv = Flush(count, &subtotal);
1060   *countRead += subtotal;
1061   return rv;
1062 }
1063 
CreateShimError(nsresult code)1064 void SpdyConnectTransaction::CreateShimError(nsresult code) {
1065   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
1066   MOZ_ASSERT(NS_FAILED(code));
1067 
1068   if (mTunnelStreamOut && NS_SUCCEEDED(mTunnelStreamOut->mStatus)) {
1069     mTunnelStreamOut->mStatus = code;
1070   }
1071 
1072   if (mTunnelStreamIn && NS_SUCCEEDED(mTunnelStreamIn->mStatus)) {
1073     mTunnelStreamIn->mStatus = code;
1074   }
1075 
1076   if (mTunnelStreamIn && mTunnelStreamIn->mCallback) {
1077     mTunnelStreamIn->mCallback->OnInputStreamReady(mTunnelStreamIn);
1078   }
1079 
1080   if (mTunnelStreamOut && mTunnelStreamOut->mCallback) {
1081     mTunnelStreamOut->mCallback->OnOutputStreamReady(mTunnelStreamOut);
1082   }
1083 }
1084 
WriteSegments(nsAHttpSegmentWriter * writer,uint32_t count,uint32_t * countWritten)1085 nsresult SpdyConnectTransaction::WriteSegments(nsAHttpSegmentWriter *writer,
1086                                                uint32_t count,
1087                                                uint32_t *countWritten) {
1088   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
1089   LOG(("SpdyConnectTransaction::WriteSegments %p max=%d cb=%p\n", this, count,
1090        mTunneledConn ? mTunnelStreamIn->mCallback : nullptr));
1091 
1092   // first call into the tunnel stream to get the demux'd data out of the
1093   // spdy session.
1094   EnsureBuffer(mInputData, mInputDataUsed + count, mInputDataUsed,
1095                mInputDataSize);
1096   nsresult rv =
1097       writer->OnWriteSegment(&mInputData[mInputDataUsed], count, countWritten);
1098   if (NS_FAILED(rv)) {
1099     if (rv != NS_BASE_STREAM_WOULD_BLOCK) {
1100       LOG(
1101           ("SpdyConnectTransaction::WriteSegments wrapped writer %p Error "
1102            "%" PRIx32 "\n",
1103            this, static_cast<uint32_t>(rv)));
1104       CreateShimError(rv);
1105     }
1106     return rv;
1107   }
1108   mInputDataUsed += *countWritten;
1109   LOG(
1110       ("SpdyConnectTransaction %p %d new bytes [%d total] of ciphered data "
1111        "buffered\n",
1112        this, *countWritten, mInputDataUsed - mInputDataOffset));
1113 
1114   if (!mTunneledConn || !mTunnelStreamIn->mCallback) {
1115     return NS_BASE_STREAM_WOULD_BLOCK;
1116   }
1117 
1118   rv = mTunnelStreamIn->mCallback->OnInputStreamReady(mTunnelStreamIn);
1119   LOG(
1120       ("SpdyConnectTransaction::WriteSegments %p "
1121        "after InputStreamReady callback %d total of ciphered data buffered "
1122        "rv=%" PRIx32 "\n",
1123        this, mInputDataUsed - mInputDataOffset, static_cast<uint32_t>(rv)));
1124   LOG(
1125       ("SpdyConnectTransaction::WriteSegments %p "
1126        "goodput %p out %" PRId64 "\n",
1127        this, mTunneledConn.get(), mTunneledConn->ContentBytesWritten()));
1128   if (NS_SUCCEEDED(rv) && !mTunneledConn->ContentBytesWritten()) {
1129     mTunnelStreamOut->AsyncWait(mTunnelStreamOut->mCallback, 0, 0, nullptr);
1130   }
1131   return rv;
1132 }
1133 
ConnectedReadyForInput()1134 bool SpdyConnectTransaction::ConnectedReadyForInput() {
1135   return mTunneledConn && mTunnelStreamIn->mCallback;
1136 }
1137 
RequestHead()1138 nsHttpRequestHead *SpdyConnectTransaction::RequestHead() {
1139   return mRequestHead;
1140 }
1141 
Close(nsresult code)1142 void SpdyConnectTransaction::Close(nsresult code) {
1143   LOG(("SpdyConnectTransaction close %p %" PRIx32 "\n", this,
1144        static_cast<uint32_t>(code)));
1145 
1146   NullHttpTransaction::Close(code);
1147   if (NS_FAILED(code) && (code != NS_BASE_STREAM_WOULD_BLOCK)) {
1148     CreateShimError(code);
1149   } else {
1150     CreateShimError(NS_BASE_STREAM_CLOSED);
1151   }
1152 }
1153 
1154 NS_IMETHODIMP
AsyncWait(nsIOutputStreamCallback * callback,unsigned int,unsigned int,nsIEventTarget * target)1155 OutputStreamShim::AsyncWait(nsIOutputStreamCallback *callback, unsigned int,
1156                             unsigned int, nsIEventTarget *target) {
1157   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
1158   bool currentThread;
1159 
1160   if (target && (NS_FAILED(target->IsOnCurrentThread(&currentThread)) ||
1161                  !currentThread)) {
1162     return NS_ERROR_FAILURE;
1163   }
1164 
1165   LOG(("OutputStreamShim::AsyncWait %p callback %p\n", this, callback));
1166   mCallback = callback;
1167 
1168   RefPtr<NullHttpTransaction> baseTrans(do_QueryReferent(mWeakTrans));
1169   if (!baseTrans) {
1170     return NS_ERROR_FAILURE;
1171   }
1172   SpdyConnectTransaction *trans = baseTrans->QuerySpdyConnectTransaction();
1173   MOZ_ASSERT(trans);
1174   if (!trans) {
1175     return NS_ERROR_UNEXPECTED;
1176   }
1177 
1178   trans->mSession->TransactionHasDataToWrite(trans);
1179 
1180   return NS_OK;
1181 }
1182 
1183 NS_IMETHODIMP
CloseWithStatus(nsresult reason)1184 OutputStreamShim::CloseWithStatus(nsresult reason) {
1185   RefPtr<NullHttpTransaction> baseTrans(do_QueryReferent(mWeakTrans));
1186   if (!baseTrans) {
1187     return NS_ERROR_FAILURE;
1188   }
1189   SpdyConnectTransaction *trans = baseTrans->QuerySpdyConnectTransaction();
1190   MOZ_ASSERT(trans);
1191   if (!trans) {
1192     return NS_ERROR_UNEXPECTED;
1193   }
1194 
1195   trans->mSession->CloseTransaction(trans, reason);
1196   return NS_OK;
1197 }
1198 
1199 NS_IMETHODIMP
Close()1200 OutputStreamShim::Close() { return CloseWithStatus(NS_OK); }
1201 
1202 NS_IMETHODIMP
Flush()1203 OutputStreamShim::Flush() {
1204   RefPtr<NullHttpTransaction> baseTrans(do_QueryReferent(mWeakTrans));
1205   if (!baseTrans) {
1206     return NS_ERROR_FAILURE;
1207   }
1208   SpdyConnectTransaction *trans = baseTrans->QuerySpdyConnectTransaction();
1209   MOZ_ASSERT(trans);
1210   if (!trans) {
1211     return NS_ERROR_UNEXPECTED;
1212   }
1213 
1214   uint32_t count = trans->mOutputDataUsed - trans->mOutputDataOffset;
1215   if (!count) {
1216     return NS_OK;
1217   }
1218 
1219   uint32_t countRead;
1220   nsresult rv = trans->Flush(count, &countRead);
1221   LOG(("OutputStreamShim::Flush %p before %d after %d\n", this, count,
1222        trans->mOutputDataUsed - trans->mOutputDataOffset));
1223   return rv;
1224 }
1225 
1226 NS_IMETHODIMP
Write(const char * aBuf,uint32_t aCount,uint32_t * _retval)1227 OutputStreamShim::Write(const char *aBuf, uint32_t aCount, uint32_t *_retval) {
1228   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
1229 
1230   if (NS_FAILED(mStatus)) {
1231     return mStatus;
1232   }
1233 
1234   RefPtr<NullHttpTransaction> baseTrans(do_QueryReferent(mWeakTrans));
1235   if (!baseTrans) {
1236     return NS_ERROR_FAILURE;
1237   }
1238   SpdyConnectTransaction *trans = baseTrans->QuerySpdyConnectTransaction();
1239   MOZ_ASSERT(trans);
1240   if (!trans) {
1241     return NS_ERROR_UNEXPECTED;
1242   }
1243 
1244   if ((trans->mOutputDataUsed + aCount) >= 512000) {
1245     *_retval = 0;
1246     // time for some flow control;
1247     return NS_BASE_STREAM_WOULD_BLOCK;
1248   }
1249 
1250   EnsureBuffer(trans->mOutputData, trans->mOutputDataUsed + aCount,
1251                trans->mOutputDataUsed, trans->mOutputDataSize);
1252   memcpy(&trans->mOutputData[trans->mOutputDataUsed], aBuf, aCount);
1253   trans->mOutputDataUsed += aCount;
1254   *_retval = aCount;
1255   LOG(("OutputStreamShim::Write %p new %d total %d\n", this, aCount,
1256        trans->mOutputDataUsed));
1257 
1258   trans->mSession->TransactionHasDataToWrite(trans);
1259 
1260   return NS_OK;
1261 }
1262 
1263 NS_IMETHODIMP
WriteFrom(nsIInputStream * aFromStream,uint32_t aCount,uint32_t * _retval)1264 OutputStreamShim::WriteFrom(nsIInputStream *aFromStream, uint32_t aCount,
1265                             uint32_t *_retval) {
1266   return NS_ERROR_NOT_IMPLEMENTED;
1267 }
1268 
1269 NS_IMETHODIMP
WriteSegments(nsReadSegmentFun aReader,void * aClosure,uint32_t aCount,uint32_t * _retval)1270 OutputStreamShim::WriteSegments(nsReadSegmentFun aReader, void *aClosure,
1271                                 uint32_t aCount, uint32_t *_retval) {
1272   return NS_ERROR_NOT_IMPLEMENTED;
1273 }
1274 
1275 NS_IMETHODIMP
IsNonBlocking(bool * _retval)1276 OutputStreamShim::IsNonBlocking(bool *_retval) {
1277   *_retval = true;
1278   return NS_OK;
1279 }
1280 
1281 NS_IMETHODIMP
AsyncWait(nsIInputStreamCallback * callback,unsigned int,unsigned int,nsIEventTarget * target)1282 InputStreamShim::AsyncWait(nsIInputStreamCallback *callback, unsigned int,
1283                            unsigned int, nsIEventTarget *target) {
1284   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
1285   bool currentThread;
1286 
1287   if (target && (NS_FAILED(target->IsOnCurrentThread(&currentThread)) ||
1288                  !currentThread)) {
1289     return NS_ERROR_FAILURE;
1290   }
1291 
1292   LOG(("InputStreamShim::AsyncWait %p callback %p\n", this, callback));
1293   mCallback = callback;
1294   return NS_OK;
1295 }
1296 
1297 NS_IMETHODIMP
CloseWithStatus(nsresult reason)1298 InputStreamShim::CloseWithStatus(nsresult reason) {
1299   RefPtr<NullHttpTransaction> baseTrans(do_QueryReferent(mWeakTrans));
1300   if (!baseTrans) {
1301     return NS_ERROR_FAILURE;
1302   }
1303   SpdyConnectTransaction *trans = baseTrans->QuerySpdyConnectTransaction();
1304   MOZ_ASSERT(trans);
1305   if (!trans) {
1306     return NS_ERROR_UNEXPECTED;
1307   }
1308 
1309   trans->mSession->CloseTransaction(trans, reason);
1310   return NS_OK;
1311 }
1312 
1313 NS_IMETHODIMP
Close()1314 InputStreamShim::Close() { return CloseWithStatus(NS_OK); }
1315 
1316 NS_IMETHODIMP
Available(uint64_t * _retval)1317 InputStreamShim::Available(uint64_t *_retval) {
1318   RefPtr<NullHttpTransaction> baseTrans(do_QueryReferent(mWeakTrans));
1319   if (!baseTrans) {
1320     return NS_ERROR_FAILURE;
1321   }
1322   SpdyConnectTransaction *trans = baseTrans->QuerySpdyConnectTransaction();
1323   MOZ_ASSERT(trans);
1324   if (!trans) {
1325     return NS_ERROR_UNEXPECTED;
1326   }
1327 
1328   *_retval = trans->mInputDataUsed - trans->mInputDataOffset;
1329   return NS_OK;
1330 }
1331 
1332 NS_IMETHODIMP
Read(char * aBuf,uint32_t aCount,uint32_t * _retval)1333 InputStreamShim::Read(char *aBuf, uint32_t aCount, uint32_t *_retval) {
1334   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
1335 
1336   if (NS_FAILED(mStatus)) {
1337     return mStatus;
1338   }
1339 
1340   RefPtr<NullHttpTransaction> baseTrans(do_QueryReferent(mWeakTrans));
1341   if (!baseTrans) {
1342     return NS_ERROR_FAILURE;
1343   }
1344   SpdyConnectTransaction *trans = baseTrans->QuerySpdyConnectTransaction();
1345   MOZ_ASSERT(trans);
1346   if (!trans) {
1347     return NS_ERROR_UNEXPECTED;
1348   }
1349 
1350   uint32_t avail = trans->mInputDataUsed - trans->mInputDataOffset;
1351   uint32_t tocopy = std::min(aCount, avail);
1352   *_retval = tocopy;
1353   memcpy(aBuf, &trans->mInputData[trans->mInputDataOffset], tocopy);
1354   trans->mInputDataOffset += tocopy;
1355   if (trans->mInputDataOffset == trans->mInputDataUsed) {
1356     trans->mInputDataOffset = trans->mInputDataUsed = 0;
1357   }
1358 
1359   return tocopy ? NS_OK : NS_BASE_STREAM_WOULD_BLOCK;
1360 }
1361 
1362 NS_IMETHODIMP
ReadSegments(nsWriteSegmentFun aWriter,void * aClosure,uint32_t aCount,uint32_t * _retval)1363 InputStreamShim::ReadSegments(nsWriteSegmentFun aWriter, void *aClosure,
1364                               uint32_t aCount, uint32_t *_retval) {
1365   return NS_ERROR_NOT_IMPLEMENTED;
1366 }
1367 
1368 NS_IMETHODIMP
IsNonBlocking(bool * _retval)1369 InputStreamShim::IsNonBlocking(bool *_retval) {
1370   *_retval = true;
1371   return NS_OK;
1372 }
1373 
1374 NS_IMETHODIMP
SetKeepaliveEnabled(bool aKeepaliveEnabled)1375 SocketTransportShim::SetKeepaliveEnabled(bool aKeepaliveEnabled) {
1376   return NS_ERROR_NOT_IMPLEMENTED;
1377 }
1378 
1379 NS_IMETHODIMP
SetKeepaliveVals(int32_t keepaliveIdleTime,int32_t keepaliveRetryInterval)1380 SocketTransportShim::SetKeepaliveVals(int32_t keepaliveIdleTime,
1381                                       int32_t keepaliveRetryInterval) {
1382   return NS_ERROR_NOT_IMPLEMENTED;
1383 }
1384 
1385 NS_IMETHODIMP
SetSecurityCallbacks(nsIInterfaceRequestor * aSecurityCallbacks)1386 SocketTransportShim::SetSecurityCallbacks(
1387     nsIInterfaceRequestor *aSecurityCallbacks) {
1388   return NS_ERROR_NOT_IMPLEMENTED;
1389 }
1390 
1391 NS_IMETHODIMP
OpenInputStream(uint32_t aFlags,uint32_t aSegmentSize,uint32_t aSegmentCount,nsIInputStream ** _retval)1392 SocketTransportShim::OpenInputStream(uint32_t aFlags, uint32_t aSegmentSize,
1393                                      uint32_t aSegmentCount,
1394                                      nsIInputStream **_retval) {
1395   return NS_ERROR_NOT_IMPLEMENTED;
1396 }
1397 
1398 NS_IMETHODIMP
OpenOutputStream(uint32_t aFlags,uint32_t aSegmentSize,uint32_t aSegmentCount,nsIOutputStream ** _retval)1399 SocketTransportShim::OpenOutputStream(uint32_t aFlags, uint32_t aSegmentSize,
1400                                       uint32_t aSegmentCount,
1401                                       nsIOutputStream **_retval) {
1402   return NS_ERROR_NOT_IMPLEMENTED;
1403 }
1404 
1405 NS_IMETHODIMP
Close(nsresult aReason)1406 SocketTransportShim::Close(nsresult aReason) {
1407   return NS_ERROR_NOT_IMPLEMENTED;
1408 }
1409 
1410 NS_IMETHODIMP
SetEventSink(nsITransportEventSink * aSink,nsIEventTarget * aEventTarget)1411 SocketTransportShim::SetEventSink(nsITransportEventSink *aSink,
1412                                   nsIEventTarget *aEventTarget) {
1413   return NS_ERROR_NOT_IMPLEMENTED;
1414 }
1415 
1416 NS_IMETHODIMP
Bind(NetAddr * aLocalAddr)1417 SocketTransportShim::Bind(NetAddr *aLocalAddr) {
1418   return NS_ERROR_NOT_IMPLEMENTED;
1419 }
1420 
1421 NS_IMETHODIMP
GetFirstRetryError(nsresult * aFirstRetryError)1422 SocketTransportShim::GetFirstRetryError(nsresult *aFirstRetryError) {
1423   return NS_ERROR_NOT_IMPLEMENTED;
1424 }
1425 
1426 #define FWD_TS_PTR(fx, ts) \
1427   NS_IMETHODIMP            \
1428   SocketTransportShim::fx(ts *arg) { return mWrapped->fx(arg); }
1429 
1430 #define FWD_TS_ADDREF(fx, ts) \
1431   NS_IMETHODIMP               \
1432   SocketTransportShim::fx(ts **arg) { return mWrapped->fx(arg); }
1433 
1434 #define FWD_TS(fx, ts) \
1435   NS_IMETHODIMP        \
1436   SocketTransportShim::fx(ts arg) { return mWrapped->fx(arg); }
1437 
1438 FWD_TS_PTR(GetKeepaliveEnabled, bool);
1439 FWD_TS_PTR(GetSendBufferSize, uint32_t);
1440 FWD_TS(SetSendBufferSize, uint32_t);
1441 FWD_TS_PTR(GetPort, int32_t);
1442 FWD_TS_PTR(GetPeerAddr, mozilla::net::NetAddr);
1443 FWD_TS_PTR(GetSelfAddr, mozilla::net::NetAddr);
1444 FWD_TS_ADDREF(GetScriptablePeerAddr, nsINetAddr);
1445 FWD_TS_ADDREF(GetScriptableSelfAddr, nsINetAddr);
1446 FWD_TS_ADDREF(GetSecurityInfo, nsISupports);
1447 FWD_TS_ADDREF(GetSecurityCallbacks, nsIInterfaceRequestor);
1448 FWD_TS_PTR(IsAlive, bool);
1449 FWD_TS_PTR(GetConnectionFlags, uint32_t);
1450 FWD_TS(SetConnectionFlags, uint32_t);
1451 FWD_TS_PTR(GetTlsFlags, uint32_t);
1452 FWD_TS(SetTlsFlags, uint32_t);
1453 FWD_TS_PTR(GetRecvBufferSize, uint32_t);
1454 FWD_TS(SetRecvBufferSize, uint32_t);
1455 
GetOriginAttributes(mozilla::OriginAttributes * aOriginAttributes)1456 nsresult SocketTransportShim::GetOriginAttributes(
1457     mozilla::OriginAttributes *aOriginAttributes) {
1458   return mWrapped->GetOriginAttributes(aOriginAttributes);
1459 }
1460 
SetOriginAttributes(const mozilla::OriginAttributes & aOriginAttributes)1461 nsresult SocketTransportShim::SetOriginAttributes(
1462     const mozilla::OriginAttributes &aOriginAttributes) {
1463   return mWrapped->SetOriginAttributes(aOriginAttributes);
1464 }
1465 
1466 NS_IMETHODIMP
GetScriptableOriginAttributes(JSContext * aCx,JS::MutableHandle<JS::Value> aOriginAttributes)1467 SocketTransportShim::GetScriptableOriginAttributes(
1468     JSContext *aCx, JS::MutableHandle<JS::Value> aOriginAttributes) {
1469   return mWrapped->GetScriptableOriginAttributes(aCx, aOriginAttributes);
1470 }
1471 
1472 NS_IMETHODIMP
SetScriptableOriginAttributes(JSContext * aCx,JS::Handle<JS::Value> aOriginAttributes)1473 SocketTransportShim::SetScriptableOriginAttributes(
1474     JSContext *aCx, JS::Handle<JS::Value> aOriginAttributes) {
1475   return mWrapped->SetScriptableOriginAttributes(aCx, aOriginAttributes);
1476 }
1477 
1478 NS_IMETHODIMP
GetHost(nsACString & aHost)1479 SocketTransportShim::GetHost(nsACString &aHost) {
1480   return mWrapped->GetHost(aHost);
1481 }
1482 
1483 NS_IMETHODIMP
GetTimeout(uint32_t aType,uint32_t * _retval)1484 SocketTransportShim::GetTimeout(uint32_t aType, uint32_t *_retval) {
1485   return mWrapped->GetTimeout(aType, _retval);
1486 }
1487 
1488 NS_IMETHODIMP
GetNetworkInterfaceId(nsACString & aNetworkInterfaceId)1489 SocketTransportShim::GetNetworkInterfaceId(nsACString &aNetworkInterfaceId) {
1490   return mWrapped->GetNetworkInterfaceId(aNetworkInterfaceId);
1491 }
1492 
1493 NS_IMETHODIMP
SetNetworkInterfaceId(const nsACString & aNetworkInterfaceId)1494 SocketTransportShim::SetNetworkInterfaceId(
1495     const nsACString &aNetworkInterfaceId) {
1496   return mWrapped->SetNetworkInterfaceId(aNetworkInterfaceId);
1497 }
1498 
1499 NS_IMETHODIMP
SetTimeout(uint32_t aType,uint32_t aValue)1500 SocketTransportShim::SetTimeout(uint32_t aType, uint32_t aValue) {
1501   return mWrapped->SetTimeout(aType, aValue);
1502 }
1503 
1504 NS_IMETHODIMP
SetReuseAddrPort(bool aReuseAddrPort)1505 SocketTransportShim::SetReuseAddrPort(bool aReuseAddrPort) {
1506   return mWrapped->SetReuseAddrPort(aReuseAddrPort);
1507 }
1508 
1509 NS_IMETHODIMP
GetQoSBits(uint8_t * aQoSBits)1510 SocketTransportShim::GetQoSBits(uint8_t *aQoSBits) {
1511   return mWrapped->GetQoSBits(aQoSBits);
1512 }
1513 
1514 NS_IMETHODIMP
SetQoSBits(uint8_t aQoSBits)1515 SocketTransportShim::SetQoSBits(uint8_t aQoSBits) {
1516   return mWrapped->SetQoSBits(aQoSBits);
1517 }
1518 
1519 NS_IMETHODIMP
SetFastOpenCallback(TCPFastOpen * aFastOpen)1520 SocketTransportShim::SetFastOpenCallback(TCPFastOpen *aFastOpen) {
1521   return mWrapped->SetFastOpenCallback(aFastOpen);
1522 }
1523 
1524 NS_IMPL_ISUPPORTS(TLSFilterTransaction, nsITimerCallback, nsINamed)
1525 NS_IMPL_ISUPPORTS(SocketTransportShim, nsISocketTransport, nsITransport)
1526 NS_IMPL_ISUPPORTS(InputStreamShim, nsIInputStream, nsIAsyncInputStream)
1527 NS_IMPL_ISUPPORTS(OutputStreamShim, nsIOutputStream, nsIAsyncOutputStream)
1528 NS_IMPL_ISUPPORTS(SocketInWrapper, nsIAsyncInputStream)
1529 NS_IMPL_ISUPPORTS(SocketOutWrapper, nsIAsyncOutputStream)
1530 
1531 }  // namespace net
1532 }  // namespace mozilla
1533