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