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, ¬Used);
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(¤tThread)) ||
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(¤tThread)) ||
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