summaryrefslogtreecommitdiff
path: root/packages/taler-util/src/http-impl.qtart.ts
blob: 954b41802ffb444211b3301bc9096ee1ca6ffb58 (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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/*
 This file is part of GNU Taler
 (C) 2019 Taler Systems S.A.

 GNU Taler is free software; you can redistribute it and/or modify it under the
 terms of the GNU General Public License as published by the Free Software
 Foundation; either version 3, or (at your option) any later version.

 GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 A PARTICULAR PURPOSE.  See the GNU General Public License for more details.

 You should have received a copy of the GNU General Public License along with
 GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>

 SPDX-License-Identifier: AGPL3.0-or-later
*/

/**
 * Imports.
 */
import { Logger } from "@gnu-taler/taler-util";
import { TalerError } from "./errors.js";
import { encodeBody, HttpLibArgs } from "./http-common.js";
import {
  Headers,
  HttpRequestLibrary,
  HttpRequestOptions,
  HttpResponse,
} from "./http.js";
import { RequestThrottler, TalerErrorCode, URL } from "./index.js";
import { qjsOs } from "./qtart.js";

const logger = new Logger("http-impl.qtart.ts");

const textDecoder = new TextDecoder();

/**
 * Implementation of the HTTP request library interface for node.
 */
export class HttpLibImpl implements HttpRequestLibrary {
  private throttle = new RequestThrottler();
  private throttlingEnabled = true;

  constructor(args?: HttpLibArgs) {
    this.throttlingEnabled = args?.enableThrottling ?? false;
  }

  /**
   * Set whether requests should be throttled.
   */
  setThrottling(enabled: boolean): void {
    this.throttlingEnabled = enabled;
  }

  async fetch(url: string, opt?: HttpRequestOptions): Promise<HttpResponse> {
    const method = opt?.method ?? "GET";

    logger.trace(`Requesting ${method} ${url}`);

    const parsedUrl = new URL(url);
    if (this.throttlingEnabled && this.throttle.applyThrottle(url)) {
      throw TalerError.fromDetail(
        TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED,
        {
          requestMethod: method,
          requestUrl: url,
          throttleStats: this.throttle.getThrottleStats(url),
        },
        `request to origin ${parsedUrl.origin} was throttled`,
      );
    }

    let data: ArrayBuffer | undefined = undefined;
    let headers: string[] = [];
    if (opt?.headers) {
      for (let headerName of Object.keys(opt.headers)) {
        headers.push(`${headerName}: ${opt.headers[headerName]}`);
      }
    }
    if (method.toUpperCase() === "POST") {
      data = encodeBody(opt?.body);
    }
    const res = await qjsOs.fetchHttp(url, {
      method,
      data,
      headers,
    });
    return {
      requestMethod: method,
      // FIXME: We don't return headers!
      headers: new Headers(),
      async bytes() {
        return res.data;
      },
      json() {
        const text = textDecoder.decode(res.data);
        return JSON.parse(text);
      },
      async text() {
        const text = textDecoder.decode(res.data);
        return text;
      },
      requestUrl: url,
      status: res.status,
    };
  }

  async get(url: string, opt?: HttpRequestOptions): Promise<HttpResponse> {
    return this.fetch(url, {
      method: "GET",
      ...opt,
    });
  }

  async postJson(
    url: string,
    body: any,
    opt?: HttpRequestOptions,
  ): Promise<HttpResponse> {
    return this.fetch(url, {
      method: "POST",
      body,
      ...opt,
    });
  }
}