Bug 1931425 - Limit how often moz-label's #setStyles runs r=reusable-components-revie...
[gecko.git] / netwerk / dns / DNSRequestChild.cpp
blobe5f16c53642f8942fd5fe653ab7e8f8051f13d7e
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/. */
7 #include "mozilla/dom/ContentChild.h"
8 #include "mozilla/net/ChildDNSService.h"
9 #include "mozilla/net/DNSByTypeRecord.h"
10 #include "mozilla/net/DNSRequestChild.h"
11 #include "mozilla/net/DNSRequestParent.h"
12 #include "mozilla/net/NeckoChild.h"
13 #include "mozilla/net/SocketProcessChild.h"
14 #include "mozilla/SchedulerGroup.h"
15 #include "mozilla/net/SocketProcessParent.h"
16 #include "mozilla/Unused.h"
17 #include "nsIDNSRecord.h"
18 #include "nsIDNSByTypeRecord.h"
19 #include "nsHostResolver.h"
20 #include "nsIOService.h"
21 #include "nsTArray.h"
22 #include "nsNetAddr.h"
23 #include "nsThreadUtils.h"
25 using namespace mozilla::ipc;
27 namespace mozilla {
28 namespace net {
30 void DNSRequestBase::SetIPCActor(DNSRequestActor* aActor) {
31 mIPCActor = aActor;
34 //-----------------------------------------------------------------------------
35 // ChildDNSRecord:
36 // A simple class to provide nsIDNSRecord on the child
37 //-----------------------------------------------------------------------------
39 class ChildDNSRecord : public nsIDNSAddrRecord {
40 public:
41 NS_DECL_THREADSAFE_ISUPPORTS
42 NS_DECL_NSIDNSRECORD
43 NS_DECL_NSIDNSADDRRECORD
45 ChildDNSRecord(const DNSRecord& reply, nsIDNSService::DNSFlags flags);
47 private:
48 virtual ~ChildDNSRecord() = default;
50 nsCString mCanonicalName;
51 nsTArray<NetAddr> mAddresses;
52 uint32_t mCurrent = 0; // addr iterator
53 nsIDNSService::DNSFlags mFlags = nsIDNSService::RESOLVE_DEFAULT_FLAGS;
54 double mTrrFetchDuration = 0;
55 double mTrrFetchDurationNetworkOnly = 0;
56 bool mIsTRR = false;
57 bool mResolvedInSocketProcess = false;
58 nsIRequest::TRRMode mEffectiveTRRMode = nsIRequest::TRR_DEFAULT_MODE;
59 nsITRRSkipReason::value mTRRSkipReason = nsITRRSkipReason::TRR_UNSET;
60 uint32_t mTTL = 0;
63 NS_IMPL_ISUPPORTS(ChildDNSRecord, nsIDNSRecord, nsIDNSAddrRecord)
65 ChildDNSRecord::ChildDNSRecord(const DNSRecord& reply,
66 nsIDNSService::DNSFlags flags)
67 : mFlags(flags) {
68 mCanonicalName = reply.canonicalName();
69 mTrrFetchDuration = reply.trrFetchDuration();
70 mTrrFetchDurationNetworkOnly = reply.trrFetchDurationNetworkOnly();
71 mIsTRR = reply.isTRR();
72 // When ChildDNSRecord is created in parent process, we know this is case that
73 // DNS resolution is done in socket process.
74 mResolvedInSocketProcess = XRE_IsParentProcess();
75 mEffectiveTRRMode = reply.effectiveTRRMode();
77 // A shame IPDL gives us no way to grab ownership of array: so copy it.
78 const nsTArray<NetAddr>& addrs = reply.addrs();
79 mAddresses = addrs.Clone();
80 mTTL = reply.ttl();
83 //-----------------------------------------------------------------------------
84 // ChildDNSRecord::nsIDNSAddrRecord
85 //-----------------------------------------------------------------------------
87 NS_IMETHODIMP
88 ChildDNSRecord::GetCanonicalName(nsACString& result) {
89 if (!(mFlags & nsIDNSService::RESOLVE_CANONICAL_NAME)) {
90 return NS_ERROR_NOT_AVAILABLE;
93 result = mCanonicalName;
94 return NS_OK;
97 NS_IMETHODIMP
98 ChildDNSRecord::IsTRR(bool* retval) {
99 *retval = mIsTRR;
100 return NS_OK;
103 NS_IMETHODIMP
104 ChildDNSRecord::ResolvedInSocketProcess(bool* retval) {
105 *retval = mResolvedInSocketProcess;
106 return NS_OK;
109 NS_IMETHODIMP
110 ChildDNSRecord::GetTrrFetchDuration(double* aTime) {
111 *aTime = mTrrFetchDuration;
112 return NS_OK;
115 NS_IMETHODIMP
116 ChildDNSRecord::GetTrrFetchDurationNetworkOnly(double* aTime) {
117 *aTime = mTrrFetchDurationNetworkOnly;
118 return NS_OK;
121 NS_IMETHODIMP
122 ChildDNSRecord::GetNextAddr(uint16_t port, NetAddr* addr) {
123 if (mCurrent >= mAddresses.Length()) {
124 return NS_ERROR_NOT_AVAILABLE;
127 *addr = mAddresses[mCurrent++];
129 // both Ipv4/6 use same bits for port, so safe to just use ipv4's field
130 addr->inet.port = htons(port);
132 return NS_OK;
135 NS_IMETHODIMP
136 ChildDNSRecord::GetAddresses(nsTArray<NetAddr>& aAddressArray) {
137 aAddressArray = mAddresses.Clone();
138 return NS_OK;
141 // shamelessly copied from nsDNSRecord
142 NS_IMETHODIMP
143 ChildDNSRecord::GetScriptableNextAddr(uint16_t port, nsINetAddr** result) {
144 NetAddr addr;
145 nsresult rv = GetNextAddr(port, &addr);
146 if (NS_FAILED(rv)) {
147 return rv;
150 RefPtr<nsNetAddr> netaddr = new nsNetAddr(&addr);
151 netaddr.forget(result);
153 return NS_OK;
156 // also copied from nsDNSRecord
157 NS_IMETHODIMP
158 ChildDNSRecord::GetNextAddrAsString(nsACString& result) {
159 NetAddr addr;
160 nsresult rv = GetNextAddr(0, &addr);
161 if (NS_FAILED(rv)) {
162 return rv;
165 char buf[kIPv6CStrBufSize];
166 if (addr.ToStringBuffer(buf, sizeof(buf))) {
167 result.Assign(buf);
168 return NS_OK;
170 NS_ERROR("NetAddrToString failed unexpectedly");
171 return NS_ERROR_FAILURE; // conversion failed for some reason
174 NS_IMETHODIMP
175 ChildDNSRecord::HasMore(bool* result) {
176 *result = mCurrent < mAddresses.Length();
177 return NS_OK;
180 NS_IMETHODIMP
181 ChildDNSRecord::Rewind() {
182 mCurrent = 0;
183 return NS_OK;
186 NS_IMETHODIMP
187 ChildDNSRecord::ReportUnusable(uint16_t aPort) {
188 // "We thank you for your feedback" == >/dev/null
189 // TODO: we could send info back to parent.
190 return NS_OK;
193 NS_IMETHODIMP
194 ChildDNSRecord::GetEffectiveTRRMode(nsIRequest::TRRMode* aMode) {
195 *aMode = mEffectiveTRRMode;
196 return NS_OK;
199 NS_IMETHODIMP ChildDNSRecord::GetTrrSkipReason(
200 nsITRRSkipReason::value* aTrrSkipReason) {
201 *aTrrSkipReason = mTRRSkipReason;
202 return NS_OK;
205 NS_IMETHODIMP
206 ChildDNSRecord::GetTtl(uint32_t* aTtl) {
207 *aTtl = mTTL;
208 return NS_OK;
211 class ChildDNSByTypeRecord : public nsIDNSByTypeRecord,
212 public nsIDNSTXTRecord,
213 public nsIDNSHTTPSSVCRecord,
214 public DNSHTTPSSVCRecordBase {
215 public:
216 NS_DECL_THREADSAFE_ISUPPORTS
217 NS_DECL_NSIDNSRECORD
218 NS_DECL_NSIDNSBYTYPERECORD
219 NS_DECL_NSIDNSTXTRECORD
220 NS_DECL_NSIDNSHTTPSSVCRECORD
222 explicit ChildDNSByTypeRecord(const TypeRecordResultType& reply,
223 const nsACString& aHost, uint32_t aTTL,
224 bool aIsTRR);
226 private:
227 virtual ~ChildDNSByTypeRecord() = default;
229 TypeRecordResultType mResults = AsVariant(mozilla::Nothing());
230 bool mAllRecordsExcluded = false;
231 uint32_t mTTL = 0;
232 bool mIsTRR = false;
235 NS_IMPL_ISUPPORTS(ChildDNSByTypeRecord, nsIDNSByTypeRecord, nsIDNSRecord,
236 nsIDNSTXTRecord, nsIDNSHTTPSSVCRecord)
238 ChildDNSByTypeRecord::ChildDNSByTypeRecord(const TypeRecordResultType& reply,
239 const nsACString& aHost,
240 uint32_t aTTL, bool aIsTRR)
241 : DNSHTTPSSVCRecordBase(aHost) {
242 mResults = reply;
243 mTTL = aTTL;
244 mIsTRR = aIsTRR;
247 NS_IMETHODIMP
248 ChildDNSByTypeRecord::GetType(uint32_t* aType) {
249 *aType = mResults.match(
250 [](TypeRecordEmpty&) {
251 MOZ_ASSERT(false, "This should never be the case");
252 return nsIDNSService::RESOLVE_TYPE_DEFAULT;
254 [](TypeRecordTxt&) { return nsIDNSService::RESOLVE_TYPE_TXT; },
255 [](TypeRecordHTTPSSVC&) { return nsIDNSService::RESOLVE_TYPE_HTTPSSVC; });
256 return NS_OK;
259 NS_IMETHODIMP
260 ChildDNSByTypeRecord::GetRecords(CopyableTArray<nsCString>& aRecords) {
261 if (!mResults.is<TypeRecordTxt>()) {
262 return NS_ERROR_NOT_AVAILABLE;
264 aRecords = mResults.as<CopyableTArray<nsCString>>();
265 return NS_OK;
268 NS_IMETHODIMP
269 ChildDNSByTypeRecord::GetRecordsAsOneString(nsACString& aRecords) {
270 // deep copy
271 if (!mResults.is<TypeRecordTxt>()) {
272 return NS_ERROR_NOT_AVAILABLE;
274 auto& results = mResults.as<CopyableTArray<nsCString>>();
275 for (uint32_t i = 0; i < results.Length(); i++) {
276 aRecords.Append(results[i]);
278 return NS_OK;
281 NS_IMETHODIMP
282 ChildDNSByTypeRecord::GetRecords(nsTArray<RefPtr<nsISVCBRecord>>& aRecords) {
283 if (!mResults.is<TypeRecordHTTPSSVC>()) {
284 return NS_ERROR_NOT_AVAILABLE;
287 auto& results = mResults.as<TypeRecordHTTPSSVC>();
289 for (const SVCB& r : results) {
290 RefPtr<nsISVCBRecord> rec = new SVCBRecord(r);
291 aRecords.AppendElement(rec);
293 return NS_OK;
296 NS_IMETHODIMP
297 ChildDNSByTypeRecord::GetServiceModeRecord(bool aNoHttp2, bool aNoHttp3,
298 nsISVCBRecord** aRecord) {
299 return GetServiceModeRecordWithCname(aNoHttp2, aNoHttp3, ""_ns, aRecord);
302 NS_IMETHODIMP
303 ChildDNSByTypeRecord::IsTRR(bool* aResult) {
304 *aResult = mIsTRR;
305 return NS_OK;
308 NS_IMETHODIMP
309 ChildDNSByTypeRecord::GetServiceModeRecordWithCname(bool aNoHttp2,
310 bool aNoHttp3,
311 const nsACString& aCname,
312 nsISVCBRecord** aRecord) {
313 if (!mResults.is<TypeRecordHTTPSSVC>()) {
314 return NS_ERROR_NOT_AVAILABLE;
317 auto& results = mResults.as<TypeRecordHTTPSSVC>();
318 nsCOMPtr<nsISVCBRecord> result = GetServiceModeRecordInternal(
319 aNoHttp2, aNoHttp3, results, mAllRecordsExcluded, true, aCname);
320 if (!result) {
321 return NS_ERROR_NOT_AVAILABLE;
324 result.forget(aRecord);
325 return NS_OK;
328 NS_IMETHODIMP
329 ChildDNSByTypeRecord::GetAllRecordsWithEchConfig(
330 bool aNoHttp2, bool aNoHttp3, const nsACString& aCname,
331 bool* aAllRecordsHaveEchConfig, bool* aAllRecordsInH3ExcludedList,
332 nsTArray<RefPtr<nsISVCBRecord>>& aResult) {
333 if (!mResults.is<TypeRecordHTTPSSVC>()) {
334 return NS_ERROR_NOT_AVAILABLE;
337 auto& records = mResults.as<TypeRecordHTTPSSVC>();
338 GetAllRecordsWithEchConfigInternal(aNoHttp2, aNoHttp3, aCname, records,
339 aAllRecordsHaveEchConfig,
340 aAllRecordsInH3ExcludedList, aResult);
341 return NS_OK;
344 NS_IMETHODIMP
345 ChildDNSByTypeRecord::GetHasIPAddresses(bool* aResult) {
346 NS_ENSURE_ARG(aResult);
348 if (!mResults.is<TypeRecordHTTPSSVC>()) {
349 return NS_ERROR_NOT_AVAILABLE;
352 auto& results = mResults.as<TypeRecordHTTPSSVC>();
353 *aResult = HasIPAddressesInternal(results);
354 return NS_OK;
357 NS_IMETHODIMP
358 ChildDNSByTypeRecord::GetAllRecordsExcluded(bool* aResult) {
359 NS_ENSURE_ARG(aResult);
361 if (!mResults.is<TypeRecordHTTPSSVC>()) {
362 return NS_ERROR_NOT_AVAILABLE;
365 *aResult = mAllRecordsExcluded;
366 return NS_OK;
369 NS_IMETHODIMP
370 ChildDNSByTypeRecord::GetResults(mozilla::net::TypeRecordResultType* aResults) {
371 *aResults = mResults;
372 return NS_OK;
375 NS_IMETHODIMP
376 ChildDNSByTypeRecord::GetTtl(uint32_t* aResult) {
377 *aResult = mTTL;
378 return NS_OK;
381 //-----------------------------------------------------------------------------
382 // DNSRequestSender
383 //-----------------------------------------------------------------------------
385 NS_IMPL_ISUPPORTS(DNSRequestSender, nsICancelable)
387 DNSRequestSender::DNSRequestSender(const nsACString& aHost,
388 const nsACString& aTrrServer, int32_t aPort,
389 const uint16_t& aType,
390 const OriginAttributes& aOriginAttributes,
391 const nsIDNSService::DNSFlags& aFlags,
392 nsIDNSListener* aListener,
393 nsIEventTarget* target)
394 : mListener(aListener),
395 mTarget(target),
396 mResultStatus(NS_OK),
397 mHost(aHost),
398 mTrrServer(aTrrServer),
399 mPort(aPort),
400 mType(aType),
401 mOriginAttributes(aOriginAttributes),
402 mFlags(aFlags) {}
404 void DNSRequestSender::OnRecvCancelDNSRequest(
405 const nsCString& hostName, const nsCString& trrServer, const int32_t& port,
406 const uint16_t& type, const OriginAttributes& originAttributes,
407 const nsIDNSService::DNSFlags& flags, const nsresult& reason) {}
409 NS_IMETHODIMP
410 DNSRequestSender::Cancel(nsresult reason) {
411 // we can only do IPC on the MainThread
412 if (!NS_IsMainThread()) {
413 SchedulerGroup::Dispatch(
414 NewRunnableMethod<nsresult>("net::DNSRequestSender::Cancel", this,
415 &DNSRequestSender::Cancel, reason));
416 return NS_OK;
419 if (!mIPCActor || !mIPCActor->CanSend()) {
420 // Really a failure, but we won't be able to tell anyone about it anyways
421 return NS_OK;
424 if (DNSRequestChild* child = mIPCActor->AsDNSRequestChild()) {
425 Unused << child->SendCancelDNSRequest(mHost, mTrrServer, mPort, mType,
426 mOriginAttributes, mFlags, reason);
427 } else if (DNSRequestParent* parent = mIPCActor->AsDNSRequestParent()) {
428 Unused << parent->SendCancelDNSRequest(mHost, mTrrServer, mPort, mType,
429 mOriginAttributes, mFlags, reason);
432 return NS_OK;
435 void DNSRequestSender::StartRequest() {
436 // we can only do IPC on the MainThread
437 if (!NS_IsMainThread()) {
438 SchedulerGroup::Dispatch(
439 NewRunnableMethod("net::DNSRequestSender::StartRequest", this,
440 &DNSRequestSender::StartRequest));
441 return;
444 if (RefPtr<DNSRequestChild> child = mIPCActor->AsDNSRequestChild()) {
445 if (XRE_IsContentProcess()) {
446 mozilla::dom::ContentChild* cc =
447 static_cast<mozilla::dom::ContentChild*>(gNeckoChild->Manager());
448 if (cc->IsShuttingDown()) {
449 return;
452 // Send request to Parent process.
453 gNeckoChild->SendPDNSRequestConstructor(child, mHost, mTrrServer, mPort,
454 mType, mOriginAttributes, mFlags);
455 } else if (XRE_IsSocketProcess()) {
456 // DNS resolution is done in the parent process. Send a DNS request to
457 // parent process.
458 MOZ_ASSERT(!nsIOService::UseSocketProcess());
460 SocketProcessChild* socketProcessChild =
461 SocketProcessChild::GetSingleton();
462 if (!socketProcessChild->CanSend()) {
463 return;
466 MOZ_ALWAYS_TRUE(socketProcessChild->SendPDNSRequestConstructor(
467 child, mHost, mTrrServer, mPort, mType, mOriginAttributes, mFlags));
468 } else {
469 MOZ_ASSERT(false, "Wrong process");
470 return;
472 } else if (DNSRequestParent* parent = mIPCActor->AsDNSRequestParent()) {
473 // DNS resolution is done in the socket process. Send a DNS request to
474 // socket process.
475 MOZ_ASSERT(nsIOService::UseSocketProcess());
477 RefPtr<DNSRequestParent> requestParent = parent;
478 RefPtr<DNSRequestSender> self = this;
479 auto task = [requestParent, self]() {
480 RefPtr<SocketProcessParent> socketParent =
481 SocketProcessParent::GetSingleton();
482 Unused << socketParent->SendPDNSRequestConstructor(
483 requestParent, self->mHost, self->mTrrServer, self->mPort,
484 self->mType, self->mOriginAttributes, self->mFlags);
486 if (!gIOService->SocketProcessReady()) {
487 gIOService->CallOrWaitForSocketProcess(std::move(task));
488 return;
491 task();
495 void DNSRequestSender::CallOnLookupComplete() {
496 MOZ_ASSERT(mListener);
497 mListener->OnLookupComplete(this, mResultRecord, mResultStatus);
500 bool DNSRequestSender::OnRecvLookupCompleted(const DNSRequestResponse& reply) {
501 MOZ_ASSERT(mListener);
503 switch (reply.type()) {
504 case DNSRequestResponse::TDNSRecord: {
505 mResultRecord = new ChildDNSRecord(reply.get_DNSRecord(), mFlags);
506 break;
508 case DNSRequestResponse::Tnsresult: {
509 mResultStatus = reply.get_nsresult();
510 break;
512 case DNSRequestResponse::TIPCTypeRecord: {
513 MOZ_ASSERT(mType != nsIDNSService::RESOLVE_TYPE_DEFAULT);
514 mResultRecord = new ChildDNSByTypeRecord(
515 reply.get_IPCTypeRecord().mData, mHost,
516 reply.get_IPCTypeRecord().mTTL, reply.get_IPCTypeRecord().mIsTRR);
517 break;
519 default:
520 MOZ_ASSERT_UNREACHABLE("unknown type");
521 return false;
524 MOZ_ASSERT(NS_IsMainThread());
526 bool targetIsMain = false;
527 if (!mTarget) {
528 targetIsMain = true;
529 } else {
530 mTarget->IsOnCurrentThread(&targetIsMain);
533 if (targetIsMain) {
534 CallOnLookupComplete();
535 } else {
536 nsCOMPtr<nsIRunnable> event =
537 NewRunnableMethod("net::DNSRequestSender::CallOnLookupComplete", this,
538 &DNSRequestSender::CallOnLookupComplete);
539 mTarget->Dispatch(event, NS_DISPATCH_NORMAL);
542 if (DNSRequestChild* child = mIPCActor->AsDNSRequestChild()) {
543 Unused << mozilla::net::DNSRequestChild::Send__delete__(child);
544 } else if (DNSRequestParent* parent = mIPCActor->AsDNSRequestParent()) {
545 Unused << mozilla::net::DNSRequestParent::Send__delete__(parent);
548 return true;
551 void DNSRequestSender::OnIPCActorDestroy() {
552 // Request is done or destroyed. Remove it from the hash table.
553 RefPtr<ChildDNSService> dnsServiceChild =
554 dont_AddRef(ChildDNSService::GetSingleton());
555 dnsServiceChild->NotifyRequestDone(this);
557 mIPCActor = nullptr;
560 //-----------------------------------------------------------------------------
561 // DNSRequestChild
562 //-----------------------------------------------------------------------------
564 DNSRequestChild::DNSRequestChild(DNSRequestBase* aRequest)
565 : DNSRequestActor(aRequest) {
566 aRequest->SetIPCActor(this);
569 mozilla::ipc::IPCResult DNSRequestChild::RecvCancelDNSRequest(
570 const nsCString& hostName, const nsCString& trrServer, const int32_t& port,
571 const uint16_t& type, const OriginAttributes& originAttributes,
572 const nsIDNSService::DNSFlags& flags, const nsresult& reason) {
573 mDNSRequest->OnRecvCancelDNSRequest(hostName, trrServer, port, type,
574 originAttributes, flags, reason);
575 return IPC_OK();
578 mozilla::ipc::IPCResult DNSRequestChild::RecvLookupCompleted(
579 const DNSRequestResponse& reply) {
580 return mDNSRequest->OnRecvLookupCompleted(reply) ? IPC_OK()
581 : IPC_FAIL_NO_REASON(this);
584 void DNSRequestChild::ActorDestroy(ActorDestroyReason) {
585 mDNSRequest->OnIPCActorDestroy();
586 mDNSRequest = nullptr;
589 //------------------------------------------------------------------------------
590 } // namespace net
591 } // namespace mozilla