1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=4 sw=2 sts=2 et cin: */
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 // Log on level :5, instead of default :4.
11 #undef LOG
12 #define LOG(args) LOG5(args)
13 #undef LOG_ENABLED
14 #define LOG_ENABLED() LOG5_ENABLED()
15
16 #define TLS_EARLY_DATA_NOT_AVAILABLE 0
17 #define TLS_EARLY_DATA_AVAILABLE_BUT_NOT_USED 1
18 #define TLS_EARLY_DATA_AVAILABLE_AND_USED 2
19
20 #include "ASpdySession.h"
21 #include "mozilla/Telemetry.h"
22 #include "HttpConnectionUDP.h"
23 #include "nsHttpHandler.h"
24 #include "Http3Session.h"
25 #include "nsISocketProvider.h"
26 #include "nsNetAddr.h"
27 #include "nsINetAddr.h"
28
29 namespace mozilla {
30 namespace net {
31
32 //-----------------------------------------------------------------------------
33 // HttpConnectionUDP <public>
34 //-----------------------------------------------------------------------------
35
HttpConnectionUDP()36 HttpConnectionUDP::HttpConnectionUDP() : mHttpHandler(gHttpHandler) {
37 LOG(("Creating HttpConnectionUDP @%p\n", this));
38 }
39
~HttpConnectionUDP()40 HttpConnectionUDP::~HttpConnectionUDP() {
41 LOG(("Destroying HttpConnectionUDP @%p\n", this));
42
43 if (mForceSendTimer) {
44 mForceSendTimer->Cancel();
45 mForceSendTimer = nullptr;
46 }
47 }
48
Init(nsHttpConnectionInfo * info,nsIDNSRecord * dnsRecord,nsresult status,nsIInterfaceRequestor * callbacks,uint32_t caps)49 nsresult HttpConnectionUDP::Init(nsHttpConnectionInfo* info,
50 nsIDNSRecord* dnsRecord, nsresult status,
51 nsIInterfaceRequestor* callbacks,
52 uint32_t caps) {
53 LOG1(("HttpConnectionUDP::Init this=%p", this));
54 NS_ENSURE_ARG_POINTER(info);
55 NS_ENSURE_TRUE(!mConnInfo, NS_ERROR_ALREADY_INITIALIZED);
56 MOZ_ASSERT(dnsRecord || NS_FAILED(status));
57
58 mConnInfo = info;
59 MOZ_ASSERT(mConnInfo);
60 MOZ_ASSERT(mConnInfo->IsHttp3());
61
62 mErrorBeforeConnect = status;
63 mAlpnToken = mConnInfo->GetNPNToken();
64 if (NS_FAILED(mErrorBeforeConnect)) {
65 // See explanation for non-strictness of this operation in
66 // SetSecurityCallbacks.
67 mCallbacks = new nsMainThreadPtrHolder<nsIInterfaceRequestor>(
68 "HttpConnectionUDP::mCallbacks", callbacks, false);
69 return mErrorBeforeConnect;
70 }
71
72 nsCOMPtr<nsIDNSAddrRecord> dnsAddrRecord = do_QueryInterface(dnsRecord);
73 MOZ_ASSERT(dnsAddrRecord);
74 if (!dnsAddrRecord) {
75 return NS_ERROR_FAILURE;
76 }
77 dnsAddrRecord->IsTRR(&mResolvedByTRR);
78 NetAddr peerAddr;
79 nsresult rv = dnsAddrRecord->GetNextAddr(mConnInfo->GetRoutedHost().IsEmpty()
80 ? mConnInfo->OriginPort()
81 : mConnInfo->RoutedPort(),
82 &peerAddr);
83 if (NS_FAILED(rv)) {
84 return rv;
85 }
86
87 mSocket = do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv);
88 if (NS_FAILED(rv)) {
89 return rv;
90 }
91
92 // We need an address here so that we can convey the IP version of the
93 // socket.
94 NetAddr local;
95 memset(&local, 0, sizeof(local));
96 local.raw.family = peerAddr.raw.family;
97 rv = mSocket->InitWithAddress(&local, nullptr, false, 1);
98 if (NS_FAILED(rv)) {
99 mSocket = nullptr;
100 return rv;
101 }
102
103 rv = mSocket->SetRecvBufferSize(
104 StaticPrefs::network_http_http3_recvBufferSize());
105 if (NS_FAILED(rv)) {
106 LOG(("HttpConnectionUDP::Init SetRecvBufferSize failed %d [this=%p]",
107 static_cast<uint32_t>(rv), this));
108 mSocket->Close();
109 mSocket = nullptr;
110 return rv;
111 }
112
113 if (peerAddr.raw.family == AF_INET) {
114 rv = mSocket->SetDontFragment(true);
115 if (NS_FAILED(rv)) {
116 LOG(("HttpConnectionUDP::Init SetDontFragment failed %d [this=%p]",
117 static_cast<uint32_t>(rv), this));
118 }
119 }
120
121 // get the resulting socket address.
122 rv = mSocket->GetLocalAddr(getter_AddRefs(mSelfAddr));
123 if (NS_FAILED(rv)) {
124 mSocket->Close();
125 mSocket = nullptr;
126 return rv;
127 }
128
129 uint32_t controlFlags = 0;
130 if (caps & NS_HTTP_LOAD_ANONYMOUS) {
131 controlFlags |= nsISocketProvider::ANONYMOUS_CONNECT;
132 }
133 if (mConnInfo->GetPrivate()) {
134 controlFlags |= nsISocketProvider::NO_PERMANENT_STORAGE;
135 }
136 if (((caps & NS_HTTP_BE_CONSERVATIVE) || mConnInfo->GetBeConservative()) &&
137 gHttpHandler->ConnMgr()->BeConservativeIfProxied(
138 mConnInfo->ProxyInfo())) {
139 controlFlags |= nsISocketProvider::BE_CONSERVATIVE;
140 }
141
142 mPeerAddr = new nsNetAddr(&peerAddr);
143 mHttp3Session = new Http3Session();
144 rv = mHttp3Session->Init(mConnInfo, mSelfAddr, mPeerAddr, this, controlFlags,
145 callbacks);
146 if (NS_FAILED(rv)) {
147 LOG(
148 ("HttpConnectionUDP::Init mHttp3Session->Init failed "
149 "[this=%p rv=%x]\n",
150 this, static_cast<uint32_t>(rv)));
151 mSocket->Close();
152 mSocket = nullptr;
153 mHttp3Session = nullptr;
154 return rv;
155 }
156
157 // See explanation for non-strictness of this operation in
158 // SetSecurityCallbacks.
159 mCallbacks = new nsMainThreadPtrHolder<nsIInterfaceRequestor>(
160 "HttpConnectionUDP::mCallbacks", callbacks, false);
161
162 // Call SyncListen at the end of this function. This call will actually
163 // attach the sockte to SocketTransportService.
164 rv = mSocket->SyncListen(this);
165 if (NS_FAILED(rv)) {
166 mSocket->Close();
167 mSocket = nullptr;
168 return rv;
169 }
170
171 return NS_OK;
172 }
173
174 // called on the socket thread
Activate(nsAHttpTransaction * trans,uint32_t caps,int32_t pri)175 nsresult HttpConnectionUDP::Activate(nsAHttpTransaction* trans, uint32_t caps,
176 int32_t pri) {
177 MOZ_ASSERT(OnSocketThread(), "not on socket thread");
178 LOG1(("HttpConnectionUDP::Activate [this=%p trans=%p caps=%x]\n", this, trans,
179 caps));
180
181 if (!mExperienced && !trans->IsNullTransaction()) {
182 // For QUIC we have HttpConnecitonUDP before the actual connection
183 // has been establish so wait for TLS handshake to be finished before
184 // we mark the connection 'experienced'.
185 if (!mExperienced && mHttp3Session && mHttp3Session->IsConnected()) {
186 mExperienced = true;
187 }
188 if (mBootstrappedTimingsSet) {
189 mBootstrappedTimingsSet = false;
190 nsHttpTransaction* hTrans = trans->QueryHttpTransaction();
191 if (hTrans) {
192 hTrans->BootstrapTimings(mBootstrappedTimings);
193 }
194 }
195 mBootstrappedTimings = TimingStruct();
196 }
197
198 mTransactionCaps = caps;
199 mPriority = pri;
200
201 NS_ENSURE_ARG_POINTER(trans);
202
203 // Connection failures are Activated() just like regular transacions.
204 // If we don't have a confirmation of a connected socket then test it
205 // with a write() to get relevant error code.
206 if (NS_FAILED(mErrorBeforeConnect)) {
207 CloseTransaction(nullptr, mErrorBeforeConnect);
208 trans->Close(mErrorBeforeConnect);
209 gHttpHandler->ExcludeHttp3(mConnInfo);
210 return mErrorBeforeConnect;
211 }
212
213 if (!mHttp3Session->AddStream(trans, pri, mCallbacks)) {
214 MOZ_ASSERT(false); // this cannot happen!
215 trans->Close(NS_ERROR_ABORT);
216 return NS_ERROR_FAILURE;
217 }
218
219 Unused << ResumeSend();
220 return NS_OK;
221 }
222
Close(nsresult reason,bool aIsShutdown)223 void HttpConnectionUDP::Close(nsresult reason, bool aIsShutdown) {
224 LOG(("HttpConnectionUDP::Close [this=%p reason=%" PRIx32 "]\n", this,
225 static_cast<uint32_t>(reason)));
226
227 MOZ_ASSERT(OnSocketThread(), "not on socket thread");
228
229 if (mForceSendTimer) {
230 mForceSendTimer->Cancel();
231 mForceSendTimer = nullptr;
232 }
233
234 if (!mTrafficCategory.IsEmpty()) {
235 HttpTrafficAnalyzer* hta = gHttpHandler->GetHttpTrafficAnalyzer();
236 if (hta) {
237 hta->IncrementHttpConnection(std::move(mTrafficCategory));
238 MOZ_ASSERT(mTrafficCategory.IsEmpty());
239 }
240 }
241 if (mSocket) {
242 mSocket->Close();
243 mSocket = nullptr;
244 }
245 }
246
DontReuse()247 void HttpConnectionUDP::DontReuse() {
248 LOG(("HttpConnectionUDP::DontReuse %p http3session=%p\n", this,
249 mHttp3Session.get()));
250 mDontReuse = true;
251 if (mHttp3Session) {
252 mHttp3Session->DontReuse();
253 }
254 }
255
TestJoinConnection(const nsACString & hostname,int32_t port)256 bool HttpConnectionUDP::TestJoinConnection(const nsACString& hostname,
257 int32_t port) {
258 if (mHttp3Session && CanDirectlyActivate()) {
259 return mHttp3Session->TestJoinConnection(hostname, port);
260 }
261
262 return false;
263 }
264
JoinConnection(const nsACString & hostname,int32_t port)265 bool HttpConnectionUDP::JoinConnection(const nsACString& hostname,
266 int32_t port) {
267 if (mHttp3Session && CanDirectlyActivate()) {
268 return mHttp3Session->JoinConnection(hostname, port);
269 }
270
271 return false;
272 }
273
CanReuse()274 bool HttpConnectionUDP::CanReuse() {
275 if (NS_FAILED(mErrorBeforeConnect)) {
276 return false;
277 }
278 if (mDontReuse) {
279 return false;
280 }
281
282 if (mHttp3Session) {
283 return mHttp3Session->CanReuse();
284 }
285 return false;
286 }
287
CanDirectlyActivate()288 bool HttpConnectionUDP::CanDirectlyActivate() {
289 // return true if a new transaction can be addded to ths connection at any
290 // time through Activate(). In practice this means this is a healthy SPDY
291 // connection with room for more concurrent streams.
292
293 if (mHttp3Session) {
294 return CanReuse();
295 }
296 return false;
297 }
298
299 //----------------------------------------------------------------------------
300 // HttpConnectionUDP::nsAHttpConnection compatible methods
301 //----------------------------------------------------------------------------
302
OnHeadersAvailable(nsAHttpTransaction * trans,nsHttpRequestHead * requestHead,nsHttpResponseHead * responseHead,bool * reset)303 nsresult HttpConnectionUDP::OnHeadersAvailable(nsAHttpTransaction* trans,
304 nsHttpRequestHead* requestHead,
305 nsHttpResponseHead* responseHead,
306 bool* reset) {
307 LOG(
308 ("HttpConnectionUDP::OnHeadersAvailable [this=%p trans=%p "
309 "response-head=%p]\n",
310 this, trans, responseHead));
311
312 MOZ_ASSERT(OnSocketThread(), "not on socket thread");
313 NS_ENSURE_ARG_POINTER(trans);
314 MOZ_ASSERT(responseHead, "No response head?");
315
316 DebugOnly<nsresult> rv =
317 responseHead->SetHeader(nsHttp::X_Firefox_Http3, mAlpnToken);
318 MOZ_ASSERT(NS_SUCCEEDED(rv));
319
320 // deal with 408 Server Timeouts
321 uint16_t responseStatus = responseHead->Status();
322 static const PRIntervalTime k1000ms = PR_MillisecondsToInterval(1000);
323 if (responseStatus == 408) {
324 // If this error could be due to a persistent connection reuse then
325 // we pass an error code of NS_ERROR_NET_RESET to
326 // trigger the transaction 'restart' mechanism. We tell it to reset its
327 // response headers so that it will be ready to receive the new response.
328 if (mIsReused &&
329 ((PR_IntervalNow() - mHttp3Session->LastWriteTime()) < k1000ms)) {
330 Close(NS_ERROR_NET_RESET);
331 *reset = true;
332 return NS_OK;
333 }
334 }
335
336 return NS_OK;
337 }
338
IsReused()339 bool HttpConnectionUDP::IsReused() { return mIsReused; }
340
TakeTransport(nsISocketTransport ** aTransport,nsIAsyncInputStream ** aInputStream,nsIAsyncOutputStream ** aOutputStream)341 nsresult HttpConnectionUDP::TakeTransport(
342 nsISocketTransport** aTransport, nsIAsyncInputStream** aInputStream,
343 nsIAsyncOutputStream** aOutputStream) {
344 return NS_ERROR_FAILURE;
345 }
346
GetSecurityInfo(nsISupports ** secinfo)347 void HttpConnectionUDP::GetSecurityInfo(nsISupports** secinfo) {
348 MOZ_ASSERT(OnSocketThread(), "not on socket thread");
349 LOG(("HttpConnectionUDP::GetSecurityInfo http3Session=%p\n",
350 mHttp3Session.get()));
351
352 if (mHttp3Session &&
353 NS_SUCCEEDED(mHttp3Session->GetTransactionSecurityInfo(secinfo))) {
354 return;
355 }
356
357 *secinfo = nullptr;
358 }
359
PushBack(const char * data,uint32_t length)360 nsresult HttpConnectionUDP::PushBack(const char* data, uint32_t length) {
361 LOG(("HttpConnectionUDP::PushBack [this=%p, length=%d]\n", this, length));
362
363 return NS_ERROR_UNEXPECTED;
364 }
365
366 class HttpConnectionUDPForceIO : public Runnable {
367 public:
HttpConnectionUDPForceIO(HttpConnectionUDP * aConn,bool doRecv)368 HttpConnectionUDPForceIO(HttpConnectionUDP* aConn, bool doRecv)
369 : Runnable("net::HttpConnectionUDPForceIO"),
370 mConn(aConn),
371 mDoRecv(doRecv) {}
372
Run()373 NS_IMETHOD Run() override {
374 MOZ_ASSERT(OnSocketThread(), "not on socket thread");
375
376 if (mDoRecv) {
377 return mConn->RecvData();
378 }
379
380 MOZ_ASSERT(mConn->mForceSendPending);
381 mConn->mForceSendPending = false;
382
383 return mConn->SendData();
384 }
385
386 private:
387 RefPtr<HttpConnectionUDP> mConn;
388 bool mDoRecv;
389 };
390
ResumeSend()391 nsresult HttpConnectionUDP::ResumeSend() {
392 LOG(("HttpConnectionUDP::ResumeSend [this=%p]\n", this));
393 MOZ_ASSERT(OnSocketThread(), "not on socket thread");
394 RefPtr<HttpConnectionUDP> self(this);
395 NS_DispatchToCurrentThread(
396 NS_NewRunnableFunction("HttpConnectionUDP::CallSendData",
397 [self{std::move(self)}]() { self->SendData(); }));
398 return NS_OK;
399 }
400
ResumeRecv()401 nsresult HttpConnectionUDP::ResumeRecv() { return NS_OK; }
402
ForceSendIO(nsITimer * aTimer,void * aClosure)403 void HttpConnectionUDP::ForceSendIO(nsITimer* aTimer, void* aClosure) {
404 MOZ_ASSERT(OnSocketThread(), "not on socket thread");
405 HttpConnectionUDP* self = static_cast<HttpConnectionUDP*>(aClosure);
406 MOZ_ASSERT(aTimer == self->mForceSendTimer);
407 self->mForceSendTimer = nullptr;
408 NS_DispatchToCurrentThread(new HttpConnectionUDPForceIO(self, false));
409 }
410
MaybeForceSendIO()411 nsresult HttpConnectionUDP::MaybeForceSendIO() {
412 MOZ_ASSERT(OnSocketThread(), "not on socket thread");
413 // due to bug 1213084 sometimes real I/O events do not get serviced when
414 // NSPR derived I/O events are ready and this can cause a deadlock with
415 // https over https proxying. Normally we would expect the write callback to
416 // be invoked before this timer goes off, but set it at the old windows
417 // tick interval (kForceDelay) as a backup for those circumstances.
418 static const uint32_t kForceDelay = 17; // ms
419
420 if (mForceSendPending) {
421 return NS_OK;
422 }
423 MOZ_ASSERT(!mForceSendTimer);
424 mForceSendPending = true;
425 return NS_NewTimerWithFuncCallback(
426 getter_AddRefs(mForceSendTimer), HttpConnectionUDP::ForceSendIO, this,
427 kForceDelay, nsITimer::TYPE_ONE_SHOT,
428 "net::HttpConnectionUDP::MaybeForceSendIO");
429 }
430
431 // trigger an asynchronous read
ForceRecv()432 nsresult HttpConnectionUDP::ForceRecv() {
433 LOG(("HttpConnectionUDP::ForceRecv [this=%p]\n", this));
434 MOZ_ASSERT(OnSocketThread(), "not on socket thread");
435
436 return NS_DispatchToCurrentThread(new HttpConnectionUDPForceIO(this, true));
437 }
438
439 // trigger an asynchronous write
ForceSend()440 nsresult HttpConnectionUDP::ForceSend() {
441 LOG(("HttpConnectionUDP::ForceSend [this=%p]\n", this));
442 MOZ_ASSERT(OnSocketThread(), "not on socket thread");
443
444 return MaybeForceSendIO();
445 }
446
Version()447 HttpVersion HttpConnectionUDP::Version() { return HttpVersion::v3_0; }
448
449 //-----------------------------------------------------------------------------
450 // HttpConnectionUDP <private>
451 //-----------------------------------------------------------------------------
452
CloseTransaction(nsAHttpTransaction * trans,nsresult reason,bool aIsShutdown)453 void HttpConnectionUDP::CloseTransaction(nsAHttpTransaction* trans,
454 nsresult reason, bool aIsShutdown) {
455 LOG(("HttpConnectionUDP::CloseTransaction[this=%p trans=%p reason=%" PRIx32
456 "]\n",
457 this, trans, static_cast<uint32_t>(reason)));
458
459 MOZ_ASSERT(trans == mHttp3Session);
460 MOZ_ASSERT(OnSocketThread(), "not on socket thread");
461
462 if (NS_SUCCEEDED(reason) || (reason == NS_BASE_STREAM_CLOSED)) {
463 MOZ_ASSERT(false);
464 return;
465 }
466
467 // The connection and security errors clear out alt-svc mappings
468 // in case any previously validated ones are now invalid
469 if (((reason == NS_ERROR_NET_RESET) ||
470 (NS_ERROR_GET_MODULE(reason) == NS_ERROR_MODULE_SECURITY)) &&
471 mConnInfo && !(mTransactionCaps & NS_HTTP_ERROR_SOFTLY)) {
472 gHttpHandler->ClearHostMapping(mConnInfo);
473 }
474
475 mDontReuse = true;
476 if (mHttp3Session) {
477 mHttp3Session->SetCleanShutdown(aIsShutdown);
478 mHttp3Session->Close(reason);
479 if (!mHttp3Session->IsClosed()) {
480 // During closing phase we still keep mHttp3Session session,
481 // to resend CLOSE_CONNECTION frames.
482 return;
483 }
484 }
485
486 mHttp3Session = nullptr;
487
488 {
489 MutexAutoLock lock(mCallbacksLock);
490 mCallbacks = nullptr;
491 }
492
493 Close(reason, aIsShutdown);
494
495 // flag the connection as reused here for convenience sake. certainly
496 // it might be going away instead ;-)
497 mIsReused = true;
498 }
499
OnQuicTimeout(nsITimer * aTimer,void * aClosure)500 void HttpConnectionUDP::OnQuicTimeout(nsITimer* aTimer, void* aClosure) {
501 MOZ_ASSERT(OnSocketThread(), "not on socket thread");
502 LOG(("HttpConnectionUDP::OnQuicTimeout [this=%p]\n", aClosure));
503
504 HttpConnectionUDP* self = static_cast<HttpConnectionUDP*>(aClosure);
505 self->OnQuicTimeoutExpired();
506 }
507
OnQuicTimeoutExpired()508 void HttpConnectionUDP::OnQuicTimeoutExpired() {
509 // if the transaction was dropped...
510 if (!mHttp3Session) {
511 LOG((" no transaction; ignoring event\n"));
512 return;
513 }
514
515 nsresult rv = mHttp3Session->ProcessOutputAndEvents(mSocket);
516 if (NS_FAILED(rv)) {
517 CloseTransaction(mHttp3Session, rv);
518 }
519 }
520
521 //-----------------------------------------------------------------------------
522 // HttpConnectionUDP::nsISupports
523 //-----------------------------------------------------------------------------
524
525 NS_IMPL_ADDREF(HttpConnectionUDP)
NS_IMPL_RELEASE(HttpConnectionUDP)526 NS_IMPL_RELEASE(HttpConnectionUDP)
527
528 NS_INTERFACE_MAP_BEGIN(HttpConnectionUDP)
529 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
530 NS_INTERFACE_MAP_ENTRY(nsIUDPSocketSyncListener)
531 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
532 NS_INTERFACE_MAP_ENTRY(HttpConnectionBase)
533 NS_INTERFACE_MAP_ENTRY_CONCRETE(HttpConnectionUDP)
534 NS_INTERFACE_MAP_END
535
536 // called on the socket transport thread
537 nsresult HttpConnectionUDP::RecvData() {
538 MOZ_ASSERT(OnSocketThread(), "not on socket thread");
539
540 // if the transaction was dropped...
541 if (!mHttp3Session) {
542 LOG((" no Http3Session; ignoring event\n"));
543 return NS_OK;
544 }
545
546 nsresult rv = mHttp3Session->RecvData(mSocket);
547 LOG(("HttpConnectionUDP::OnInputReady %p rv=%" PRIx32, this,
548 static_cast<uint32_t>(rv)));
549
550 if (NS_FAILED(rv)) CloseTransaction(mHttp3Session, rv);
551
552 return NS_OK;
553 }
554
555 // called on the socket transport thread
SendData()556 nsresult HttpConnectionUDP::SendData() {
557 MOZ_ASSERT(OnSocketThread(), "not on socket thread");
558
559 // if the transaction was dropped...
560 if (!mHttp3Session) {
561 LOG((" no Http3Session; ignoring event\n"));
562 return NS_OK;
563 }
564
565 nsresult rv = mHttp3Session->SendData(mSocket);
566 LOG(("HttpConnectionUDP::OnInputReady %p rv=%" PRIx32, this,
567 static_cast<uint32_t>(rv)));
568
569 if (NS_FAILED(rv)) CloseTransaction(mHttp3Session, rv);
570
571 return NS_OK;
572 }
573
574 //-----------------------------------------------------------------------------
575 // HttpConnectionUDP::nsIInterfaceRequestor
576 //-----------------------------------------------------------------------------
577
578 // not called on the socket transport thread
579 NS_IMETHODIMP
GetInterface(const nsIID & iid,void ** result)580 HttpConnectionUDP::GetInterface(const nsIID& iid, void** result) {
581 // NOTE: This function is only called on the UI thread via sync proxy from
582 // the socket transport thread. If that weren't the case, then we'd
583 // have to worry about the possibility of mHttp3Session going away
584 // part-way through this function call. See CloseTransaction.
585
586 // NOTE - there is a bug here, the call to getinterface is proxied off the
587 // nss thread, not the ui thread as the above comment says. So there is
588 // indeed a chance of mSession going away. bug 615342
589
590 MOZ_ASSERT(!OnSocketThread(), "on socket thread");
591
592 nsCOMPtr<nsIInterfaceRequestor> callbacks;
593 {
594 MutexAutoLock lock(mCallbacksLock);
595 callbacks = mCallbacks;
596 }
597 if (callbacks) return callbacks->GetInterface(iid, result);
598 return NS_ERROR_NO_INTERFACE;
599 }
600
SetEvent(nsresult aStatus)601 void HttpConnectionUDP::SetEvent(nsresult aStatus) {
602 switch (aStatus) {
603 case NS_NET_STATUS_RESOLVING_HOST:
604 mBootstrappedTimings.domainLookupStart = TimeStamp::Now();
605 break;
606 case NS_NET_STATUS_RESOLVED_HOST:
607 mBootstrappedTimings.domainLookupEnd = TimeStamp::Now();
608 break;
609 case NS_NET_STATUS_CONNECTING_TO:
610 mBootstrappedTimings.connectStart = TimeStamp::Now();
611 break;
612 case NS_NET_STATUS_CONNECTED_TO:
613 mBootstrappedTimings.connectEnd = TimeStamp::Now();
614 break;
615 case NS_NET_STATUS_TLS_HANDSHAKE_STARTING:
616 mBootstrappedTimings.secureConnectionStart = TimeStamp::Now();
617 break;
618 case NS_NET_STATUS_TLS_HANDSHAKE_ENDED:
619 mBootstrappedTimings.connectEnd = TimeStamp::Now();
620 break;
621 default:
622 break;
623 }
624 }
625
IsProxyConnectInProgress()626 bool HttpConnectionUDP::IsProxyConnectInProgress() { return false; }
627
LastTransactionExpectedNoContent()628 bool HttpConnectionUDP::LastTransactionExpectedNoContent() {
629 return mLastTransactionExpectedNoContent;
630 }
631
SetLastTransactionExpectedNoContent(bool val)632 void HttpConnectionUDP::SetLastTransactionExpectedNoContent(bool val) {
633 mLastTransactionExpectedNoContent = val;
634 }
635
IsPersistent()636 bool HttpConnectionUDP::IsPersistent() { return !mDontReuse; }
637
Transaction()638 nsAHttpTransaction* HttpConnectionUDP::Transaction() { return mHttp3Session; }
639
BytesWritten()640 int64_t HttpConnectionUDP::BytesWritten() {
641 if (!mHttp3Session) {
642 return 0;
643 }
644 return mHttp3Session->GetBytesWritten();
645 }
646
OnPacketReceived(nsIUDPSocket * aSocket)647 NS_IMETHODIMP HttpConnectionUDP::OnPacketReceived(nsIUDPSocket* aSocket) {
648 RecvData();
649 return NS_OK;
650 }
651
OnStopListening(nsIUDPSocket * aSocket,nsresult aStatus)652 NS_IMETHODIMP HttpConnectionUDP::OnStopListening(nsIUDPSocket* aSocket,
653 nsresult aStatus) {
654 CloseTransaction(mHttp3Session, aStatus);
655 return NS_OK;
656 }
657
GetSelfAddr(NetAddr * addr)658 nsresult HttpConnectionUDP::GetSelfAddr(NetAddr* addr) {
659 if (mSelfAddr) {
660 return mSelfAddr->GetNetAddr(addr);
661 }
662 return NS_ERROR_FAILURE;
663 }
664
GetPeerAddr(NetAddr * addr)665 nsresult HttpConnectionUDP::GetPeerAddr(NetAddr* addr) {
666 if (mPeerAddr) {
667 return mPeerAddr->GetNetAddr(addr);
668 }
669 return NS_ERROR_FAILURE;
670 }
671
ResolvedByTRR()672 bool HttpConnectionUDP::ResolvedByTRR() { return mResolvedByTRR; }
673
674 } // namespace net
675 } // namespace mozilla
676