1 |
|
2 |
|
3 |
|
4 |
|
5 | import * as Request from "@types/request";
|
6 |
|
7 | import { AbortError, HttpError, TimeoutError } from "./Errors";
|
8 | import { HttpClient, HttpRequest, HttpResponse } from "./HttpClient";
|
9 | import { ILogger, LogLevel } from "./ILogger";
|
10 | import { isArrayBuffer } from "./Utils";
|
11 |
|
12 | let requestModule: Request.RequestAPI<Request.Request, Request.CoreOptions, Request.RequiredUriUrl>;
|
13 | if (typeof XMLHttpRequest === "undefined") {
|
14 |
|
15 |
|
16 | const requireFunc = typeof __webpack_require__ === "function" ? __non_webpack_require__ : require;
|
17 | requestModule = requireFunc("request");
|
18 | }
|
19 |
|
20 |
|
21 | export class NodeHttpClient extends HttpClient {
|
22 | private readonly logger: ILogger;
|
23 | private readonly request: typeof requestModule;
|
24 | private readonly cookieJar: Request.CookieJar;
|
25 |
|
26 | public constructor(logger: ILogger) {
|
27 | super();
|
28 | if (typeof requestModule === "undefined") {
|
29 | throw new Error("The 'request' module could not be loaded.");
|
30 | }
|
31 |
|
32 | this.logger = logger;
|
33 | this.cookieJar = requestModule.jar();
|
34 | this.request = requestModule.defaults({ jar: this.cookieJar });
|
35 | }
|
36 |
|
37 | public send(httpRequest: HttpRequest): Promise<HttpResponse> {
|
38 |
|
39 | if (httpRequest.abortSignal) {
|
40 | if (httpRequest.abortSignal.aborted) {
|
41 | return Promise.reject(new AbortError());
|
42 | }
|
43 | }
|
44 |
|
45 | return new Promise<HttpResponse>((resolve, reject) => {
|
46 |
|
47 | let requestBody: Buffer | string;
|
48 | if (isArrayBuffer(httpRequest.content)) {
|
49 | requestBody = Buffer.from(httpRequest.content);
|
50 | } else {
|
51 | requestBody = httpRequest.content || "";
|
52 | }
|
53 |
|
54 | const currentRequest = this.request(httpRequest.url!, {
|
55 | body: requestBody,
|
56 |
|
57 | encoding: httpRequest.responseType === "arraybuffer" ? null : "utf8",
|
58 | headers: {
|
59 |
|
60 | "X-Requested-With": "XMLHttpRequest",
|
61 | ...httpRequest.headers,
|
62 | },
|
63 | method: httpRequest.method,
|
64 | timeout: httpRequest.timeout,
|
65 | },
|
66 | (error, response, body) => {
|
67 | if (httpRequest.abortSignal) {
|
68 | httpRequest.abortSignal.onabort = null;
|
69 | }
|
70 |
|
71 | if (error) {
|
72 | if (error.code === "ETIMEDOUT") {
|
73 | this.logger.log(LogLevel.Warning, `Timeout from HTTP request.`);
|
74 | reject(new TimeoutError());
|
75 | }
|
76 | this.logger.log(LogLevel.Warning, `Error from HTTP request. ${error}`);
|
77 | reject(error);
|
78 | return;
|
79 | }
|
80 |
|
81 | if (response.statusCode >= 200 && response.statusCode < 300) {
|
82 | resolve(new HttpResponse(response.statusCode, response.statusMessage || "", body));
|
83 | } else {
|
84 | reject(new HttpError(response.statusMessage || "", response.statusCode || 0));
|
85 | }
|
86 | });
|
87 |
|
88 | if (httpRequest.abortSignal) {
|
89 | httpRequest.abortSignal.onabort = () => {
|
90 | currentRequest.abort();
|
91 | reject(new AbortError());
|
92 | };
|
93 | }
|
94 | });
|
95 | }
|
96 |
|
97 | public getCookieString(url: string): string {
|
98 | return this.cookieJar.getCookieString(url);
|
99 | }
|
100 | }
|
101 |
|
\ | No newline at end of file |