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 "nsISocketProvider.h"
15 #include "nsSocketProviderService.h"
16 #include "nsISSLSocketControl.h"
17 #include "nsISocketTransport.h"
18 #include "nsISupportsPriority.h"
19 #include "nsNetAddr.h"
20 #include "prerror.h"
21 #include "prio.h"
22 #include "TunnelUtils.h"
23 #include "nsNetCID.h"
24 #include "nsServiceManagerUtils.h"
25 #include "nsComponentManagerUtils.h"
26 #include "nsSocketTransport2.h"
27 #include "nsSocketTransportService2.h"
28 #include "mozilla/AutoRestore.h"
29 #include "mozilla/Mutex.h"
30 
31 #if defined(FUZZING)
32 #  include "FuzzySecurityInfo.h"
33 #  include "mozilla/StaticPrefs_fuzzing.h"
34 #endif
35 
36 namespace mozilla {
37 namespace net {
38 
39 static PRDescIdentity sLayerIdentity;
40 static PRIOMethods sLayerMethods;
41 static PRIOMethods* sLayerMethodsPtr = nullptr;
42 
TLSFilterTransaction(nsAHttpTransaction * aWrapped,const char * aTLSHost,int32_t aTLSPort,nsAHttpSegmentReader * aReader,nsAHttpSegmentWriter * aWriter)43 TLSFilterTransaction::TLSFilterTransaction(nsAHttpTransaction* aWrapped,
44                                            const char* aTLSHost,
45                                            int32_t aTLSPort,
46                                            nsAHttpSegmentReader* aReader,
47                                            nsAHttpSegmentWriter* aWriter)
48     : mTransaction(aWrapped),
49       mEncryptedTextUsed(0),
50       mEncryptedTextSize(0),
51       mSegmentReader(aReader),
52       mSegmentWriter(aWriter),
53       mFilterReadCode(NS_ERROR_NOT_INITIALIZED),
54       mFilterReadAmount(0),
55       mInOnReadSegment(false),
56       mForce(false),
57       mReadSegmentReturnValue(NS_OK),
58       mCloseReason(NS_ERROR_UNEXPECTED),
59       mNudgeCounter(0) {
60   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
61   LOG(("TLSFilterTransaction ctor %p\n", this));
62 
63   nsCOMPtr<nsISocketProvider> provider;
64   nsCOMPtr<nsISocketProviderService> spserv =
65       nsSocketProviderService::GetOrCreate();
66 
67   if (spserv) {
68     spserv->GetSocketProvider("ssl", getter_AddRefs(provider));
69   }
70 
71   // Install an NSPR layer to handle getpeername() with a failure. This is kind
72   // of silly, but the default one used by the pipe asserts when called and the
73   // nss code calls it to see if we are connected to a real socket or not.
74   if (!sLayerMethodsPtr) {
75     // one time initialization
76     sLayerIdentity = PR_GetUniqueIdentity("TLSFilterTransaction Layer");
77     sLayerMethods = *PR_GetDefaultIOMethods();
78     sLayerMethods.getpeername = GetPeerName;
79     sLayerMethods.getsocketoption = GetSocketOption;
80     sLayerMethods.setsocketoption = SetSocketOption;
81     sLayerMethods.read = FilterRead;
82     sLayerMethods.write = FilterWrite;
83     sLayerMethods.send = FilterSend;
84     sLayerMethods.recv = FilterRecv;
85     sLayerMethods.close = FilterClose;
86     sLayerMethodsPtr = &sLayerMethods;
87   }
88 
89   mFD = PR_CreateIOLayerStub(sLayerIdentity, &sLayerMethods);
90 
91   bool addTLSLayer = true;
92 #ifdef FUZZING
93   addTLSLayer = !StaticPrefs::fuzzing_necko_enabled();
94   if (!addTLSLayer) {
95     SOCKET_LOG(("Skipping TLS layer in TLSFilterTransaction for fuzzing.\n"));
96 
97     mSecInfo = static_cast<nsISupports*>(
98         static_cast<nsISSLSocketControl*>(new FuzzySecurityInfo()));
99   }
100 #endif
101 
102   if (provider && mFD) {
103     mFD->secret = reinterpret_cast<PRFilePrivate*>(this);
104 
105     if (addTLSLayer) {
106       provider->AddToSocket(PR_AF_INET, aTLSHost, aTLSPort, nullptr,
107                             OriginAttributes(), 0, 0, mFD,
108                             getter_AddRefs(mSecInfo));
109     }
110   }
111 
112   if (mTransaction) {
113     nsCOMPtr<nsIInterfaceRequestor> callbacks;
114     mTransaction->GetSecurityCallbacks(getter_AddRefs(callbacks));
115     nsCOMPtr<nsISSLSocketControl> secCtrl(do_QueryInterface(mSecInfo));
116     if (secCtrl) {
117       secCtrl->SetNotificationCallbacks(callbacks);
118     }
119   }
120 }
121 
~TLSFilterTransaction()122 TLSFilterTransaction::~TLSFilterTransaction() {
123   LOG(("TLSFilterTransaction dtor %p\n", this));
124 
125   // Prevent call to OnReadSegment from FilterOutput, our mSegmentReader is now
126   // an invalid pointer.
127   mInOnReadSegment = true;
128 
129   Cleanup();
130 }
131 
Cleanup()132 void TLSFilterTransaction::Cleanup() {
133   LOG(("TLSFilterTransaction::Cleanup %p", this));
134 
135   if (mTransaction) {
136     mTransaction->Close(NS_ERROR_ABORT);
137     mTransaction = nullptr;
138   }
139 
140   if (mFD) {
141     PR_Close(mFD);
142     mFD = nullptr;
143   }
144   mSecInfo = nullptr;
145   if (mTimer) {
146     mTimer->Cancel();
147     mTimer = nullptr;
148   }
149 }
150 
Close(nsresult aReason)151 void TLSFilterTransaction::Close(nsresult aReason) {
152   LOG(("TLSFilterTransaction::Close %p %" PRIx32, this,
153        static_cast<uint32_t>(aReason)));
154 
155   if (!mTransaction) {
156     return;
157   }
158 
159   if (mTimer) {
160     mTimer->Cancel();
161     mTimer = nullptr;
162   }
163   mTransaction->Close(aReason);
164   mTransaction = nullptr;
165 
166   if (gHttpHandler->Bug1563538()) {
167     if (NS_FAILED(aReason)) {
168       mCloseReason = aReason;
169     } else {
170       mCloseReason = NS_BASE_STREAM_CLOSED;
171     }
172   } else {
173     MOZ_ASSERT(NS_ERROR_UNEXPECTED == mCloseReason);
174   }
175 }
176 
OnReadSegment(const char * aData,uint32_t aCount,uint32_t * outCountRead)177 nsresult TLSFilterTransaction::OnReadSegment(const char* aData, uint32_t aCount,
178                                              uint32_t* outCountRead) {
179   LOG(("TLSFilterTransaction %p OnReadSegment %d (buffered %d)\n", this, aCount,
180        mEncryptedTextUsed));
181 
182   mReadSegmentReturnValue = NS_OK;
183   MOZ_ASSERT(mSegmentReader);
184   if (!mSecInfo) {
185     return NS_ERROR_FAILURE;
186   }
187 
188   nsresult rv;
189   *outCountRead = 0;
190 
191   // get rid of buffer first
192   if (mEncryptedTextUsed) {
193     rv = mSegmentReader->CommitToSegmentSize(mEncryptedTextUsed, mForce);
194     if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
195       return rv;
196     }
197 
198     uint32_t amt;
199     rv = mSegmentReader->OnReadSegment(mEncryptedText.get(), mEncryptedTextUsed,
200                                        &amt);
201     if (NS_FAILED(rv)) {
202       return rv;
203     }
204 
205     mEncryptedTextUsed -= amt;
206     if (mEncryptedTextUsed) {
207       memmove(mEncryptedText.get(), &mEncryptedText[amt], mEncryptedTextUsed);
208       return NS_OK;
209     }
210   }
211 
212   // encrypt for network write
213   // write aData down the SSL layer into the FilterWrite() method where it will
214   // be queued into mEncryptedText. We need to copy it like this in order to
215   // guarantee atomic writes
216 
217   EnsureBuffer(mEncryptedText, aCount + 4096, 0, mEncryptedTextSize);
218 
219   // Prevents call to OnReadSegment from inside FilterOutput, as we handle it
220   // here.
221   AutoRestore<bool> inOnReadSegment(mInOnReadSegment);
222   mInOnReadSegment = true;
223 
224   while (aCount > 0) {
225     int32_t written = PR_Write(mFD, aData, aCount);
226     LOG(("TLSFilterTransaction %p OnReadSegment PRWrite(%d) = %d %d\n", this,
227          aCount, written, PR_GetError() == PR_WOULD_BLOCK_ERROR));
228 
229     if (written < 1) {
230       if (*outCountRead) {
231         return NS_OK;
232       }
233       // mTransaction ReadSegments actually obscures this code, so
234       // keep it in a member var for this::ReadSegments to inspect. Similar
235       // to nsHttpConnection::mSocketOutCondition
236       PRErrorCode code = PR_GetError();
237       mReadSegmentReturnValue = ErrorAccordingToNSPR(code);
238 
239       return mReadSegmentReturnValue;
240     }
241     aCount -= written;
242     aData += written;
243     *outCountRead += written;
244     mNudgeCounter = 0;
245   }
246 
247   LOG(("TLSFilterTransaction %p OnReadSegment2 (buffered %d)\n", this,
248        mEncryptedTextUsed));
249 
250   uint32_t amt = 0;
251   if (mEncryptedTextUsed) {
252     // If we are tunneled on spdy CommitToSegmentSize will prevent partial
253     // writes that could interfere with multiplexing. H1 is fine with
254     // partial writes.
255     rv = mSegmentReader->CommitToSegmentSize(mEncryptedTextUsed, mForce);
256     if (rv != NS_BASE_STREAM_WOULD_BLOCK) {
257       rv = mSegmentReader->OnReadSegment(mEncryptedText.get(),
258                                          mEncryptedTextUsed, &amt);
259     }
260 
261     if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
262       // return OK because all the data was consumed and stored in this buffer
263       // It is fine if the connection is null.  We are likely a websocket and
264       // thus writing push is ensured by the caller.
265       if (Connection()) {
266         Connection()->TransactionHasDataToWrite(this);
267       }
268       return NS_OK;
269     }
270     if (NS_FAILED(rv)) {
271       return rv;
272     }
273   }
274 
275   if (amt == mEncryptedTextUsed) {
276     mEncryptedText = nullptr;
277     mEncryptedTextUsed = 0;
278     mEncryptedTextSize = 0;
279   } else {
280     memmove(mEncryptedText.get(), &mEncryptedText[amt],
281             mEncryptedTextUsed - amt);
282     mEncryptedTextUsed -= amt;
283   }
284   return NS_OK;
285 }
286 
FilterOutput(const char * aBuf,int32_t aAmount)287 int32_t TLSFilterTransaction::FilterOutput(const char* aBuf, int32_t aAmount) {
288   EnsureBuffer(mEncryptedText, mEncryptedTextUsed + aAmount, mEncryptedTextUsed,
289                mEncryptedTextSize);
290   memcpy(&mEncryptedText[mEncryptedTextUsed], aBuf, aAmount);
291   mEncryptedTextUsed += aAmount;
292 
293   LOG(("TLSFilterTransaction::FilterOutput %p %d buffered=%u mSegmentReader=%p",
294        this, aAmount, mEncryptedTextUsed, mSegmentReader));
295 
296   if (!mInOnReadSegment) {
297     // When called externally, we must make sure any newly written data is
298     // actually sent to the higher level connection.
299     // This also covers the case when PR_Read() wrote a re-negotioation
300     // response.
301     uint32_t notUsed;
302     Unused << OnReadSegment("", 0, &notUsed);
303   }
304 
305   return aAmount;
306 }
307 
CommitToSegmentSize(uint32_t size,bool forceCommitment)308 nsresult TLSFilterTransaction::CommitToSegmentSize(uint32_t size,
309                                                    bool forceCommitment) {
310   if (!mSegmentReader) {
311     return NS_ERROR_FAILURE;
312   }
313 
314   // pad the commit by a little bit to leave room for encryption overhead
315   // this isn't foolproof and we may still have to buffer, but its a good start
316   mForce = forceCommitment;
317   return mSegmentReader->CommitToSegmentSize(size + 1024, forceCommitment);
318 }
319 
OnWriteSegment(char * aData,uint32_t aCount,uint32_t * outCountRead)320 nsresult TLSFilterTransaction::OnWriteSegment(char* aData, uint32_t aCount,
321                                               uint32_t* outCountRead) {
322   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
323   MOZ_ASSERT(mSegmentWriter);
324   LOG(("TLSFilterTransaction::OnWriteSegment %p max=%d\n", this, aCount));
325   if (!mSecInfo) {
326     return NS_ERROR_FAILURE;
327   }
328 
329   // this will call through to FilterInput to get data from the higher
330   // level connection before removing the local TLS layer
331   mFilterReadCode = NS_OK;
332   mFilterReadAmount = 0;
333   int32_t bytesRead = PR_Read(mFD, aData, aCount);
334   if (bytesRead == -1) {
335     PRErrorCode code = PR_GetError();
336     if (code == PR_WOULD_BLOCK_ERROR) {
337       LOG(
338           ("TLSFilterTransaction::OnWriteSegment %p PR_Read would block, "
339            "actual read: %d\n",
340            this, mFilterReadAmount));
341 
342       if (mFilterReadAmount == 0 && NS_SUCCEEDED(mFilterReadCode)) {
343         // No reading happened, but also no error occured, hence there is no
344         // condition to break the `again` loop, propagate WOULD_BLOCK through
345         // mFilterReadCode to break it and poll the socket again for reading.
346         mFilterReadCode = NS_BASE_STREAM_WOULD_BLOCK;
347       }
348       return NS_BASE_STREAM_WOULD_BLOCK;
349     }
350     // If reading from the socket succeeded (NS_SUCCEEDED(mFilterReadCode)),
351     // but the nss layer encountered an error remember the error.
352     if (NS_SUCCEEDED(mFilterReadCode)) {
353       mFilterReadCode = ErrorAccordingToNSPR(code);
354       LOG(("TLSFilterTransaction::OnWriteSegment %p nss error %" PRIx32 ".\n",
355            this, static_cast<uint32_t>(mFilterReadCode)));
356     }
357     return mFilterReadCode;
358   }
359   *outCountRead = bytesRead;
360 
361   if (NS_SUCCEEDED(mFilterReadCode) && !bytesRead) {
362     LOG(
363         ("TLSFilterTransaction::OnWriteSegment %p "
364          "Second layer of TLS stripping results in STREAM_CLOSED\n",
365          this));
366     mFilterReadCode = NS_BASE_STREAM_CLOSED;
367   }
368 
369   LOG(("TLSFilterTransaction::OnWriteSegment %p rv=%" PRIx32 " didread=%d "
370        "2 layers of ssl stripped to plaintext\n",
371        this, static_cast<uint32_t>(mFilterReadCode), bytesRead));
372   return mFilterReadCode;
373 }
374 
FilterInput(char * aBuf,int32_t aAmount)375 int32_t TLSFilterTransaction::FilterInput(char* aBuf, int32_t aAmount) {
376   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
377   MOZ_ASSERT(mSegmentWriter);
378   LOG(("TLSFilterTransaction::FilterInput max=%d\n", aAmount));
379 
380   uint32_t outCountRead = 0;
381   mFilterReadCode =
382       mSegmentWriter->OnWriteSegment(aBuf, aAmount, &outCountRead);
383   if (NS_SUCCEEDED(mFilterReadCode) && outCountRead) {
384     LOG(("TLSFilterTransaction::FilterInput rv=%" PRIx32
385          " read=%d input from net "
386          "1 layer stripped, 1 still on\n",
387          static_cast<uint32_t>(mFilterReadCode), outCountRead));
388     if (mReadSegmentReturnValue == NS_BASE_STREAM_WOULD_BLOCK) {
389       mNudgeCounter = 0;
390     }
391 
392     mFilterReadAmount += outCountRead;
393   }
394   if (mFilterReadCode == NS_BASE_STREAM_WOULD_BLOCK) {
395     PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
396     return -1;
397   }
398   return outCountRead;
399 }
400 
ReadSegments(nsAHttpSegmentReader * aReader,uint32_t aCount,uint32_t * outCountRead)401 nsresult TLSFilterTransaction::ReadSegments(nsAHttpSegmentReader* aReader,
402                                             uint32_t aCount,
403                                             uint32_t* outCountRead) {
404   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
405   LOG(("TLSFilterTransaction::ReadSegments %p max=%d\n", this, aCount));
406 
407   if (!mTransaction) {
408     return mCloseReason;
409   }
410 
411   mReadSegmentReturnValue = NS_OK;
412   mSegmentReader = aReader;
413   nsresult rv = mTransaction->ReadSegments(this, aCount, outCountRead);
414 
415   // mSegmentReader is left assigned (not nullified) because we want to be able
416   // to call OnReadSegment directly, it expects mSegmentReader be non-null.
417 
418   LOG(("TLSFilterTransaction %p called trans->ReadSegments rv=%" PRIx32 " %d\n",
419        this, static_cast<uint32_t>(rv), *outCountRead));
420   if (NS_SUCCEEDED(rv) &&
421       (mReadSegmentReturnValue == NS_BASE_STREAM_WOULD_BLOCK)) {
422     LOG(("TLSFilterTransaction %p read segment blocked found rv=%" PRIx32 "\n",
423          this, static_cast<uint32_t>(rv)));
424     if (Connection()) {
425       Unused << Connection()->ForceSend();
426     }
427   }
428 
429   return NS_SUCCEEDED(rv) ? mReadSegmentReturnValue : rv;
430 }
431 
WriteSegmentsAgain(nsAHttpSegmentWriter * aWriter,uint32_t aCount,uint32_t * outCountWritten,bool * again)432 nsresult TLSFilterTransaction::WriteSegmentsAgain(nsAHttpSegmentWriter* aWriter,
433                                                   uint32_t aCount,
434                                                   uint32_t* outCountWritten,
435                                                   bool* again) {
436   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
437   LOG(("TLSFilterTransaction::WriteSegmentsAgain %p max=%d\n", this, aCount));
438 
439   if (!mTransaction) {
440     return mCloseReason;
441   }
442 
443   mSegmentWriter = aWriter;
444 
445   nsresult rv =
446       mTransaction->WriteSegmentsAgain(this, aCount, outCountWritten, again);
447 
448   if (NS_SUCCEEDED(rv) && !(*outCountWritten) && NS_FAILED(mFilterReadCode)) {
449     // nsPipe turns failures into silent OK.. undo that!
450     rv = mFilterReadCode;
451     if (Connection() && (mFilterReadCode == NS_BASE_STREAM_WOULD_BLOCK)) {
452       Unused << Connection()->ResumeRecv();
453     }
454   }
455   LOG(("TLSFilterTransaction %p called trans->WriteSegments rv=%" PRIx32
456        " %d\n",
457        this, static_cast<uint32_t>(rv), *outCountWritten));
458   return rv;
459 }
460 
WriteSegments(nsAHttpSegmentWriter * aWriter,uint32_t aCount,uint32_t * outCountWritten)461 nsresult TLSFilterTransaction::WriteSegments(nsAHttpSegmentWriter* aWriter,
462                                              uint32_t aCount,
463                                              uint32_t* outCountWritten) {
464   bool again = false;
465   return WriteSegmentsAgain(aWriter, aCount, outCountWritten, &again);
466 }
467 
GetTransactionSecurityInfo(nsISupports ** outSecInfo)468 nsresult TLSFilterTransaction::GetTransactionSecurityInfo(
469     nsISupports** outSecInfo) {
470   if (!mSecInfo) {
471     return NS_ERROR_FAILURE;
472   }
473 
474   nsCOMPtr<nsISupports> temp(mSecInfo);
475   temp.forget(outSecInfo);
476   return NS_OK;
477 }
478 
NudgeTunnel(NudgeTunnelCallback * aCallback)479 nsresult TLSFilterTransaction::NudgeTunnel(NudgeTunnelCallback* aCallback) {
480   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
481   LOG(("TLSFilterTransaction %p NudgeTunnel\n", this));
482   mNudgeCallback = nullptr;
483 
484   if (!mSecInfo) {
485     return NS_ERROR_FAILURE;
486   }
487 
488   nsCOMPtr<nsISSLSocketControl> ssl(do_QueryInterface(mSecInfo));
489   nsresult rv = ssl ? ssl->DriveHandshake() : NS_ERROR_FAILURE;
490   if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) {
491     // fatal handshake failure
492     LOG(("TLSFilterTransaction %p Fatal Handshake Failure: %d\n", this,
493          PR_GetError()));
494     return NS_ERROR_FAILURE;
495   }
496 
497   uint32_t notUsed;
498   Unused << OnReadSegment("", 0, &notUsed);
499 
500   // The SSL Layer does some unusual things with PR_Poll that makes it a bad
501   // match for multiplexed SSL sessions. We work around this by manually polling
502   // for the moment during the brief handshake phase or otherwise blocked on
503   // write. Thankfully this is a pretty unusual state. NSPR doesn't help us here
504   // - asserting when polling without the NSPR IO layer on the bottom of the
505   // stack. As a follow-on we can do some NSPR and maybe libssl changes to make
506   // this more event driven, but this is acceptable for getting started.
507 
508   uint32_t counter = mNudgeCounter++;
509   uint32_t delay;
510 
511   if (!counter) {
512     delay = 0;
513   } else if (counter < 8) {  // up to 48ms at 6
514     delay = 6;
515   } else if (counter < 34) {  // up to 499 ms at 17ms
516     delay = 17;
517   } else {  // after that at 51ms (3 old windows ticks)
518     delay = 51;
519   }
520 
521   if (!mTimer) {
522     mTimer = NS_NewTimer();
523   }
524 
525   mNudgeCallback = aCallback;
526   if (!mTimer || NS_FAILED(mTimer->InitWithCallback(this, delay,
527                                                     nsITimer::TYPE_ONE_SHOT))) {
528     return StartTimerCallback();
529   }
530 
531   LOG(("TLSFilterTransaction %p NudgeTunnel timer started\n", this));
532   return NS_OK;
533 }
534 
535 NS_IMETHODIMP
Notify(nsITimer * timer)536 TLSFilterTransaction::Notify(nsITimer* timer) {
537   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
538   LOG(("TLSFilterTransaction %p NudgeTunnel notify\n", this));
539 
540   if (timer != mTimer) {
541     return NS_ERROR_UNEXPECTED;
542   }
543   nsresult rv = StartTimerCallback();
544   if (NS_FAILED(rv)) {
545     Close(rv);
546   }
547   return NS_OK;
548 }
549 
550 NS_IMETHODIMP
GetName(nsACString & aName)551 TLSFilterTransaction::GetName(nsACString& aName) {
552   aName.AssignLiteral("TLSFilterTransaction");
553   return NS_OK;
554 }
555 
StartTimerCallback()556 nsresult TLSFilterTransaction::StartTimerCallback() {
557   LOG(("TLSFilterTransaction %p NudgeTunnel StartTimerCallback %p\n", this,
558        mNudgeCallback.get()));
559 
560   if (mNudgeCallback) {
561     // This class can be called re-entrantly, so cleanup m* before ->on()
562     RefPtr<NudgeTunnelCallback> cb(mNudgeCallback);
563     mNudgeCallback = nullptr;
564     return cb->OnTunnelNudged(this);
565   }
566   return NS_OK;
567 }
568 
HasDataToRecv()569 bool TLSFilterTransaction::HasDataToRecv() {
570   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
571   if (!mFD) {
572     return false;
573   }
574   int32_t n = 0;
575   char c;
576   n = PR_Recv(mFD, &c, 1, PR_MSG_PEEK, 0);
577   return n > 0;
578 }
579 
GetPeerName(PRFileDesc * aFD,PRNetAddr * addr)580 PRStatus TLSFilterTransaction::GetPeerName(PRFileDesc* aFD, PRNetAddr* addr) {
581   NetAddr peeraddr;
582   TLSFilterTransaction* self =
583       reinterpret_cast<TLSFilterTransaction*>(aFD->secret);
584 
585   if (!self->mTransaction ||
586       NS_FAILED(self->mTransaction->Connection()->Transport()->GetPeerAddr(
587           &peeraddr))) {
588     return PR_FAILURE;
589   }
590   NetAddrToPRNetAddr(&peeraddr, addr);
591   return PR_SUCCESS;
592 }
593 
GetSocketOption(PRFileDesc * aFD,PRSocketOptionData * aOpt)594 PRStatus TLSFilterTransaction::GetSocketOption(PRFileDesc* aFD,
595                                                PRSocketOptionData* aOpt) {
596   if (aOpt->option == PR_SockOpt_Nonblocking) {
597     aOpt->value.non_blocking = PR_TRUE;
598     return PR_SUCCESS;
599   }
600   return PR_FAILURE;
601 }
602 
SetSocketOption(PRFileDesc * aFD,const PRSocketOptionData * aOpt)603 PRStatus TLSFilterTransaction::SetSocketOption(PRFileDesc* aFD,
604                                                const PRSocketOptionData* aOpt) {
605   return PR_FAILURE;
606 }
607 
FilterClose(PRFileDesc * aFD)608 PRStatus TLSFilterTransaction::FilterClose(PRFileDesc* aFD) {
609   return PR_SUCCESS;
610 }
611 
FilterWrite(PRFileDesc * aFD,const void * aBuf,int32_t aAmount)612 int32_t TLSFilterTransaction::FilterWrite(PRFileDesc* aFD, const void* aBuf,
613                                           int32_t aAmount) {
614   TLSFilterTransaction* self =
615       reinterpret_cast<TLSFilterTransaction*>(aFD->secret);
616   return self->FilterOutput(static_cast<const char*>(aBuf), aAmount);
617 }
618 
FilterSend(PRFileDesc * aFD,const void * aBuf,int32_t aAmount,int,PRIntervalTime)619 int32_t TLSFilterTransaction::FilterSend(PRFileDesc* aFD, const void* aBuf,
620                                          int32_t aAmount, int, PRIntervalTime) {
621   return FilterWrite(aFD, aBuf, aAmount);
622 }
623 
FilterRead(PRFileDesc * aFD,void * aBuf,int32_t aAmount)624 int32_t TLSFilterTransaction::FilterRead(PRFileDesc* aFD, void* aBuf,
625                                          int32_t aAmount) {
626   TLSFilterTransaction* self =
627       reinterpret_cast<TLSFilterTransaction*>(aFD->secret);
628   return self->FilterInput(static_cast<char*>(aBuf), aAmount);
629 }
630 
FilterRecv(PRFileDesc * aFD,void * aBuf,int32_t aAmount,int,PRIntervalTime)631 int32_t TLSFilterTransaction::FilterRecv(PRFileDesc* aFD, void* aBuf,
632                                          int32_t aAmount, int, PRIntervalTime) {
633   return FilterRead(aFD, aBuf, aAmount);
634 }
635 
636 /////
637 // The other methods of TLSFilterTransaction just call mTransaction->method
638 /////
639 
SetConnection(nsAHttpConnection * aConnection)640 void TLSFilterTransaction::SetConnection(nsAHttpConnection* aConnection) {
641   if (!mTransaction) {
642     return;
643   }
644 
645   mTransaction->SetConnection(aConnection);
646 }
647 
Connection()648 nsAHttpConnection* TLSFilterTransaction::Connection() {
649   if (!mTransaction) {
650     return nullptr;
651   }
652   return mTransaction->Connection();
653 }
654 
GetSecurityCallbacks(nsIInterfaceRequestor ** outCB)655 void TLSFilterTransaction::GetSecurityCallbacks(nsIInterfaceRequestor** outCB) {
656   if (!mTransaction) {
657     return;
658   }
659   mTransaction->GetSecurityCallbacks(outCB);
660 }
661 
OnTransportStatus(nsITransport * aTransport,nsresult aStatus,int64_t aProgress)662 void TLSFilterTransaction::OnTransportStatus(nsITransport* aTransport,
663                                              nsresult aStatus,
664                                              int64_t aProgress) {
665   if (!mTransaction) {
666     return;
667   }
668   mTransaction->OnTransportStatus(aTransport, aStatus, aProgress);
669 }
670 
ConnectionInfo()671 nsHttpConnectionInfo* TLSFilterTransaction::ConnectionInfo() {
672   if (!mTransaction) {
673     return nullptr;
674   }
675   return mTransaction->ConnectionInfo();
676 }
677 
IsDone()678 bool TLSFilterTransaction::IsDone() {
679   if (!mTransaction) {
680     return true;
681   }
682   return mTransaction->IsDone();
683 }
684 
Status()685 nsresult TLSFilterTransaction::Status() {
686   if (!mTransaction) {
687     return NS_ERROR_UNEXPECTED;
688   }
689 
690   return mTransaction->Status();
691 }
692 
Caps()693 uint32_t TLSFilterTransaction::Caps() {
694   if (!mTransaction) {
695     return 0;
696   }
697 
698   return mTransaction->Caps();
699 }
700 
SetProxyConnectFailed()701 void TLSFilterTransaction::SetProxyConnectFailed() {
702   if (!mTransaction) {
703     return;
704   }
705 
706   mTransaction->SetProxyConnectFailed();
707 }
708 
RequestHead()709 nsHttpRequestHead* TLSFilterTransaction::RequestHead() {
710   if (!mTransaction) {
711     return nullptr;
712   }
713 
714   return mTransaction->RequestHead();
715 }
716 
Http1xTransactionCount()717 uint32_t TLSFilterTransaction::Http1xTransactionCount() {
718   if (!mTransaction) {
719     return 0;
720   }
721 
722   return mTransaction->Http1xTransactionCount();
723 }
724 
TakeSubTransactions(nsTArray<RefPtr<nsAHttpTransaction>> & outTransactions)725 nsresult TLSFilterTransaction::TakeSubTransactions(
726     nsTArray<RefPtr<nsAHttpTransaction> >& outTransactions) {
727   LOG(("TLSFilterTransaction::TakeSubTransactions [this=%p] mTransaction %p\n",
728        this, mTransaction.get()));
729 
730   if (!mTransaction) {
731     return NS_ERROR_UNEXPECTED;
732   }
733 
734   if (mTransaction->TakeSubTransactions(outTransactions) ==
735       NS_ERROR_NOT_IMPLEMENTED) {
736     outTransactions.AppendElement(mTransaction);
737   }
738   mTransaction = nullptr;
739 
740   return NS_OK;
741 }
742 
SetProxiedTransaction(nsAHttpTransaction * aTrans,nsAHttpTransaction * aSpdyConnectTransaction)743 nsresult TLSFilterTransaction::SetProxiedTransaction(
744     nsAHttpTransaction* aTrans, nsAHttpTransaction* aSpdyConnectTransaction) {
745   LOG(
746       ("TLSFilterTransaction::SetProxiedTransaction [this=%p] aTrans=%p, "
747        "aSpdyConnectTransaction=%p\n",
748        this, aTrans, aSpdyConnectTransaction));
749 
750   mTransaction = aTrans;
751 
752   // Reverting mCloseReason to the default value for consistency to indicate we
753   // are no longer in closed state.
754   mCloseReason = NS_ERROR_UNEXPECTED;
755 
756   nsCOMPtr<nsIInterfaceRequestor> callbacks;
757   mTransaction->GetSecurityCallbacks(getter_AddRefs(callbacks));
758   nsCOMPtr<nsISSLSocketControl> secCtrl(do_QueryInterface(mSecInfo));
759   if (secCtrl && callbacks) {
760     secCtrl->SetNotificationCallbacks(callbacks);
761   }
762 
763   mWeakTrans = do_GetWeakReference(aSpdyConnectTransaction);
764 
765   return NS_OK;
766 }
767 
IsNullTransaction()768 bool TLSFilterTransaction::IsNullTransaction() {
769   if (!mTransaction) {
770     return false;
771   }
772   return mTransaction->IsNullTransaction();
773 }
774 
QueryNullTransaction()775 NullHttpTransaction* TLSFilterTransaction::QueryNullTransaction() {
776   if (!mTransaction) {
777     return nullptr;
778   }
779   return mTransaction->QueryNullTransaction();
780 }
781 
QueryHttpTransaction()782 nsHttpTransaction* TLSFilterTransaction::QueryHttpTransaction() {
783   if (!mTransaction) {
784     return nullptr;
785   }
786   return mTransaction->QueryHttpTransaction();
787 }
788 
789 class SocketInWrapper : public nsIAsyncInputStream,
790                         public nsAHttpSegmentWriter {
791   NS_DECL_THREADSAFE_ISUPPORTS
792   NS_FORWARD_NSIASYNCINPUTSTREAM(mStream->)
793 
SocketInWrapper(nsIAsyncInputStream * aWrapped,TLSFilterTransaction * aFilter)794   SocketInWrapper(nsIAsyncInputStream* aWrapped, TLSFilterTransaction* aFilter)
795       : mStream(aWrapped), mTLSFilter(aFilter) {}
796 
Close()797   NS_IMETHOD Close() override {
798     mTLSFilter = nullptr;
799     return mStream->Close();
800   }
801 
Available(uint64_t * _retval)802   NS_IMETHOD Available(uint64_t* _retval) override {
803     return mStream->Available(_retval);
804   }
805 
IsNonBlocking(bool * _retval)806   NS_IMETHOD IsNonBlocking(bool* _retval) override {
807     return mStream->IsNonBlocking(_retval);
808   }
809 
ReadSegments(nsWriteSegmentFun aWriter,void * aClosure,uint32_t aCount,uint32_t * _retval)810   NS_IMETHOD ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
811                           uint32_t aCount, uint32_t* _retval) override {
812     return mStream->ReadSegments(aWriter, aClosure, aCount, _retval);
813   }
814 
815   // finally, ones that don't get forwarded :)
816   NS_IMETHOD Read(char* aBuf, uint32_t aCount, uint32_t* _retval) override;
817   virtual nsresult OnWriteSegment(char* segment, uint32_t count,
818                                   uint32_t* countWritten) override;
819 
820  private:
821   virtual ~SocketInWrapper() = default;
822   ;
823 
824   nsCOMPtr<nsIAsyncInputStream> mStream;
825   RefPtr<TLSFilterTransaction> mTLSFilter;
826 };
827 
OnWriteSegment(char * segment,uint32_t count,uint32_t * countWritten)828 nsresult SocketInWrapper::OnWriteSegment(char* segment, uint32_t count,
829                                          uint32_t* countWritten) {
830   LOG(("SocketInWrapper OnWriteSegment %d %p filter=%p\n", count, this,
831        mTLSFilter.get()));
832 
833   nsresult rv = mStream->Read(segment, count, countWritten);
834   LOG(("SocketInWrapper OnWriteSegment %p wrapped read %" PRIx32 " %d\n", this,
835        static_cast<uint32_t>(rv), *countWritten));
836   return rv;
837 }
838 
839 NS_IMETHODIMP
Read(char * aBuf,uint32_t aCount,uint32_t * _retval)840 SocketInWrapper::Read(char* aBuf, uint32_t aCount, uint32_t* _retval) {
841   LOG(("SocketInWrapper Read %d %p filter=%p\n", aCount, this,
842        mTLSFilter.get()));
843 
844   if (!mTLSFilter) {
845     return NS_ERROR_UNEXPECTED;  // protect potentially dangling mTLSFilter
846   }
847 
848   // mTLSFilter->mSegmentWriter MUST be this at ctor time
849   return mTLSFilter->OnWriteSegment(aBuf, aCount, _retval);
850 }
851 
852 class SocketOutWrapper : public nsIAsyncOutputStream,
853                          public nsAHttpSegmentReader {
854   NS_DECL_THREADSAFE_ISUPPORTS
855   NS_FORWARD_NSIASYNCOUTPUTSTREAM(mStream->)
856 
SocketOutWrapper(nsIAsyncOutputStream * aWrapped,TLSFilterTransaction * aFilter)857   SocketOutWrapper(nsIAsyncOutputStream* aWrapped,
858                    TLSFilterTransaction* aFilter)
859       : mStream(aWrapped), mTLSFilter(aFilter) {}
860 
Close()861   NS_IMETHOD Close() override {
862     mTLSFilter = nullptr;
863     return mStream->Close();
864   }
865 
Flush()866   NS_IMETHOD Flush() override { return mStream->Flush(); }
867 
IsNonBlocking(bool * _retval)868   NS_IMETHOD IsNonBlocking(bool* _retval) override {
869     return mStream->IsNonBlocking(_retval);
870   }
871 
WriteSegments(nsReadSegmentFun aReader,void * aClosure,uint32_t aCount,uint32_t * _retval)872   NS_IMETHOD WriteSegments(nsReadSegmentFun aReader, void* aClosure,
873                            uint32_t aCount, uint32_t* _retval) override {
874     return mStream->WriteSegments(aReader, aClosure, aCount, _retval);
875   }
876 
WriteFrom(nsIInputStream * aFromStream,uint32_t aCount,uint32_t * _retval)877   NS_IMETHOD WriteFrom(nsIInputStream* aFromStream, uint32_t aCount,
878                        uint32_t* _retval) override {
879     return mStream->WriteFrom(aFromStream, aCount, _retval);
880   }
881 
882   // finally, ones that don't get forwarded :)
883   NS_IMETHOD Write(const char* aBuf, uint32_t aCount,
884                    uint32_t* _retval) override;
885   virtual nsresult OnReadSegment(const char* segment, uint32_t count,
886                                  uint32_t* countWritten) override;
887 
888  private:
889   virtual ~SocketOutWrapper() = default;
890   ;
891 
892   nsCOMPtr<nsIAsyncOutputStream> mStream;
893   RefPtr<TLSFilterTransaction> mTLSFilter;
894 };
895 
OnReadSegment(const char * segment,uint32_t count,uint32_t * countWritten)896 nsresult SocketOutWrapper::OnReadSegment(const char* segment, uint32_t count,
897                                          uint32_t* countWritten) {
898   return mStream->Write(segment, count, countWritten);
899 }
900 
901 NS_IMETHODIMP
Write(const char * aBuf,uint32_t aCount,uint32_t * _retval)902 SocketOutWrapper::Write(const char* aBuf, uint32_t aCount, uint32_t* _retval) {
903   LOG(("SocketOutWrapper Write %d %p filter=%p\n", aCount, this,
904        mTLSFilter.get()));
905 
906   // mTLSFilter->mSegmentReader MUST be this at ctor time
907   if (!mTLSFilter) {
908     return NS_ERROR_UNEXPECTED;  // protect potentially dangling mTLSFilter
909   }
910 
911   return mTLSFilter->OnReadSegment(aBuf, aCount, _retval);
912 }
913 
newIODriver(nsIAsyncInputStream * aSocketIn,nsIAsyncOutputStream * aSocketOut,nsIAsyncInputStream ** outSocketIn,nsIAsyncOutputStream ** outSocketOut)914 void TLSFilterTransaction::newIODriver(nsIAsyncInputStream* aSocketIn,
915                                        nsIAsyncOutputStream* aSocketOut,
916                                        nsIAsyncInputStream** outSocketIn,
917                                        nsIAsyncOutputStream** outSocketOut) {
918   SocketInWrapper* inputWrapper = new SocketInWrapper(aSocketIn, this);
919   mSegmentWriter = inputWrapper;
920   nsCOMPtr<nsIAsyncInputStream> newIn(inputWrapper);
921   newIn.forget(outSocketIn);
922 
923   SocketOutWrapper* outputWrapper = new SocketOutWrapper(aSocketOut, this);
924   mSegmentReader = outputWrapper;
925   nsCOMPtr<nsIAsyncOutputStream> newOut(outputWrapper);
926   newOut.forget(outSocketOut);
927 }
928 
QuerySpdyConnectTransaction()929 SpdyConnectTransaction* TLSFilterTransaction::QuerySpdyConnectTransaction() {
930   if (!mTransaction) {
931     return nullptr;
932   }
933   return mTransaction->QuerySpdyConnectTransaction();
934 }
935 
936 class WeakTransProxy final : public nsISupports {
937  public:
938   NS_DECL_THREADSAFE_ISUPPORTS
939 
WeakTransProxy(SpdyConnectTransaction * aTrans)940   explicit WeakTransProxy(SpdyConnectTransaction* aTrans) {
941     MOZ_ASSERT(OnSocketThread());
942     mWeakTrans = do_GetWeakReference(aTrans);
943   }
944 
QueryTransaction()945   already_AddRefed<NullHttpTransaction> QueryTransaction() {
946     MOZ_ASSERT(OnSocketThread());
947     RefPtr<NullHttpTransaction> trans = do_QueryReferent(mWeakTrans);
948     return trans.forget();
949   }
950 
951  private:
~WeakTransProxy()952   ~WeakTransProxy() { MOZ_ASSERT(OnSocketThread()); }
953 
954   nsWeakPtr mWeakTrans;
955 };
956 
957 NS_IMPL_ISUPPORTS(WeakTransProxy, nsISupports)
958 
959 class WeakTransFreeProxy final : public Runnable {
960  public:
WeakTransFreeProxy(WeakTransProxy * proxy)961   explicit WeakTransFreeProxy(WeakTransProxy* proxy)
962       : Runnable("WeakTransFreeProxy"), mProxy(proxy) {}
963 
Run()964   NS_IMETHOD Run() override {
965     MOZ_ASSERT(OnSocketThread());
966     mProxy = nullptr;
967     return NS_OK;
968   }
969 
Dispatch()970   void Dispatch() {
971     MOZ_ASSERT(!OnSocketThread());
972     nsCOMPtr<nsIEventTarget> sts =
973         do_GetService("@mozilla.org/network/socket-transport-service;1");
974     Unused << sts->Dispatch(this, nsIEventTarget::DISPATCH_NORMAL);
975   }
976 
977  private:
978   RefPtr<WeakTransProxy> mProxy;
979 };
980 
981 class SocketTransportShim : public nsISocketTransport {
982  public:
983   NS_DECL_THREADSAFE_ISUPPORTS
984   NS_DECL_NSITRANSPORT
985   NS_DECL_NSISOCKETTRANSPORT
986 
SocketTransportShim(SpdyConnectTransaction * aTrans,nsISocketTransport * aWrapped,bool aIsWebsocket)987   explicit SocketTransportShim(SpdyConnectTransaction* aTrans,
988                                nsISocketTransport* aWrapped, bool aIsWebsocket)
989       : mWrapped(aWrapped), mIsWebsocket(aIsWebsocket) {
990     mWeakTrans = new WeakTransProxy(aTrans);
991   }
992 
993  private:
~SocketTransportShim()994   virtual ~SocketTransportShim() {
995     if (!OnSocketThread()) {
996       RefPtr<WeakTransFreeProxy> p = new WeakTransFreeProxy(mWeakTrans);
997       mWeakTrans = nullptr;
998       p->Dispatch();
999     }
1000   }
1001 
1002   nsCOMPtr<nsISocketTransport> mWrapped;
1003   bool mIsWebsocket;
1004   nsCOMPtr<nsIInterfaceRequestor> mSecurityCallbacks;
1005   RefPtr<WeakTransProxy> mWeakTrans;  // SpdyConnectTransaction *
1006 };
1007 
1008 class OutputStreamShim : public nsIAsyncOutputStream {
1009  public:
1010   NS_DECL_THREADSAFE_ISUPPORTS
1011   NS_DECL_NSIOUTPUTSTREAM
1012   NS_DECL_NSIASYNCOUTPUTSTREAM
1013 
1014   friend class SpdyConnectTransaction;
1015   friend class WebsocketHasDataToWrite;
1016   friend class OutputCloseTransaction;
1017 
OutputStreamShim(SpdyConnectTransaction * aTrans,bool aIsWebsocket)1018   OutputStreamShim(SpdyConnectTransaction* aTrans, bool aIsWebsocket)
1019       : mCallback(nullptr),
1020         mStatus(NS_OK),
1021         mMutex("OutputStreamShim"),
1022         mIsWebsocket(aIsWebsocket) {
1023     mWeakTrans = new WeakTransProxy(aTrans);
1024   }
1025 
1026   already_AddRefed<nsIOutputStreamCallback> TakeCallback();
1027 
1028  private:
~OutputStreamShim()1029   virtual ~OutputStreamShim() {
1030     if (!OnSocketThread()) {
1031       RefPtr<WeakTransFreeProxy> p = new WeakTransFreeProxy(mWeakTrans);
1032       mWeakTrans = nullptr;
1033       p->Dispatch();
1034     }
1035   }
1036 
1037   RefPtr<WeakTransProxy> mWeakTrans;  // SpdyConnectTransaction *
1038   nsCOMPtr<nsIOutputStreamCallback> mCallback;
1039   nsresult mStatus;
1040   mozilla::Mutex mMutex;
1041 
1042   // Websockets
1043   bool mIsWebsocket;
1044   nsresult CallTransactionHasDataToWrite();
1045   nsresult CloseTransaction(nsresult reason);
1046 };
1047 
1048 class InputStreamShim : public nsIAsyncInputStream {
1049  public:
1050   NS_DECL_THREADSAFE_ISUPPORTS
1051   NS_DECL_NSIINPUTSTREAM
1052   NS_DECL_NSIASYNCINPUTSTREAM
1053 
1054   friend class SpdyConnectTransaction;
1055   friend class InputCloseTransaction;
1056 
InputStreamShim(SpdyConnectTransaction * aTrans,bool aIsWebsocket)1057   InputStreamShim(SpdyConnectTransaction* aTrans, bool aIsWebsocket)
1058       : mCallback(nullptr),
1059         mStatus(NS_OK),
1060         mMutex("InputStreamShim"),
1061         mIsWebsocket(aIsWebsocket) {
1062     mWeakTrans = new WeakTransProxy(aTrans);
1063   }
1064 
1065   already_AddRefed<nsIInputStreamCallback> TakeCallback();
1066   bool HasCallback();
1067 
1068  private:
~InputStreamShim()1069   virtual ~InputStreamShim() {
1070     if (!OnSocketThread()) {
1071       RefPtr<WeakTransFreeProxy> p = new WeakTransFreeProxy(mWeakTrans);
1072       mWeakTrans = nullptr;
1073       p->Dispatch();
1074     }
1075   }
1076 
1077   RefPtr<WeakTransProxy> mWeakTrans;  // SpdyConnectTransaction *
1078   nsCOMPtr<nsIInputStreamCallback> mCallback;
1079   nsresult mStatus;
1080   mozilla::Mutex mMutex;
1081 
1082   // Websockets
1083   bool mIsWebsocket;
1084   nsresult CloseTransaction(nsresult reason);
1085 };
1086 
SpdyConnectTransaction(nsHttpConnectionInfo * ci,nsIInterfaceRequestor * callbacks,uint32_t caps,nsHttpTransaction * trans,nsAHttpConnection * session,bool isWebsocket)1087 SpdyConnectTransaction::SpdyConnectTransaction(
1088     nsHttpConnectionInfo* ci, nsIInterfaceRequestor* callbacks, uint32_t caps,
1089     nsHttpTransaction* trans, nsAHttpConnection* session, bool isWebsocket)
1090     : NullHttpTransaction(ci, callbacks, caps | NS_HTTP_ALLOW_KEEPALIVE),
1091       mConnectStringOffset(0),
1092       mSession(session),
1093       mSegmentReader(nullptr),
1094       mInputDataSize(0),
1095       mInputDataUsed(0),
1096       mInputDataOffset(0),
1097       mOutputDataSize(0),
1098       mOutputDataUsed(0),
1099       mOutputDataOffset(0),
1100       mForcePlainText(false),
1101       mIsWebsocket(isWebsocket),
1102       mConnRefTaken(false),
1103       mCreateShimErrorCalled(false) {
1104   LOG(("SpdyConnectTransaction ctor %p\n", this));
1105 
1106   mTimestampSyn = TimeStamp::Now();
1107   mRequestHead = new nsHttpRequestHead();
1108   if (mIsWebsocket) {
1109     // Ensure our request head has all the websocket headers duplicated from the
1110     // original transaction before calling the boilerplate stuff to create the
1111     // rest of the CONNECT headers.
1112     trans->RequestHead()->Enter();
1113     mRequestHead->SetHeaders(trans->RequestHead()->Headers());
1114     trans->RequestHead()->Exit();
1115   }
1116   DebugOnly<nsresult> rv = nsHttpConnection::MakeConnectString(
1117       trans, mRequestHead, mConnectString, mIsWebsocket);
1118   MOZ_ASSERT(NS_SUCCEEDED(rv));
1119   mDrivingTransaction = trans;
1120 }
1121 
~SpdyConnectTransaction()1122 SpdyConnectTransaction::~SpdyConnectTransaction() {
1123   LOG(("SpdyConnectTransaction dtor %p\n", this));
1124 
1125   MOZ_ASSERT(OnSocketThread());
1126 
1127   if (mDrivingTransaction) {
1128     // requeue it I guess. This should be gone.
1129     mDrivingTransaction->SetH2WSTransaction(nullptr);
1130     Unused << gHttpHandler->InitiateTransaction(
1131         mDrivingTransaction, mDrivingTransaction->Priority());
1132   }
1133 }
1134 
ForcePlainText()1135 void SpdyConnectTransaction::ForcePlainText() {
1136   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
1137   MOZ_ASSERT(!mInputDataUsed && !mInputDataSize && !mInputDataOffset);
1138   MOZ_ASSERT(!mForcePlainText);
1139   MOZ_ASSERT(!mTunnelTransport, "call before mapstreamtohttpconnection");
1140   MOZ_ASSERT(!mIsWebsocket);
1141 
1142   mForcePlainText = true;
1143 }
1144 
MapStreamToHttpConnection(nsISocketTransport * aTransport,nsHttpConnectionInfo * aConnInfo,const nsACString & aFlat407Headers,int32_t aHttpResponseCode)1145 bool SpdyConnectTransaction::MapStreamToHttpConnection(
1146     nsISocketTransport* aTransport, nsHttpConnectionInfo* aConnInfo,
1147     const nsACString& aFlat407Headers, int32_t aHttpResponseCode) {
1148   MOZ_ASSERT(OnSocketThread());
1149 
1150   if (aHttpResponseCode >= 100 && aHttpResponseCode < 200) {
1151     LOG(
1152         ("SpdyConnectTransaction::MapStreamToHttpConnection %p skip "
1153          "pre-response with response code %d",
1154          this, aHttpResponseCode));
1155     return false;
1156   }
1157 
1158   mTunnelTransport = new SocketTransportShim(this, aTransport, mIsWebsocket);
1159   mTunnelStreamIn = new InputStreamShim(this, mIsWebsocket);
1160   mTunnelStreamOut = new OutputStreamShim(this, mIsWebsocket);
1161   mTunneledConn = new nsHttpConnection();
1162 
1163   // If aHttpResponseCode is -1, it means that proxy connect is not used. We
1164   // should not call HttpProxyResponseToErrorCode(), since this will create a
1165   // shim error.
1166   if (aHttpResponseCode > 0 && aHttpResponseCode != 200) {
1167     nsresult err = HttpProxyResponseToErrorCode(aHttpResponseCode);
1168     if (NS_FAILED(err)) {
1169       CreateShimError(err);
1170     }
1171   }
1172 
1173   // this new http connection has a specific hashkey (i.e. to a particular
1174   // host via the tunnel) and is associated with the tunnel streams
1175   LOG(("SpdyConnectTransaction %p new httpconnection %p %s\n", this,
1176        mTunneledConn.get(), aConnInfo->HashKey().get()));
1177 
1178   nsCOMPtr<nsIInterfaceRequestor> callbacks;
1179   GetSecurityCallbacks(getter_AddRefs(callbacks));
1180   mTunneledConn->SetTransactionCaps(Caps());
1181   MOZ_ASSERT(aConnInfo->UsingHttpsProxy() || mIsWebsocket);
1182   TimeDuration rtt = TimeStamp::Now() - mTimestampSyn;
1183   DebugOnly<nsresult> rv = mTunneledConn->Init(
1184       aConnInfo, gHttpHandler->ConnMgr()->MaxRequestDelay(), mTunnelTransport,
1185       mTunnelStreamIn, mTunnelStreamOut, true, NS_OK, callbacks,
1186       PR_MillisecondsToInterval(static_cast<uint32_t>(rtt.ToMilliseconds())),
1187       false);
1188   MOZ_ASSERT(NS_SUCCEEDED(rv));
1189   if (mForcePlainText) {
1190     mTunneledConn->ForcePlainText();
1191   } else if (mIsWebsocket) {
1192     LOG(("SpdyConnectTransaction::MapStreamToHttpConnection %p websocket",
1193          this));
1194     // Let the root transaction know about us, so it can pass our own conn
1195     // to the websocket.
1196     mDrivingTransaction->SetH2WSTransaction(this);
1197   } else {
1198     mTunneledConn->SetupSecondaryTLS(this);
1199     mTunneledConn->SetInSpdyTunnel(true);
1200   }
1201 
1202   // make the originating transaction stick to the tunneled conn
1203   RefPtr<nsAHttpConnection> wrappedConn =
1204       gHttpHandler->ConnMgr()->MakeConnectionHandle(mTunneledConn);
1205   mDrivingTransaction->SetConnection(wrappedConn);
1206   mDrivingTransaction->MakeSticky();
1207 
1208   if (!mIsWebsocket) {
1209     mDrivingTransaction->OnProxyConnectComplete(aHttpResponseCode);
1210 
1211     if (aHttpResponseCode == 407) {
1212       mDrivingTransaction->SetFlat407Headers(aFlat407Headers);
1213       mDrivingTransaction->SetProxyConnectFailed();
1214     }
1215 
1216     // jump the priority and start the dispatcher
1217     Unused << gHttpHandler->InitiateTransaction(
1218         mDrivingTransaction, nsISupportsPriority::PRIORITY_HIGHEST - 60);
1219     mDrivingTransaction = nullptr;
1220   }
1221 
1222   return true;
1223 }
1224 
Flush(uint32_t count,uint32_t * countRead)1225 nsresult SpdyConnectTransaction::Flush(uint32_t count, uint32_t* countRead) {
1226   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
1227   LOG(("SpdyConnectTransaction::Flush %p count %d avail %d\n", this, count,
1228        mOutputDataUsed - mOutputDataOffset));
1229 
1230   if (!mSegmentReader) {
1231     return NS_ERROR_UNEXPECTED;
1232   }
1233 
1234   *countRead = 0;
1235   count = std::min(count, (mOutputDataUsed - mOutputDataOffset));
1236   if (count) {
1237     nsresult rv;
1238     rv = mSegmentReader->OnReadSegment(&mOutputData[mOutputDataOffset], count,
1239                                        countRead);
1240     if (NS_FAILED(rv) && (rv != NS_BASE_STREAM_WOULD_BLOCK)) {
1241       LOG(("SpdyConnectTransaction::Flush %p Error %" PRIx32 "\n", this,
1242            static_cast<uint32_t>(rv)));
1243       CreateShimError(rv);
1244       return rv;
1245     }
1246   }
1247 
1248   mOutputDataOffset += *countRead;
1249   if (mOutputDataOffset == mOutputDataUsed) {
1250     mOutputDataOffset = mOutputDataUsed = 0;
1251   }
1252   if (!(*countRead)) {
1253     return NS_BASE_STREAM_WOULD_BLOCK;
1254   }
1255 
1256   if (mOutputDataUsed != mOutputDataOffset) {
1257     LOG(("SpdyConnectTransaction::Flush %p Incomplete %d\n", this,
1258          mOutputDataUsed - mOutputDataOffset));
1259     mSession->TransactionHasDataToWrite(this);
1260   }
1261 
1262   return NS_OK;
1263 }
1264 
ReadSegments(nsAHttpSegmentReader * reader,uint32_t count,uint32_t * countRead)1265 nsresult SpdyConnectTransaction::ReadSegments(nsAHttpSegmentReader* reader,
1266                                               uint32_t count,
1267                                               uint32_t* countRead) {
1268   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
1269   LOG(("SpdyConnectTransaction::ReadSegments %p count %d conn %p\n", this,
1270        count, mTunneledConn.get()));
1271 
1272   mSegmentReader = reader;
1273 
1274   // spdy stream carrying tunnel is not setup yet.
1275   if (!mTunneledConn) {
1276     uint32_t toWrite = mConnectString.Length() - mConnectStringOffset;
1277     toWrite = std::min(toWrite, count);
1278     *countRead = toWrite;
1279     if (toWrite) {
1280       nsresult rv = mSegmentReader->OnReadSegment(
1281           mConnectString.BeginReading() + mConnectStringOffset, toWrite,
1282           countRead);
1283       if (NS_FAILED(rv) && (rv != NS_BASE_STREAM_WOULD_BLOCK)) {
1284         LOG(
1285             ("SpdyConnectTransaction::ReadSegments %p OnReadSegmentError "
1286              "%" PRIx32 "\n",
1287              this, static_cast<uint32_t>(rv)));
1288         CreateShimError(rv);
1289       } else {
1290         mConnectStringOffset += toWrite;
1291         if (mConnectString.Length() == mConnectStringOffset) {
1292           mConnectString.Truncate();
1293           mConnectStringOffset = 0;
1294         }
1295       }
1296       return rv;
1297     }
1298 
1299     LOG(("SpdyConnectTransaciton::ReadSegments %p connect request consumed",
1300          this));
1301     return NS_BASE_STREAM_WOULD_BLOCK;
1302   }
1303 
1304   if (mForcePlainText) {
1305     // this path just ignores sending the request so that we can
1306     // send a synthetic reply in writesegments()
1307     LOG(
1308         ("SpdyConnectTransaciton::ReadSegments %p dropping %d output bytes "
1309          "due to synthetic reply\n",
1310          this, mOutputDataUsed - mOutputDataOffset));
1311     *countRead = mOutputDataUsed - mOutputDataOffset;
1312     mOutputDataOffset = mOutputDataUsed = 0;
1313     mTunneledConn->DontReuse();
1314     return NS_OK;
1315   }
1316 
1317   *countRead = 0;
1318   nsresult rv = Flush(count, countRead);
1319   if (!(*countRead)) {
1320     return NS_BASE_STREAM_WOULD_BLOCK;
1321   }
1322 
1323   nsCOMPtr<nsIOutputStreamCallback> cb = mTunnelStreamOut->TakeCallback();
1324   if (!cb) {
1325     return NS_BASE_STREAM_WOULD_BLOCK;
1326   }
1327 
1328   // See if there is any more data available
1329   rv = cb->OnOutputStreamReady(mTunnelStreamOut);
1330   if (NS_FAILED(rv)) {
1331     return rv;
1332   }
1333 
1334   // Write out anything that may have come out of the stream just above
1335   uint32_t subtotal;
1336   count -= *countRead;
1337   rv = Flush(count, &subtotal);
1338   *countRead += subtotal;
1339 
1340   return rv;
1341 }
1342 
CreateShimError(nsresult code)1343 void SpdyConnectTransaction::CreateShimError(nsresult code) {
1344   LOG(("SpdyConnectTransaction::CreateShimError %p 0x%08" PRIx32, this,
1345        static_cast<uint32_t>(code)));
1346 
1347   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
1348   MOZ_ASSERT(NS_FAILED(code));
1349 
1350   MOZ_ASSERT(!mCreateShimErrorCalled);
1351   if (mCreateShimErrorCalled) {
1352     return;
1353   }
1354   mCreateShimErrorCalled = true;
1355 
1356   if (mTunnelStreamOut && NS_SUCCEEDED(mTunnelStreamOut->mStatus)) {
1357     mTunnelStreamOut->mStatus = code;
1358   }
1359 
1360   if (mTunnelStreamIn && NS_SUCCEEDED(mTunnelStreamIn->mStatus)) {
1361     mTunnelStreamIn->mStatus = code;
1362   }
1363 
1364   if (mTunnelStreamIn) {
1365     nsCOMPtr<nsIInputStreamCallback> cb = mTunnelStreamIn->TakeCallback();
1366     if (cb) {
1367       cb->OnInputStreamReady(mTunnelStreamIn);
1368     }
1369   }
1370 
1371   if (mTunnelStreamOut) {
1372     nsCOMPtr<nsIOutputStreamCallback> cb = mTunnelStreamOut->TakeCallback();
1373     if (cb) {
1374       cb->OnOutputStreamReady(mTunnelStreamOut);
1375     }
1376   }
1377   mCreateShimErrorCalled = false;
1378 }
1379 
WriteDataToBuffer(nsAHttpSegmentWriter * writer,uint32_t count,uint32_t * countWritten)1380 nsresult SpdyConnectTransaction::WriteDataToBuffer(nsAHttpSegmentWriter* writer,
1381                                                    uint32_t count,
1382                                                    uint32_t* countWritten) {
1383   EnsureBuffer(mInputData, mInputDataUsed + count, mInputDataUsed,
1384                mInputDataSize);
1385   nsresult rv =
1386       writer->OnWriteSegment(&mInputData[mInputDataUsed], count, countWritten);
1387   if (NS_FAILED(rv)) {
1388     if (rv != NS_BASE_STREAM_WOULD_BLOCK) {
1389       LOG(
1390           ("SpdyConnectTransaction::WriteSegments wrapped writer %p Error "
1391            "%" PRIx32 "\n",
1392            this, static_cast<uint32_t>(rv)));
1393       CreateShimError(rv);
1394     }
1395     return rv;
1396   }
1397   mInputDataUsed += *countWritten;
1398   LOG(
1399       ("SpdyConnectTransaction %p %d new bytes [%d total] of ciphered data "
1400        "buffered\n",
1401        this, *countWritten, mInputDataUsed - mInputDataOffset));
1402 
1403   return rv;
1404 }
1405 
WriteSegments(nsAHttpSegmentWriter * writer,uint32_t count,uint32_t * countWritten)1406 nsresult SpdyConnectTransaction::WriteSegments(nsAHttpSegmentWriter* writer,
1407                                                uint32_t count,
1408                                                uint32_t* countWritten) {
1409   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
1410   LOG(("SpdyConnectTransaction::WriteSegments %p max=%d", this, count));
1411 
1412   // For websockets, we need to forward the initial response through to the base
1413   // transaction so the normal websocket plumbing can do all the things it needs
1414   // to do.
1415   if (mIsWebsocket) {
1416     return WebsocketWriteSegments(writer, count, countWritten);
1417   }
1418 
1419   // first call into the tunnel stream to get the demux'd data out of the
1420   // spdy session.
1421   nsresult rv = WriteDataToBuffer(writer, count, countWritten);
1422   if (NS_FAILED(rv)) {
1423     return rv;
1424   }
1425 
1426   nsCOMPtr<nsIInputStreamCallback> cb =
1427       mTunneledConn ? mTunnelStreamIn->TakeCallback() : nullptr;
1428   LOG(("SpdyConnectTransaction::WriteSegments %p cb=%p", this, cb.get()));
1429 
1430   if (!cb) {
1431     return NS_BASE_STREAM_WOULD_BLOCK;
1432   }
1433 
1434   rv = cb->OnInputStreamReady(mTunnelStreamIn);
1435   LOG(
1436       ("SpdyConnectTransaction::WriteSegments %p "
1437        "after InputStreamReady callback %d total of ciphered data buffered "
1438        "rv=%" PRIx32 "\n",
1439        this, mInputDataUsed - mInputDataOffset, static_cast<uint32_t>(rv)));
1440   LOG(
1441       ("SpdyConnectTransaction::WriteSegments %p "
1442        "goodput %p out %" PRId64 "\n",
1443        this, mTunneledConn.get(), mTunneledConn->ContentBytesWritten()));
1444   if (NS_SUCCEEDED(rv) && !mTunneledConn->ContentBytesWritten()) {
1445     nsCOMPtr<nsIOutputStreamCallback> ocb = mTunnelStreamOut->TakeCallback();
1446     mTunnelStreamOut->AsyncWait(ocb, 0, 0, nullptr);
1447   }
1448   return rv;
1449 }
1450 
WebsocketWriteSegments(nsAHttpSegmentWriter * writer,uint32_t count,uint32_t * countWritten)1451 nsresult SpdyConnectTransaction::WebsocketWriteSegments(
1452     nsAHttpSegmentWriter* writer, uint32_t count, uint32_t* countWritten) {
1453   MOZ_ASSERT(OnSocketThread());
1454   MOZ_ASSERT(mIsWebsocket);
1455   LOG(("SpdyConnectTransaction::WebsocketWriteSegments %p max=%d", this,
1456        count));
1457 
1458   if (mDrivingTransaction && !mDrivingTransaction->IsDone()) {
1459     // Transaction hasn't received end of headers yet, so keep passing data to
1460     // it until it has. Then we can take over.
1461     nsresult rv =
1462         mDrivingTransaction->WriteSegments(writer, count, countWritten);
1463     if (NS_SUCCEEDED(rv) && mDrivingTransaction->IsDone() && !mConnRefTaken) {
1464       mDrivingTransaction->Close(NS_OK);
1465     }
1466   }
1467 
1468   if (!mConnRefTaken) {
1469     // Force driving transaction to finish so the websocket channel can get its
1470     // notifications correctly and start driving.
1471     MOZ_ASSERT(mDrivingTransaction);
1472     mDrivingTransaction->Close(NS_OK);
1473   }
1474 
1475   nsresult rv = WriteDataToBuffer(writer, count, countWritten);
1476   if (NS_SUCCEEDED(rv)) {
1477     if (!mTunneledConn) {
1478       return NS_BASE_STREAM_WOULD_BLOCK;
1479     }
1480     nsCOMPtr<nsIInputStreamCallback> cb = mTunnelStreamIn->TakeCallback();
1481     if (!cb) {
1482       return NS_BASE_STREAM_WOULD_BLOCK;
1483     }
1484     rv = cb->OnInputStreamReady(mTunnelStreamIn);
1485   }
1486 
1487   return rv;
1488 }
1489 
ConnectedReadyForInput()1490 bool SpdyConnectTransaction::ConnectedReadyForInput() {
1491   return mTunneledConn && mTunnelStreamIn->HasCallback();
1492 }
1493 
RequestHead()1494 nsHttpRequestHead* SpdyConnectTransaction::RequestHead() {
1495   return mRequestHead;
1496 }
1497 
Close(nsresult code)1498 void SpdyConnectTransaction::Close(nsresult code) {
1499   LOG(("SpdyConnectTransaction close %p %" PRIx32 "\n", this,
1500        static_cast<uint32_t>(code)));
1501 
1502   MOZ_ASSERT(OnSocketThread());
1503 
1504   if (mIsWebsocket && mDrivingTransaction) {
1505     mDrivingTransaction->SetH2WSTransaction(nullptr);
1506     if (!mConnRefTaken) {
1507       // This indicates that the websocket failed to set up, so just close down
1508       // the transaction as usual.
1509       mDrivingTransaction->Close(code);
1510       mDrivingTransaction = nullptr;
1511     }
1512   }
1513   NullHttpTransaction::Close(code);
1514   if (NS_FAILED(code) && (code != NS_BASE_STREAM_WOULD_BLOCK)) {
1515     CreateShimError(code);
1516   } else {
1517     CreateShimError(NS_BASE_STREAM_CLOSED);
1518   }
1519 }
1520 
SetConnRefTaken()1521 void SpdyConnectTransaction::SetConnRefTaken() {
1522   MOZ_ASSERT(OnSocketThread());
1523 
1524   mConnRefTaken = true;
1525   mDrivingTransaction = nullptr;  // Just in case
1526 }
1527 
TakeCallback()1528 already_AddRefed<nsIOutputStreamCallback> OutputStreamShim::TakeCallback() {
1529   mozilla::MutexAutoLock lock(mMutex);
1530   return mCallback.forget();
1531 }
1532 
1533 class WebsocketHasDataToWrite final : public Runnable {
1534  public:
WebsocketHasDataToWrite(OutputStreamShim * shim)1535   explicit WebsocketHasDataToWrite(OutputStreamShim* shim)
1536       : Runnable("WebsocketHasDataToWrite"), mShim(shim) {}
1537 
1538   ~WebsocketHasDataToWrite() = default;
1539 
Run()1540   NS_IMETHOD Run() override { return mShim->CallTransactionHasDataToWrite(); }
1541 
Dispatch()1542   [[nodiscard]] nsresult Dispatch() {
1543     if (OnSocketThread()) {
1544       return Run();
1545     }
1546 
1547     nsCOMPtr<nsIEventTarget> sts =
1548         do_GetService("@mozilla.org/network/socket-transport-service;1");
1549     return sts->Dispatch(this, nsIEventTarget::DISPATCH_NORMAL);
1550   }
1551 
1552  private:
1553   RefPtr<OutputStreamShim> mShim;
1554 };
1555 
1556 NS_IMETHODIMP
AsyncWait(nsIOutputStreamCallback * callback,unsigned int flags,unsigned int requestedCount,nsIEventTarget * target)1557 OutputStreamShim::AsyncWait(nsIOutputStreamCallback* callback,
1558                             unsigned int flags, unsigned int requestedCount,
1559                             nsIEventTarget* target) {
1560   if (mIsWebsocket) {
1561     // With websockets, AsyncWait may be called from the main thread, but the
1562     // target is on the socket thread. That's all we really care about.
1563     nsCOMPtr<nsIEventTarget> sts =
1564         do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID);
1565     MOZ_ASSERT((!target && !callback) || (target == sts));
1566     if (target && (target != sts)) {
1567       return NS_ERROR_FAILURE;
1568     }
1569   } else {
1570     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
1571     bool currentThread;
1572 
1573     if (target && (NS_FAILED(target->IsOnCurrentThread(&currentThread)) ||
1574                    !currentThread)) {
1575       return NS_ERROR_FAILURE;
1576     }
1577   }
1578 
1579   LOG(("OutputStreamShim::AsyncWait %p callback %p\n", this, callback));
1580 
1581   {
1582     mozilla::MutexAutoLock lock(mMutex);
1583     mCallback = callback;
1584   }
1585 
1586   RefPtr<WebsocketHasDataToWrite> wsdw = new WebsocketHasDataToWrite(this);
1587   Unused << wsdw->Dispatch();
1588 
1589   return NS_OK;
1590 }
1591 
1592 class OutputCloseTransaction final : public Runnable {
1593  public:
OutputCloseTransaction(OutputStreamShim * shim,nsresult reason)1594   OutputCloseTransaction(OutputStreamShim* shim, nsresult reason)
1595       : Runnable("OutputCloseTransaction"), mShim(shim), mReason(reason) {}
1596 
1597   ~OutputCloseTransaction() = default;
1598 
Run()1599   NS_IMETHOD Run() override { return mShim->CloseTransaction(mReason); }
1600 
1601  private:
1602   RefPtr<OutputStreamShim> mShim;
1603   nsresult mReason;
1604 };
1605 
1606 NS_IMETHODIMP
CloseWithStatus(nsresult reason)1607 OutputStreamShim::CloseWithStatus(nsresult reason) {
1608   if (!OnSocketThread()) {
1609     RefPtr<OutputCloseTransaction> oct =
1610         new OutputCloseTransaction(this, reason);
1611     nsCOMPtr<nsIEventTarget> sts =
1612         do_GetService("@mozilla.org/network/socket-transport-service;1");
1613     return sts->Dispatch(oct, nsIEventTarget::DISPATCH_NORMAL);
1614   }
1615 
1616   return CloseTransaction(reason);
1617 }
1618 
CloseTransaction(nsresult reason)1619 nsresult OutputStreamShim::CloseTransaction(nsresult reason) {
1620   MOZ_ASSERT(OnSocketThread());
1621   RefPtr<NullHttpTransaction> baseTrans = mWeakTrans->QueryTransaction();
1622   if (!baseTrans) {
1623     return NS_ERROR_FAILURE;
1624   }
1625   SpdyConnectTransaction* trans = baseTrans->QuerySpdyConnectTransaction();
1626   MOZ_ASSERT(trans);
1627   if (!trans) {
1628     return NS_ERROR_UNEXPECTED;
1629   }
1630 
1631   trans->mSession->CloseTransaction(trans, reason);
1632   return NS_OK;
1633 }
1634 
1635 NS_IMETHODIMP
Close()1636 OutputStreamShim::Close() { return CloseWithStatus(NS_OK); }
1637 
1638 NS_IMETHODIMP
Flush()1639 OutputStreamShim::Flush() {
1640   MOZ_ASSERT(OnSocketThread());
1641   RefPtr<NullHttpTransaction> baseTrans = mWeakTrans->QueryTransaction();
1642   if (!baseTrans) {
1643     return NS_ERROR_FAILURE;
1644   }
1645   SpdyConnectTransaction* trans = baseTrans->QuerySpdyConnectTransaction();
1646   MOZ_ASSERT(trans);
1647   if (!trans) {
1648     return NS_ERROR_UNEXPECTED;
1649   }
1650 
1651   uint32_t count = trans->mOutputDataUsed - trans->mOutputDataOffset;
1652   if (!count) {
1653     return NS_OK;
1654   }
1655 
1656   uint32_t countRead;
1657   nsresult rv = trans->Flush(count, &countRead);
1658   LOG(("OutputStreamShim::Flush %p before %d after %d\n", this, count,
1659        trans->mOutputDataUsed - trans->mOutputDataOffset));
1660   return rv;
1661 }
1662 
CallTransactionHasDataToWrite()1663 nsresult OutputStreamShim::CallTransactionHasDataToWrite() {
1664   MOZ_ASSERT(OnSocketThread());
1665   RefPtr<NullHttpTransaction> baseTrans = mWeakTrans->QueryTransaction();
1666   if (!baseTrans) {
1667     return NS_ERROR_FAILURE;
1668   }
1669   SpdyConnectTransaction* trans = baseTrans->QuerySpdyConnectTransaction();
1670   MOZ_ASSERT(trans);
1671   if (!trans) {
1672     return NS_ERROR_UNEXPECTED;
1673   }
1674   trans->mSession->TransactionHasDataToWrite(trans);
1675   return NS_OK;
1676 }
1677 
1678 NS_IMETHODIMP
Write(const char * aBuf,uint32_t aCount,uint32_t * _retval)1679 OutputStreamShim::Write(const char* aBuf, uint32_t aCount, uint32_t* _retval) {
1680   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
1681 
1682   if (NS_FAILED(mStatus)) {
1683     return mStatus;
1684   }
1685 
1686   RefPtr<NullHttpTransaction> baseTrans = mWeakTrans->QueryTransaction();
1687   if (!baseTrans) {
1688     return NS_ERROR_FAILURE;
1689   }
1690   SpdyConnectTransaction* trans = baseTrans->QuerySpdyConnectTransaction();
1691   MOZ_ASSERT(trans);
1692   if (!trans) {
1693     return NS_ERROR_UNEXPECTED;
1694   }
1695 
1696   if ((trans->mOutputDataUsed + aCount) >= 512000) {
1697     *_retval = 0;
1698     // time for some flow control;
1699     return NS_BASE_STREAM_WOULD_BLOCK;
1700   }
1701 
1702   EnsureBuffer(trans->mOutputData, trans->mOutputDataUsed + aCount,
1703                trans->mOutputDataUsed, trans->mOutputDataSize);
1704   memcpy(&trans->mOutputData[trans->mOutputDataUsed], aBuf, aCount);
1705   trans->mOutputDataUsed += aCount;
1706   *_retval = aCount;
1707   LOG(("OutputStreamShim::Write %p new %d total %d\n", this, aCount,
1708        trans->mOutputDataUsed));
1709 
1710   trans->mSession->TransactionHasDataToWrite(trans);
1711 
1712   return NS_OK;
1713 }
1714 
1715 NS_IMETHODIMP
WriteFrom(nsIInputStream * aFromStream,uint32_t aCount,uint32_t * _retval)1716 OutputStreamShim::WriteFrom(nsIInputStream* aFromStream, uint32_t aCount,
1717                             uint32_t* _retval) {
1718   if (mIsWebsocket) {
1719     LOG3(("WARNING: OutputStreamShim::WriteFrom %p", this));
1720   }
1721   return NS_ERROR_NOT_IMPLEMENTED;
1722 }
1723 
1724 NS_IMETHODIMP
WriteSegments(nsReadSegmentFun aReader,void * aClosure,uint32_t aCount,uint32_t * _retval)1725 OutputStreamShim::WriteSegments(nsReadSegmentFun aReader, void* aClosure,
1726                                 uint32_t aCount, uint32_t* _retval) {
1727   if (mIsWebsocket) {
1728     LOG3(("WARNING: OutputStreamShim::WriteSegments %p", this));
1729   }
1730   return NS_ERROR_NOT_IMPLEMENTED;
1731 }
1732 
1733 NS_IMETHODIMP
IsNonBlocking(bool * _retval)1734 OutputStreamShim::IsNonBlocking(bool* _retval) {
1735   *_retval = true;
1736   return NS_OK;
1737 }
1738 
TakeCallback()1739 already_AddRefed<nsIInputStreamCallback> InputStreamShim::TakeCallback() {
1740   mozilla::MutexAutoLock lock(mMutex);
1741   return mCallback.forget();
1742 }
1743 
HasCallback()1744 bool InputStreamShim::HasCallback() {
1745   mozilla::MutexAutoLock lock(mMutex);
1746   return mCallback != nullptr;
1747 }
1748 
1749 class CheckAvailData final : public Runnable {
1750  public:
CheckAvailData(InputStreamShim * shim)1751   explicit CheckAvailData(InputStreamShim* shim)
1752       : Runnable("CheckAvailData"), mShim(shim) {}
1753 
1754   ~CheckAvailData() = default;
1755 
Run()1756   NS_IMETHOD Run() override {
1757     uint64_t avail = 0;
1758     if (NS_SUCCEEDED(mShim->Available(&avail)) && avail) {
1759       nsCOMPtr<nsIInputStreamCallback> cb = mShim->TakeCallback();
1760       if (cb) {
1761         cb->OnInputStreamReady(mShim);
1762       }
1763     }
1764     return NS_OK;
1765   }
1766 
Dispatch()1767   [[nodiscard]] nsresult Dispatch() {
1768     // Dispatch the event even if we're on socket thread to avoid closing and
1769     // destructing Http2Session in case this call is comming from
1770     // Http2Session::ReadSegments() and the callback closes the transaction in
1771     // OnInputStreamRead().
1772     nsCOMPtr<nsIEventTarget> sts =
1773         do_GetService("@mozilla.org/network/socket-transport-service;1");
1774     return sts->Dispatch(this, nsIEventTarget::DISPATCH_NORMAL);
1775   }
1776 
1777  private:
1778   RefPtr<InputStreamShim> mShim;
1779 };
1780 
1781 NS_IMETHODIMP
AsyncWait(nsIInputStreamCallback * callback,unsigned int flags,unsigned int requestedCount,nsIEventTarget * target)1782 InputStreamShim::AsyncWait(nsIInputStreamCallback* callback, unsigned int flags,
1783                            unsigned int requestedCount,
1784                            nsIEventTarget* target) {
1785   if (mIsWebsocket) {
1786     // With websockets, AsyncWait may be called from the main thread, but the
1787     // target is on the socket thread. That's all we really care about.
1788     nsCOMPtr<nsIEventTarget> sts =
1789         do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID);
1790     MOZ_ASSERT((!target && !callback) || (target == sts));
1791     if (target && (target != sts)) {
1792       return NS_ERROR_FAILURE;
1793     }
1794   } else {
1795     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
1796     bool currentThread;
1797 
1798     if (target && (NS_FAILED(target->IsOnCurrentThread(&currentThread)) ||
1799                    !currentThread)) {
1800       return NS_ERROR_FAILURE;
1801     }
1802   }
1803 
1804   LOG(("InputStreamShim::AsyncWait %p callback %p\n", this, callback));
1805 
1806   {
1807     mozilla::MutexAutoLock lock(mMutex);
1808     mCallback = callback;
1809   }
1810 
1811   if (callback) {
1812     RefPtr<CheckAvailData> cad = new CheckAvailData(this);
1813     Unused << cad->Dispatch();
1814   }
1815 
1816   return NS_OK;
1817 }
1818 
1819 class InputCloseTransaction final : public Runnable {
1820  public:
InputCloseTransaction(InputStreamShim * shim,nsresult reason)1821   InputCloseTransaction(InputStreamShim* shim, nsresult reason)
1822       : Runnable("InputCloseTransaction"), mShim(shim), mReason(reason) {}
1823 
1824   ~InputCloseTransaction() = default;
1825 
Run()1826   NS_IMETHOD Run() override { return mShim->CloseTransaction(mReason); }
1827 
1828  private:
1829   RefPtr<InputStreamShim> mShim;
1830   nsresult mReason;
1831 };
1832 
1833 NS_IMETHODIMP
CloseWithStatus(nsresult reason)1834 InputStreamShim::CloseWithStatus(nsresult reason) {
1835   if (!OnSocketThread()) {
1836     RefPtr<InputCloseTransaction> ict = new InputCloseTransaction(this, reason);
1837     nsCOMPtr<nsIEventTarget> sts =
1838         do_GetService("@mozilla.org/network/socket-transport-service;1");
1839     return sts->Dispatch(ict, nsIEventTarget::DISPATCH_NORMAL);
1840   }
1841 
1842   return CloseTransaction(reason);
1843 }
1844 
CloseTransaction(nsresult reason)1845 nsresult InputStreamShim::CloseTransaction(nsresult reason) {
1846   MOZ_ASSERT(OnSocketThread());
1847   RefPtr<NullHttpTransaction> baseTrans = mWeakTrans->QueryTransaction();
1848   if (!baseTrans) {
1849     return NS_ERROR_FAILURE;
1850   }
1851   SpdyConnectTransaction* trans = baseTrans->QuerySpdyConnectTransaction();
1852   MOZ_ASSERT(trans);
1853   if (!trans) {
1854     return NS_ERROR_UNEXPECTED;
1855   }
1856 
1857   trans->mSession->CloseTransaction(trans, reason);
1858   return NS_OK;
1859 }
1860 
1861 NS_IMETHODIMP
Close()1862 InputStreamShim::Close() { return CloseWithStatus(NS_OK); }
1863 
1864 NS_IMETHODIMP
Available(uint64_t * _retval)1865 InputStreamShim::Available(uint64_t* _retval) {
1866   RefPtr<NullHttpTransaction> baseTrans = mWeakTrans->QueryTransaction();
1867   if (!baseTrans) {
1868     return NS_ERROR_FAILURE;
1869   }
1870   SpdyConnectTransaction* trans = baseTrans->QuerySpdyConnectTransaction();
1871   MOZ_ASSERT(trans);
1872   if (!trans) {
1873     return NS_ERROR_UNEXPECTED;
1874   }
1875 
1876   *_retval = trans->mInputDataUsed - trans->mInputDataOffset;
1877   return NS_OK;
1878 }
1879 
1880 NS_IMETHODIMP
Read(char * aBuf,uint32_t aCount,uint32_t * _retval)1881 InputStreamShim::Read(char* aBuf, uint32_t aCount, uint32_t* _retval) {
1882   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
1883 
1884   if (NS_FAILED(mStatus)) {
1885     return mStatus;
1886   }
1887 
1888   RefPtr<NullHttpTransaction> baseTrans = mWeakTrans->QueryTransaction();
1889   if (!baseTrans) {
1890     return NS_ERROR_FAILURE;
1891   }
1892   SpdyConnectTransaction* trans = baseTrans->QuerySpdyConnectTransaction();
1893   MOZ_ASSERT(trans);
1894   if (!trans) {
1895     return NS_ERROR_UNEXPECTED;
1896   }
1897 
1898   uint32_t avail = trans->mInputDataUsed - trans->mInputDataOffset;
1899   uint32_t tocopy = std::min(aCount, avail);
1900   *_retval = tocopy;
1901   memcpy(aBuf, &trans->mInputData[trans->mInputDataOffset], tocopy);
1902   trans->mInputDataOffset += tocopy;
1903   if (trans->mInputDataOffset == trans->mInputDataUsed) {
1904     trans->mInputDataOffset = trans->mInputDataUsed = 0;
1905   }
1906 
1907   return tocopy ? NS_OK : NS_BASE_STREAM_WOULD_BLOCK;
1908 }
1909 
1910 NS_IMETHODIMP
ReadSegments(nsWriteSegmentFun aWriter,void * aClosure,uint32_t aCount,uint32_t * _retval)1911 InputStreamShim::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
1912                               uint32_t aCount, uint32_t* _retval) {
1913   if (mIsWebsocket) {
1914     LOG3(("WARNING: InputStreamShim::ReadSegments %p", this));
1915   }
1916   return NS_ERROR_NOT_IMPLEMENTED;
1917 }
1918 
1919 NS_IMETHODIMP
IsNonBlocking(bool * _retval)1920 InputStreamShim::IsNonBlocking(bool* _retval) {
1921   *_retval = true;
1922   return NS_OK;
1923 }
1924 
1925 NS_IMETHODIMP
SetKeepaliveEnabled(bool aKeepaliveEnabled)1926 SocketTransportShim::SetKeepaliveEnabled(bool aKeepaliveEnabled) {
1927   if (mIsWebsocket) {
1928     LOG3(("WARNING: SocketTransportShim::SetKeepaliveEnabled %p called", this));
1929   }
1930   return NS_ERROR_NOT_IMPLEMENTED;
1931 }
1932 
1933 NS_IMETHODIMP
SetKeepaliveVals(int32_t keepaliveIdleTime,int32_t keepaliveRetryInterval)1934 SocketTransportShim::SetKeepaliveVals(int32_t keepaliveIdleTime,
1935                                       int32_t keepaliveRetryInterval) {
1936   if (mIsWebsocket) {
1937     LOG3(("WARNING: SocketTransportShim::SetKeepaliveVals %p called", this));
1938   }
1939   return NS_ERROR_NOT_IMPLEMENTED;
1940 }
1941 
1942 NS_IMETHODIMP
GetSecurityCallbacks(nsIInterfaceRequestor ** aSecurityCallbacks)1943 SocketTransportShim::GetSecurityCallbacks(
1944     nsIInterfaceRequestor** aSecurityCallbacks) {
1945   if (mIsWebsocket) {
1946     nsCOMPtr<nsIInterfaceRequestor> out(mSecurityCallbacks);
1947     *aSecurityCallbacks = out.forget().take();
1948     return NS_OK;
1949   }
1950 
1951   return mWrapped->GetSecurityCallbacks(aSecurityCallbacks);
1952 }
1953 
1954 NS_IMETHODIMP
SetSecurityCallbacks(nsIInterfaceRequestor * aSecurityCallbacks)1955 SocketTransportShim::SetSecurityCallbacks(
1956     nsIInterfaceRequestor* aSecurityCallbacks) {
1957   if (mIsWebsocket) {
1958     mSecurityCallbacks = aSecurityCallbacks;
1959     return NS_OK;
1960   }
1961   return NS_ERROR_NOT_IMPLEMENTED;
1962 }
1963 
1964 NS_IMETHODIMP
OpenInputStream(uint32_t aFlags,uint32_t aSegmentSize,uint32_t aSegmentCount,nsIInputStream ** _retval)1965 SocketTransportShim::OpenInputStream(uint32_t aFlags, uint32_t aSegmentSize,
1966                                      uint32_t aSegmentCount,
1967                                      nsIInputStream** _retval) {
1968   if (mIsWebsocket) {
1969     LOG3(("WARNING: SocketTransportShim::OpenInputStream %p", this));
1970   }
1971   return NS_ERROR_NOT_IMPLEMENTED;
1972 }
1973 
1974 NS_IMETHODIMP
OpenOutputStream(uint32_t aFlags,uint32_t aSegmentSize,uint32_t aSegmentCount,nsIOutputStream ** _retval)1975 SocketTransportShim::OpenOutputStream(uint32_t aFlags, uint32_t aSegmentSize,
1976                                       uint32_t aSegmentCount,
1977                                       nsIOutputStream** _retval) {
1978   if (mIsWebsocket) {
1979     LOG3(("WARNING: SocketTransportShim::OpenOutputStream %p", this));
1980   }
1981   return NS_ERROR_NOT_IMPLEMENTED;
1982 }
1983 
1984 NS_IMETHODIMP
Close(nsresult aReason)1985 SocketTransportShim::Close(nsresult aReason) {
1986   if (mIsWebsocket) {
1987     LOG3(("WARNING: SocketTransportShim::Close %p", this));
1988   } else {
1989     LOG(("SocketTransportShim::Close %p", this));
1990   }
1991 
1992   if (gHttpHandler->Bug1563538()) {
1993     // Must always post, because mSession->CloseTransaction releases the
1994     // Http2Stream which is still on stack.
1995     RefPtr<SocketTransportShim> self(this);
1996 
1997     nsCOMPtr<nsIEventTarget> sts =
1998         do_GetService("@mozilla.org/network/socket-transport-service;1");
1999     Unused << sts->Dispatch(NS_NewRunnableFunction(
2000         "SocketTransportShim::Close", [self = std::move(self), aReason]() {
2001           RefPtr<NullHttpTransaction> baseTrans =
2002               self->mWeakTrans->QueryTransaction();
2003           if (!baseTrans) {
2004             return;
2005           }
2006           SpdyConnectTransaction* trans =
2007               baseTrans->QuerySpdyConnectTransaction();
2008           MOZ_ASSERT(trans);
2009           if (!trans) {
2010             return;
2011           }
2012 
2013           trans->mSession->CloseTransaction(trans, aReason);
2014         }));
2015     return NS_OK;
2016   }
2017 
2018   return NS_ERROR_NOT_IMPLEMENTED;
2019 }
2020 
2021 NS_IMETHODIMP
SetEventSink(nsITransportEventSink * aSink,nsIEventTarget * aEventTarget)2022 SocketTransportShim::SetEventSink(nsITransportEventSink* aSink,
2023                                   nsIEventTarget* aEventTarget) {
2024   if (mIsWebsocket) {
2025     // Need to pretend, since websockets expect this to work
2026     return NS_OK;
2027   }
2028   return NS_ERROR_NOT_IMPLEMENTED;
2029 }
2030 
2031 NS_IMETHODIMP
Bind(NetAddr * aLocalAddr)2032 SocketTransportShim::Bind(NetAddr* aLocalAddr) {
2033   if (mIsWebsocket) {
2034     LOG3(("WARNING: SocketTransportShim::Bind %p", this));
2035   }
2036   return NS_ERROR_NOT_IMPLEMENTED;
2037 }
2038 
2039 NS_IMETHODIMP
GetEchConfigUsed(bool * aEchConfigUsed)2040 SocketTransportShim::GetEchConfigUsed(bool* aEchConfigUsed) {
2041   if (mIsWebsocket) {
2042     LOG3(("WARNING: SocketTransportShim::GetEchConfigUsed %p", this));
2043   }
2044   return NS_ERROR_NOT_IMPLEMENTED;
2045 }
2046 
2047 NS_IMETHODIMP
SetEchConfig(const nsACString & aEchConfig)2048 SocketTransportShim::SetEchConfig(const nsACString& aEchConfig) {
2049   if (mIsWebsocket) {
2050     LOG3(("WARNING: SocketTransportShim::SetEchConfig %p", this));
2051   }
2052   return NS_ERROR_NOT_IMPLEMENTED;
2053 }
2054 
2055 NS_IMETHODIMP
ResolvedByTRR(bool * aResolvedByTRR)2056 SocketTransportShim::ResolvedByTRR(bool* aResolvedByTRR) {
2057   if (mIsWebsocket) {
2058     LOG3(("WARNING: SocketTransportShim::IsTRR %p", this));
2059   }
2060   return NS_ERROR_NOT_IMPLEMENTED;
2061 }
2062 
2063 #define FWD_TS_PTR(fx, ts) \
2064   NS_IMETHODIMP            \
2065   SocketTransportShim::fx(ts* arg) { return mWrapped->fx(arg); }
2066 
2067 #define FWD_TS_ADDREF(fx, ts) \
2068   NS_IMETHODIMP               \
2069   SocketTransportShim::fx(ts** arg) { return mWrapped->fx(arg); }
2070 
2071 #define FWD_TS(fx, ts) \
2072   NS_IMETHODIMP        \
2073   SocketTransportShim::fx(ts arg) { return mWrapped->fx(arg); }
2074 
2075 FWD_TS_PTR(GetKeepaliveEnabled, bool);
2076 FWD_TS_PTR(GetSendBufferSize, uint32_t);
2077 FWD_TS(SetSendBufferSize, uint32_t);
2078 FWD_TS_PTR(GetPort, int32_t);
2079 FWD_TS_PTR(GetPeerAddr, mozilla::net::NetAddr);
2080 FWD_TS_PTR(GetSelfAddr, mozilla::net::NetAddr);
2081 FWD_TS_ADDREF(GetScriptablePeerAddr, nsINetAddr);
2082 FWD_TS_ADDREF(GetScriptableSelfAddr, nsINetAddr);
2083 FWD_TS_ADDREF(GetSecurityInfo, nsISupports);
2084 FWD_TS_PTR(IsAlive, bool);
2085 FWD_TS_PTR(GetConnectionFlags, uint32_t);
2086 FWD_TS(SetConnectionFlags, uint32_t);
2087 FWD_TS(SetIsPrivate, bool);
2088 FWD_TS_PTR(GetTlsFlags, uint32_t);
2089 FWD_TS(SetTlsFlags, uint32_t);
2090 FWD_TS_PTR(GetRecvBufferSize, uint32_t);
2091 FWD_TS(SetRecvBufferSize, uint32_t);
2092 FWD_TS_PTR(GetResetIPFamilyPreference, bool);
2093 
GetOriginAttributes(mozilla::OriginAttributes * aOriginAttributes)2094 nsresult SocketTransportShim::GetOriginAttributes(
2095     mozilla::OriginAttributes* aOriginAttributes) {
2096   return mWrapped->GetOriginAttributes(aOriginAttributes);
2097 }
2098 
SetOriginAttributes(const mozilla::OriginAttributes & aOriginAttributes)2099 nsresult SocketTransportShim::SetOriginAttributes(
2100     const mozilla::OriginAttributes& aOriginAttributes) {
2101   return mWrapped->SetOriginAttributes(aOriginAttributes);
2102 }
2103 
2104 NS_IMETHODIMP
GetScriptableOriginAttributes(JSContext * aCx,JS::MutableHandle<JS::Value> aOriginAttributes)2105 SocketTransportShim::GetScriptableOriginAttributes(
2106     JSContext* aCx, JS::MutableHandle<JS::Value> aOriginAttributes) {
2107   return mWrapped->GetScriptableOriginAttributes(aCx, aOriginAttributes);
2108 }
2109 
2110 NS_IMETHODIMP
SetScriptableOriginAttributes(JSContext * aCx,JS::Handle<JS::Value> aOriginAttributes)2111 SocketTransportShim::SetScriptableOriginAttributes(
2112     JSContext* aCx, JS::Handle<JS::Value> aOriginAttributes) {
2113   return mWrapped->SetScriptableOriginAttributes(aCx, aOriginAttributes);
2114 }
2115 
2116 NS_IMETHODIMP
GetHost(nsACString & aHost)2117 SocketTransportShim::GetHost(nsACString& aHost) {
2118   return mWrapped->GetHost(aHost);
2119 }
2120 
2121 NS_IMETHODIMP
GetTimeout(uint32_t aType,uint32_t * _retval)2122 SocketTransportShim::GetTimeout(uint32_t aType, uint32_t* _retval) {
2123   return mWrapped->GetTimeout(aType, _retval);
2124 }
2125 
2126 NS_IMETHODIMP
SetTimeout(uint32_t aType,uint32_t aValue)2127 SocketTransportShim::SetTimeout(uint32_t aType, uint32_t aValue) {
2128   return mWrapped->SetTimeout(aType, aValue);
2129 }
2130 
2131 NS_IMETHODIMP
SetReuseAddrPort(bool aReuseAddrPort)2132 SocketTransportShim::SetReuseAddrPort(bool aReuseAddrPort) {
2133   return mWrapped->SetReuseAddrPort(aReuseAddrPort);
2134 }
2135 
2136 NS_IMETHODIMP
SetLinger(bool aPolarity,int16_t aTimeout)2137 SocketTransportShim::SetLinger(bool aPolarity, int16_t aTimeout) {
2138   return mWrapped->SetLinger(aPolarity, aTimeout);
2139 }
2140 
2141 NS_IMETHODIMP
GetQoSBits(uint8_t * aQoSBits)2142 SocketTransportShim::GetQoSBits(uint8_t* aQoSBits) {
2143   return mWrapped->GetQoSBits(aQoSBits);
2144 }
2145 
2146 NS_IMETHODIMP
SetQoSBits(uint8_t aQoSBits)2147 SocketTransportShim::SetQoSBits(uint8_t aQoSBits) {
2148   return mWrapped->SetQoSBits(aQoSBits);
2149 }
2150 
2151 NS_IMETHODIMP
GetRetryDnsIfPossible(bool * aRetry)2152 SocketTransportShim::GetRetryDnsIfPossible(bool* aRetry) {
2153   return mWrapped->GetRetryDnsIfPossible(aRetry);
2154 }
2155 
2156 NS_IMETHODIMP
GetStatus(nsresult * aStatus)2157 SocketTransportShim::GetStatus(nsresult* aStatus) {
2158   return mWrapped->GetStatus(aStatus);
2159 }
2160 
2161 NS_IMPL_ISUPPORTS(TLSFilterTransaction, nsITimerCallback, nsINamed)
2162 NS_IMPL_ISUPPORTS(SocketTransportShim, nsISocketTransport, nsITransport)
2163 NS_IMPL_ISUPPORTS(InputStreamShim, nsIInputStream, nsIAsyncInputStream)
2164 NS_IMPL_ISUPPORTS(OutputStreamShim, nsIOutputStream, nsIAsyncOutputStream)
2165 NS_IMPL_ISUPPORTS(SocketInWrapper, nsIAsyncInputStream)
2166 NS_IMPL_ISUPPORTS(SocketOutWrapper, nsIAsyncOutputStream)
2167 
2168 }  // namespace net
2169 }  // namespace mozilla
2170