summaryrefslogtreecommitdiffstats
path: root/dom/credentialmanagement/identity/IdentityNetworkHelpers.h
blob: d812269612d9af9886a5ed32b13e04f4cb5102f0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_dom_IdentityNetworkHelpers_h
#define mozilla_dom_IdentityNetworkHelpers_h

#include "mozilla/dom/Promise.h"
#include "mozilla/dom/Promise-inl.h"
#include "mozilla/dom/Request.h"
#include "mozilla/dom/Response.h"
#include "mozilla/dom/WindowGlobalParent.h"
#include "mozilla/MozPromise.h"

namespace mozilla::dom {

// Helper to get a JSON structure via a Fetch.
// The Request must already be built and T should be a webidl type with
// annotation GenerateConversionToJS so it has an Init method.
template <typename T, typename TPromise = MozPromise<T, nsresult, true>>
RefPtr<TPromise> FetchJSONStructure(Request* aRequest) {
  MOZ_ASSERT(XRE_IsParentProcess());

  // Create the returned Promise
  RefPtr<typename TPromise::Private> resultPromise =
      new typename TPromise::Private(__func__);

  // Fetch the provided request
  RequestOrUSVString fetchInput;
  fetchInput.SetAsRequest() = aRequest;
  RootedDictionary<RequestInit> requestInit(RootingCx());
  IgnoredErrorResult error;
  RefPtr<Promise> fetchPromise =
      FetchRequest(aRequest->GetParentObject(), fetchInput, requestInit,
                   CallerType::System, error);
  if (NS_WARN_IF(error.Failed())) {
    resultPromise->Reject(NS_ERROR_FAILURE, __func__);
    return resultPromise;
  }

  // Working around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85883
  RefPtr<PromiseNativeHandler> reject =
      new MozPromiseRejectOnDestruction{resultPromise, __func__};

  // Handle the response
  fetchPromise->AddCallbacksWithCycleCollectedArgs(
      [resultPromise, reject](JSContext* aCx, JS::Handle<JS::Value> aValue,
                              ErrorResult&) {
        // Get the Response object from the argument to the callback
        if (NS_WARN_IF(!aValue.isObject())) {
          resultPromise->Reject(NS_ERROR_FAILURE, __func__);
          return;
        }
        JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
        MOZ_ASSERT(obj);
        Response* response = nullptr;
        if (NS_WARN_IF(NS_FAILED(UNWRAP_OBJECT(Response, &obj, response)))) {
          resultPromise->Reject(NS_ERROR_FAILURE, __func__);
          return;
        }

        // Make sure the request was a success
        if (!response->Ok()) {
          resultPromise->Reject(NS_ERROR_FAILURE, __func__);
          return;
        }

        // Parse the body into JSON, which must be done async
        IgnoredErrorResult error;
        RefPtr<Promise> jsonPromise = response->ConsumeBody(
            aCx, BodyConsumer::ConsumeType::CONSUME_JSON, error);
        if (NS_WARN_IF(error.Failed())) {
          resultPromise->Reject(NS_ERROR_FAILURE, __func__);
          return;
        }

        // Handle the parsed JSON from the Response body
        jsonPromise->AddCallbacksWithCycleCollectedArgs(
            [resultPromise](JSContext* aCx, JS::Handle<JS::Value> aValue,
                            ErrorResult&) {
              // Parse the JSON into the correct type, validating fields and
              // types
              T result;
              bool success = result.Init(aCx, aValue);
              if (!success) {
                resultPromise->Reject(NS_ERROR_FAILURE, __func__);
                return;
              }

              resultPromise->Resolve(result, __func__);
            },
            [resultPromise](JSContext*, JS::Handle<JS::Value> aValue,
                            ErrorResult&) {
              resultPromise->Reject(
                  Promise::TryExtractNSResultFromRejectionValue(aValue),
                  __func__);
            });
        jsonPromise->AppendNativeHandler(reject);
      },
      [resultPromise](JSContext*, JS::Handle<JS::Value> aValue, ErrorResult&) {
        resultPromise->Reject(
            Promise::TryExtractNSResultFromRejectionValue(aValue), __func__);
      });
  fetchPromise->AppendNativeHandler(reject);

  return resultPromise;
}

}  // namespace mozilla::dom

#endif  // mozilla_dom_IdentityNetworkHelpers_h