Bug 1807268 - Re-enable verifyShowClipboardSuggestionsToggleTest UI test r=jajohnson
[gecko.git] / netwerk / dns / DNSRequestChild.cpp
blobec0f56b3f17971f0c266ec89e727976e66058ea4
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 & nsHostResolver::RES_CANON_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 memcpy(addr, &mAddresses[mCurrent++], sizeof(NetAddr));
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);
225 private:
226 virtual ~ChildDNSByTypeRecord() = default;
228 TypeRecordResultType mResults = AsVariant(mozilla::Nothing());
229 bool mAllRecordsExcluded = false;
230 uint32_t mTTL = 0;
233 NS_IMPL_ISUPPORTS(ChildDNSByTypeRecord, nsIDNSByTypeRecord, nsIDNSRecord,
234 nsIDNSTXTRecord, nsIDNSHTTPSSVCRecord)
236 ChildDNSByTypeRecord::ChildDNSByTypeRecord(const TypeRecordResultType& reply,
237 const nsACString& aHost,
238 uint32_t aTTL)
239 : DNSHTTPSSVCRecordBase(aHost) {
240 mResults = reply;
241 mTTL = aTTL;
244 NS_IMETHODIMP
245 ChildDNSByTypeRecord::GetType(uint32_t* aType) {
246 *aType = mResults.match(
247 [](TypeRecordEmpty&) {
248 MOZ_ASSERT(false, "This should never be the case");
249 return nsIDNSService::RESOLVE_TYPE_DEFAULT;
251 [](TypeRecordTxt&) { return nsIDNSService::RESOLVE_TYPE_TXT; },
252 [](TypeRecordHTTPSSVC&) { return nsIDNSService::RESOLVE_TYPE_HTTPSSVC; });
253 return NS_OK;
256 NS_IMETHODIMP
257 ChildDNSByTypeRecord::GetRecords(CopyableTArray<nsCString>& aRecords) {
258 if (!mResults.is<TypeRecordTxt>()) {
259 return NS_ERROR_NOT_AVAILABLE;
261 aRecords = mResults.as<CopyableTArray<nsCString>>();
262 return NS_OK;
265 NS_IMETHODIMP
266 ChildDNSByTypeRecord::GetRecordsAsOneString(nsACString& aRecords) {
267 // deep copy
268 if (!mResults.is<TypeRecordTxt>()) {
269 return NS_ERROR_NOT_AVAILABLE;
271 auto& results = mResults.as<CopyableTArray<nsCString>>();
272 for (uint32_t i = 0; i < results.Length(); i++) {
273 aRecords.Append(results[i]);
275 return NS_OK;
278 NS_IMETHODIMP
279 ChildDNSByTypeRecord::GetRecords(nsTArray<RefPtr<nsISVCBRecord>>& aRecords) {
280 if (!mResults.is<TypeRecordHTTPSSVC>()) {
281 return NS_ERROR_NOT_AVAILABLE;
284 auto& results = mResults.as<TypeRecordHTTPSSVC>();
286 for (const SVCB& r : results) {
287 RefPtr<nsISVCBRecord> rec = new SVCBRecord(r);
288 aRecords.AppendElement(rec);
290 return NS_OK;
293 NS_IMETHODIMP
294 ChildDNSByTypeRecord::GetServiceModeRecord(bool aNoHttp2, bool aNoHttp3,
295 nsISVCBRecord** aRecord) {
296 if (!mResults.is<TypeRecordHTTPSSVC>()) {
297 return NS_ERROR_NOT_AVAILABLE;
300 auto& results = mResults.as<TypeRecordHTTPSSVC>();
301 nsCOMPtr<nsISVCBRecord> result = GetServiceModeRecordInternal(
302 aNoHttp2, aNoHttp3, results, mAllRecordsExcluded);
303 if (!result) {
304 return NS_ERROR_NOT_AVAILABLE;
307 result.forget(aRecord);
308 return NS_OK;
311 NS_IMETHODIMP
312 ChildDNSByTypeRecord::GetAllRecordsWithEchConfig(
313 bool aNoHttp2, bool aNoHttp3, bool* aAllRecordsHaveEchConfig,
314 bool* aAllRecordsInH3ExcludedList,
315 nsTArray<RefPtr<nsISVCBRecord>>& aResult) {
316 if (!mResults.is<TypeRecordHTTPSSVC>()) {
317 return NS_ERROR_NOT_AVAILABLE;
320 auto& records = mResults.as<TypeRecordHTTPSSVC>();
321 GetAllRecordsWithEchConfigInternal(aNoHttp2, aNoHttp3, records,
322 aAllRecordsHaveEchConfig,
323 aAllRecordsInH3ExcludedList, aResult);
324 return NS_OK;
327 NS_IMETHODIMP
328 ChildDNSByTypeRecord::GetHasIPAddresses(bool* aResult) {
329 NS_ENSURE_ARG(aResult);
331 if (!mResults.is<TypeRecordHTTPSSVC>()) {
332 return NS_ERROR_NOT_AVAILABLE;
335 auto& results = mResults.as<TypeRecordHTTPSSVC>();
336 *aResult = HasIPAddressesInternal(results);
337 return NS_OK;
340 NS_IMETHODIMP
341 ChildDNSByTypeRecord::GetAllRecordsExcluded(bool* aResult) {
342 NS_ENSURE_ARG(aResult);
344 if (!mResults.is<TypeRecordHTTPSSVC>()) {
345 return NS_ERROR_NOT_AVAILABLE;
348 *aResult = mAllRecordsExcluded;
349 return NS_OK;
352 NS_IMETHODIMP
353 ChildDNSByTypeRecord::GetResults(mozilla::net::TypeRecordResultType* aResults) {
354 *aResults = mResults;
355 return NS_OK;
358 NS_IMETHODIMP
359 ChildDNSByTypeRecord::GetTtl(uint32_t* aResult) {
360 *aResult = mTTL;
361 return NS_OK;
364 //-----------------------------------------------------------------------------
365 // DNSRequestSender
366 //-----------------------------------------------------------------------------
368 NS_IMPL_ISUPPORTS(DNSRequestSender, nsICancelable)
370 DNSRequestSender::DNSRequestSender(const nsACString& aHost,
371 const nsACString& aTrrServer, int32_t aPort,
372 const uint16_t& aType,
373 const OriginAttributes& aOriginAttributes,
374 const nsIDNSService::DNSFlags& aFlags,
375 nsIDNSListener* aListener,
376 nsIEventTarget* target)
377 : mListener(aListener),
378 mTarget(target),
379 mResultStatus(NS_OK),
380 mHost(aHost),
381 mTrrServer(aTrrServer),
382 mPort(aPort),
383 mType(aType),
384 mOriginAttributes(aOriginAttributes),
385 mFlags(aFlags) {}
387 void DNSRequestSender::OnRecvCancelDNSRequest(
388 const nsCString& hostName, const nsCString& trrServer, const int32_t& port,
389 const uint16_t& type, const OriginAttributes& originAttributes,
390 const nsIDNSService::DNSFlags& flags, const nsresult& reason) {}
392 NS_IMETHODIMP
393 DNSRequestSender::Cancel(nsresult reason) {
394 if (!mIPCActor) {
395 return NS_ERROR_NOT_AVAILABLE;
398 // We can only do IPC on the MainThread
399 nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction(
400 "net::CancelDNSRequestEvent",
401 [actor(mIPCActor), host(mHost), trrServer(mTrrServer), port(mPort),
402 type(mType), originAttributes(mOriginAttributes), flags(mFlags),
403 reason]() {
404 if (!actor->CanSend()) {
405 return;
408 if (DNSRequestChild* child = actor->AsDNSRequestChild()) {
409 Unused << child->SendCancelDNSRequest(
410 host, trrServer, port, type, originAttributes, flags, reason);
411 } else if (DNSRequestParent* parent = actor->AsDNSRequestParent()) {
412 Unused << parent->SendCancelDNSRequest(
413 host, trrServer, port, type, originAttributes, flags, reason);
416 SchedulerGroup::Dispatch(runnable.forget());
417 return NS_OK;
420 void DNSRequestSender::StartRequest() {
421 // we can only do IPC on the MainThread
422 if (!NS_IsMainThread()) {
423 SchedulerGroup::Dispatch(
424 NewRunnableMethod("net::DNSRequestSender::StartRequest", this,
425 &DNSRequestSender::StartRequest));
426 return;
429 if (RefPtr<DNSRequestChild> child = mIPCActor->AsDNSRequestChild()) {
430 if (XRE_IsContentProcess()) {
431 mozilla::dom::ContentChild* cc =
432 static_cast<mozilla::dom::ContentChild*>(gNeckoChild->Manager());
433 if (cc->IsShuttingDown()) {
434 return;
437 // Send request to Parent process.
438 gNeckoChild->SendPDNSRequestConstructor(child, mHost, mTrrServer, mPort,
439 mType, mOriginAttributes, mFlags);
440 } else if (XRE_IsSocketProcess()) {
441 // DNS resolution is done in the parent process. Send a DNS request to
442 // parent process.
443 MOZ_ASSERT(!nsIOService::UseSocketProcess());
445 SocketProcessChild* socketProcessChild =
446 SocketProcessChild::GetSingleton();
447 if (!socketProcessChild->CanSend()) {
448 return;
451 MOZ_ALWAYS_TRUE(socketProcessChild->SendPDNSRequestConstructor(
452 child, mHost, mTrrServer, mPort, mType, mOriginAttributes, mFlags));
453 } else {
454 MOZ_ASSERT(false, "Wrong process");
455 return;
457 } else if (DNSRequestParent* parent = mIPCActor->AsDNSRequestParent()) {
458 // DNS resolution is done in the socket process. Send a DNS request to
459 // socket process.
460 MOZ_ASSERT(nsIOService::UseSocketProcess());
462 RefPtr<DNSRequestParent> requestParent = parent;
463 RefPtr<DNSRequestSender> self = this;
464 auto task = [requestParent, self]() {
465 Unused << SocketProcessParent::GetSingleton()->SendPDNSRequestConstructor(
466 requestParent, self->mHost, self->mTrrServer, self->mPort,
467 self->mType, self->mOriginAttributes, self->mFlags);
469 if (!gIOService->SocketProcessReady()) {
470 gIOService->CallOrWaitForSocketProcess(std::move(task));
471 return;
474 task();
478 void DNSRequestSender::CallOnLookupComplete() {
479 MOZ_ASSERT(mListener);
480 mListener->OnLookupComplete(this, mResultRecord, mResultStatus);
483 bool DNSRequestSender::OnRecvLookupCompleted(const DNSRequestResponse& reply) {
484 MOZ_ASSERT(mListener);
486 switch (reply.type()) {
487 case DNSRequestResponse::TDNSRecord: {
488 mResultRecord = new ChildDNSRecord(reply.get_DNSRecord(), mFlags);
489 break;
491 case DNSRequestResponse::Tnsresult: {
492 mResultStatus = reply.get_nsresult();
493 break;
495 case DNSRequestResponse::TIPCTypeRecord: {
496 MOZ_ASSERT(mType != nsIDNSService::RESOLVE_TYPE_DEFAULT);
497 mResultRecord =
498 new ChildDNSByTypeRecord(reply.get_IPCTypeRecord().mData, mHost,
499 reply.get_IPCTypeRecord().mTTL);
500 break;
502 default:
503 MOZ_ASSERT_UNREACHABLE("unknown type");
504 return false;
507 MOZ_ASSERT(NS_IsMainThread());
509 bool targetIsMain = false;
510 if (!mTarget) {
511 targetIsMain = true;
512 } else {
513 mTarget->IsOnCurrentThread(&targetIsMain);
516 if (targetIsMain) {
517 CallOnLookupComplete();
518 } else {
519 nsCOMPtr<nsIRunnable> event =
520 NewRunnableMethod("net::DNSRequestSender::CallOnLookupComplete", this,
521 &DNSRequestSender::CallOnLookupComplete);
522 mTarget->Dispatch(event, NS_DISPATCH_NORMAL);
525 if (DNSRequestChild* child = mIPCActor->AsDNSRequestChild()) {
526 Unused << mozilla::net::DNSRequestChild::Send__delete__(child);
527 } else if (DNSRequestParent* parent = mIPCActor->AsDNSRequestParent()) {
528 Unused << mozilla::net::DNSRequestParent::Send__delete__(parent);
531 return true;
534 void DNSRequestSender::OnIPCActorDestroy() {
535 // Request is done or destroyed. Remove it from the hash table.
536 RefPtr<ChildDNSService> dnsServiceChild =
537 dont_AddRef(ChildDNSService::GetSingleton());
538 dnsServiceChild->NotifyRequestDone(this);
540 mIPCActor = nullptr;
543 //-----------------------------------------------------------------------------
544 // DNSRequestChild
545 //-----------------------------------------------------------------------------
547 DNSRequestChild::DNSRequestChild(DNSRequestBase* aRequest)
548 : DNSRequestActor(aRequest) {
549 aRequest->SetIPCActor(this);
552 mozilla::ipc::IPCResult DNSRequestChild::RecvCancelDNSRequest(
553 const nsCString& hostName, const nsCString& trrServer, const int32_t& port,
554 const uint16_t& type, const OriginAttributes& originAttributes,
555 const nsIDNSService::DNSFlags& flags, const nsresult& reason) {
556 mDNSRequest->OnRecvCancelDNSRequest(hostName, trrServer, port, type,
557 originAttributes, flags, reason);
558 return IPC_OK();
561 mozilla::ipc::IPCResult DNSRequestChild::RecvLookupCompleted(
562 const DNSRequestResponse& reply) {
563 return mDNSRequest->OnRecvLookupCompleted(reply) ? IPC_OK()
564 : IPC_FAIL_NO_REASON(this);
567 void DNSRequestChild::ActorDestroy(ActorDestroyReason) {
568 mDNSRequest->OnIPCActorDestroy();
569 mDNSRequest = nullptr;
572 //------------------------------------------------------------------------------
573 } // namespace net
574 } // namespace mozilla