@api-client/core 0.3.2 → 0.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/browser.d.ts +1 -0
- package/build/browser.js +1 -0
- package/build/browser.js.map +1 -1
- package/build/index.d.ts +1 -1
- package/build/index.js +1 -1
- package/build/index.js.map +1 -1
- package/build/src/models/ErrorResponse.d.ts +5 -4
- package/build/src/models/ErrorResponse.js +18 -5
- package/build/src/models/ErrorResponse.js.map +1 -1
- package/build/src/models/SerializableError.d.ts +30 -0
- package/build/src/models/SerializableError.js +63 -0
- package/build/src/models/SerializableError.js.map +1 -0
- package/build/src/runtime/http-engine/ArcEngine.js +8 -4
- package/build/src/runtime/http-engine/ArcEngine.js.map +1 -1
- package/build/src/runtime/http-engine/HttpEngine.d.ts +3 -3
- package/build/src/runtime/http-engine/HttpEngine.js +3 -3
- package/build/src/runtime/http-engine/HttpEngine.js.map +1 -1
- package/build/src/runtime/http-engine/NodeEngine.js +9 -4
- package/build/src/runtime/http-engine/NodeEngine.js.map +1 -1
- package/build/src/runtime/http-engine/NodeEngineDirect.js +8 -2
- package/build/src/runtime/http-engine/NodeEngineDirect.js.map +1 -1
- package/build/src/runtime/node/ProjectRunner.d.ts +2 -2
- package/build/src/runtime/node/ProjectRunner.js +9 -2
- package/build/src/runtime/node/ProjectRunner.js.map +1 -1
- package/build/src/runtime/store/StoreSdk.js +10 -15
- package/build/src/runtime/store/StoreSdk.js.map +1 -1
- package/package.json +1 -1
- package/src/data/DataReader.ts +11 -0
- package/src/data/DataUtils.ts +108 -0
- package/src/data/JmesparthReader.ts +26 -0
- package/src/data/Json2Xml.ts +190 -0
- package/src/data/JsonReader.ts +41 -0
- package/src/data/PayloadPointer.ts +48 -0
- package/src/data/RequestDataExtractor.ts +133 -0
- package/src/data/UrlEncodedReader.ts +20 -0
- package/src/data/XmlReader.ts +103 -0
- package/src/events/BaseEvents.ts +259 -0
- package/src/events/CustomEvent.ts +27 -0
- package/src/events/EventTypes.ts +19 -0
- package/src/events/Events.ts +19 -0
- package/src/events/authorization/AuthorizationEventTypes.ts +22 -0
- package/src/events/authorization/AuthorizationEvents.ts +61 -0
- package/src/events/cookies/CookieEventTypes.ts +13 -0
- package/src/events/cookies/CookieEvents.ts +157 -0
- package/src/events/encryption/EncryptionEventTypes.ts +4 -0
- package/src/events/encryption/EncryptionEvents.ts +51 -0
- package/src/events/environment/EnvironmentEventTypes.ts +3 -0
- package/src/events/environment/EnvironmentEvents.ts +24 -0
- package/src/events/models/ClientCertificateEvents.ts +87 -0
- package/src/events/models/ModelEventTypes.ts +47 -0
- package/src/events/models/ModelEvents.ts +7 -0
- package/src/events/models/ProjectEvents.ts +331 -0
- package/src/events/process/ProcessEventTypes.ts +5 -0
- package/src/events/process/ProcessEvents.ts +76 -0
- package/src/events/readme.md +22 -0
- package/src/events/reporting/ReportingEventTypes.ts +3 -0
- package/src/events/reporting/ReportingEvents.ts +28 -0
- package/src/events/telemetry/TelemetryEventTypes.ts +10 -0
- package/src/events/telemetry/TelemetryEvents.ts +156 -0
- package/src/lib/cookies/Cookie.ts +312 -0
- package/src/lib/cookies/Cookies.ts +326 -0
- package/src/lib/cookies/Utils.ts +168 -0
- package/src/lib/headers/Headers.ts +219 -0
- package/src/lib/logging/DefaultLogger.ts +19 -0
- package/src/lib/logging/DummyLogger.ts +21 -0
- package/src/lib/logging/Logger.ts +16 -0
- package/src/lib/transformers/PayloadSerializer.ts +332 -0
- package/src/lib/transformers/Utils.ts +18 -0
- package/src/lib/uuid.ts +40 -0
- package/src/mocking/LegacyInterfaces.ts +52 -0
- package/src/mocking/LegacyMock.ts +37 -0
- package/src/mocking/legacy/Authorization.ts +39 -0
- package/src/mocking/legacy/Certificates.ts +145 -0
- package/src/mocking/legacy/Cookies.ts +51 -0
- package/src/mocking/legacy/HostRules.ts +43 -0
- package/src/mocking/legacy/Http.ts +236 -0
- package/src/mocking/legacy/HttpResponse.ts +106 -0
- package/src/mocking/legacy/RestApi.ts +68 -0
- package/src/mocking/legacy/Urls.ts +44 -0
- package/src/mocking/legacy/Variables.ts +53 -0
- package/src/models/ArcResponse.ts +166 -0
- package/src/models/Authorization.ts +481 -0
- package/src/models/AuthorizationData.ts +60 -0
- package/src/models/Backend.ts +107 -0
- package/src/models/ClientCertificate.ts +68 -0
- package/src/models/Environment.ts +279 -0
- package/src/models/ErrorResponse.ts +113 -0
- package/src/models/HistoryIndex.ts +76 -0
- package/src/models/HistoryRequest.ts +28 -0
- package/src/models/HostRule.ts +163 -0
- package/src/models/HttpCookie.ts +285 -0
- package/src/models/HttpProject.ts +1294 -0
- package/src/models/HttpProjectListItem.ts +23 -0
- package/src/models/HttpRequest.ts +124 -0
- package/src/models/HttpResponse.ts +143 -0
- package/src/models/License.ts +113 -0
- package/src/models/ProjectDefinitionProperty.ts +40 -0
- package/src/models/ProjectFolder.ts +439 -0
- package/src/models/ProjectItem.ts +135 -0
- package/src/models/ProjectParent.ts +113 -0
- package/src/models/ProjectRequest.ts +277 -0
- package/src/models/ProjectSchema.ts +202 -0
- package/src/models/Property.ts +423 -0
- package/src/models/Provider.ts +98 -0
- package/src/models/README.md +20 -0
- package/src/models/Request.ts +452 -0
- package/src/models/RequestActions.ts +163 -0
- package/src/models/RequestAuthorization.ts +115 -0
- package/src/models/RequestConfig.ts +317 -0
- package/src/models/RequestLog.ts +159 -0
- package/src/models/RequestTime.ts +108 -0
- package/src/models/RequestUiMeta.ts +258 -0
- package/src/models/RequestsSize.ts +65 -0
- package/src/models/ResponseAuthorization.ts +104 -0
- package/src/models/ResponseRedirect.ts +158 -0
- package/src/models/RevisionInfo.ts +37 -0
- package/src/models/SentRequest.ts +125 -0
- package/src/models/SerializableError.ts +80 -0
- package/src/models/SerializablePayload.ts +68 -0
- package/src/models/Server.ts +153 -0
- package/src/models/Thing.ts +110 -0
- package/src/models/Url.ts +90 -0
- package/src/models/User.ts +120 -0
- package/src/models/WebApi.ts +234 -0
- package/src/models/WebApiIndex.ts +122 -0
- package/src/models/Workspace.ts +182 -0
- package/src/models/actions/Action.ts +213 -0
- package/src/models/actions/ActionView.ts +40 -0
- package/src/models/actions/Condition.ts +207 -0
- package/src/models/actions/ConditionView.ts +42 -0
- package/src/models/actions/Enums.ts +29 -0
- package/src/models/actions/RunnableAction.ts +144 -0
- package/src/models/actions/runnable/DeleteCookieAction.ts +113 -0
- package/src/models/actions/runnable/Runnable.ts +9 -0
- package/src/models/actions/runnable/SetCookieAction.ts +216 -0
- package/src/models/actions/runnable/SetVariableAction.ts +81 -0
- package/src/models/legacy/DataExport.ts +172 -0
- package/src/models/legacy/Normalizer.ts +110 -0
- package/src/models/legacy/actions/Actions.ts +269 -0
- package/src/models/legacy/authorization/Authorization.ts +572 -0
- package/src/models/legacy/models/ApiTypes.ts +202 -0
- package/src/models/legacy/models/ArcLegacyProject.ts +39 -0
- package/src/models/legacy/models/AuthData.ts +17 -0
- package/src/models/legacy/models/ClientCertificate.ts +95 -0
- package/src/models/legacy/models/Cookies.ts +52 -0
- package/src/models/legacy/models/HostRule.ts +35 -0
- package/src/models/legacy/models/RestApi.ts +49 -0
- package/src/models/legacy/models/UrlHistory.ts +37 -0
- package/src/models/legacy/models/Variable.ts +43 -0
- package/src/models/legacy/models/base.d.ts +95 -0
- package/src/models/legacy/request/ArcRequest.ts +405 -0
- package/src/models/legacy/request/ArcResponse.ts +177 -0
- package/src/models/legacy/request/HistoryData.ts +47 -0
- package/src/models/legacy/request/Legacy.ts +45 -0
- package/src/models/legacy/request/RequestBody.ts +87 -0
- package/src/models/transformers/ArcDexieTransformer.ts +323 -0
- package/src/models/transformers/ArcLegacyNormalizer.ts +85 -0
- package/src/models/transformers/ArcLegacyTransformer.ts +200 -0
- package/src/models/transformers/ArcPouchTransformer.ts +184 -0
- package/src/models/transformers/BaseTransformer.ts +116 -0
- package/src/models/transformers/ImportUtils.ts +141 -0
- package/src/models/transformers/LegacyDataExportToApiProject.ts +76 -0
- package/src/models/transformers/LegacyExportProcessor.ts +252 -0
- package/src/models/transformers/PostmanBackupTransformer.ts +306 -0
- package/src/models/transformers/PostmanDataTransformer.ts +50 -0
- package/src/models/transformers/PostmanTransformer.ts +106 -0
- package/src/models/transformers/PostmanV21Transformer.ts +311 -0
- package/src/models/transformers/PostmanV2Transformer.ts +308 -0
- package/src/models/transformers/har.ts +865 -0
- package/src/runtime/actions/ActionRunner.ts +83 -0
- package/src/runtime/actions/ConditionRunner.ts +194 -0
- package/src/runtime/actions/RunnableCondition.ts +57 -0
- package/src/runtime/actions/runnable/ActionRunnable.ts +19 -0
- package/src/runtime/actions/runnable/DeleteCookieRunnable.ts +39 -0
- package/src/runtime/actions/runnable/SetCookieRunnable.ts +92 -0
- package/src/runtime/actions/runnable/SetVariableRunnable.ts +53 -0
- package/src/runtime/http-engine/ArcEngine.ts +1068 -0
- package/src/runtime/http-engine/FormData.ts +85 -0
- package/src/runtime/http-engine/HttpEngine.ts +874 -0
- package/src/runtime/http-engine/HttpErrorCodes.ts +270 -0
- package/src/runtime/http-engine/NodeEngine.ts +792 -0
- package/src/runtime/http-engine/NodeEngineDirect.ts +482 -0
- package/src/runtime/http-engine/PayloadSupport.ts +84 -0
- package/src/runtime/http-engine/RequestUtils.ts +164 -0
- package/src/runtime/http-engine/ntlm/Des.ts +345 -0
- package/src/runtime/http-engine/ntlm/MD4.ts +135 -0
- package/src/runtime/http-engine/ntlm/NtlmAuth.ts +186 -0
- package/src/runtime/http-engine/ntlm/NtlmMessage.ts +57 -0
- package/src/runtime/modules/BasicAuthCache.ts +133 -0
- package/src/runtime/modules/ExecutionResponse.ts +4 -0
- package/src/runtime/modules/ModulesRegistry.ts +136 -0
- package/src/runtime/modules/RequestAuthorization.ts +110 -0
- package/src/runtime/modules/RequestCookies.ts +145 -0
- package/src/runtime/node/ProjectRunner.ts +281 -0
- package/src/runtime/node/RequestFactory.ts +422 -0
- package/src/runtime/node/VariablesStore.ts +25 -0
- package/src/runtime/store/StoreSdk.ts +838 -0
- package/src/runtime/variables/Cache.ts +53 -0
- package/src/runtime/variables/EvalFunctions.ts +132 -0
- package/src/runtime/variables/ProjectVariables.ts +6 -0
- package/src/runtime/variables/VariablesProcessor.ts +543 -0
- package/src/runtime/variables/VariablesTokenizer.ts +55 -0
- package/build/src/runtime/http-engine/Errors.d.ts +0 -10
- package/build/src/runtime/http-engine/Errors.js +0 -14
- package/build/src/runtime/http-engine/Errors.js.map +0 -1
|
@@ -0,0 +1,792 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
3
|
+
import { URL, UrlWithStringQuery } from 'url';
|
|
4
|
+
import http from 'http';
|
|
5
|
+
import https from 'https';
|
|
6
|
+
import net from 'net';
|
|
7
|
+
import { HttpEngine, HttpEngineOptions, ResponseErrorInit, HeadersReceivedDetail } from './HttpEngine.js';
|
|
8
|
+
import { IHttpRequest } from '../../models/HttpRequest.js';
|
|
9
|
+
import { ArcResponse } from '../../models/ArcResponse.js';
|
|
10
|
+
import { IRequestLog } from '../../models/RequestLog.js';
|
|
11
|
+
import { SerializableError } from '../../models/SerializableError.js';
|
|
12
|
+
import { Headers } from '../../lib/headers/Headers.js';
|
|
13
|
+
import { PayloadSupport } from './PayloadSupport.js';
|
|
14
|
+
import { addContentLength, getPort } from './RequestUtils.js';
|
|
15
|
+
import { INtlmAuthorization } from '../../models/Authorization.js';
|
|
16
|
+
import { NtlmAuth, INtlmAuthConfig } from './ntlm/NtlmAuth.js';
|
|
17
|
+
|
|
18
|
+
export class NodeEngine extends HttpEngine {
|
|
19
|
+
responseReported = false;
|
|
20
|
+
|
|
21
|
+
_sentHttpMessage: any;
|
|
22
|
+
|
|
23
|
+
client?: http.ClientRequest;
|
|
24
|
+
receivingResponse = false;
|
|
25
|
+
|
|
26
|
+
constructor(request: IHttpRequest, opts: HttpEngineOptions = {}) {
|
|
27
|
+
super(request, opts);
|
|
28
|
+
|
|
29
|
+
this._connectHandler = this._connectHandler.bind(this);
|
|
30
|
+
this._secureConnectHandler = this._secureConnectHandler.bind(this);
|
|
31
|
+
this._responseHandler = this._responseHandler.bind(this);
|
|
32
|
+
this._timeoutHandler = this._timeoutHandler.bind(this);
|
|
33
|
+
this._errorHandler = this._errorHandler.bind(this);
|
|
34
|
+
this._lookupHandler = this._lookupHandler.bind(this);
|
|
35
|
+
this._closeHandler = this._closeHandler.bind(this);
|
|
36
|
+
this._socketHandler = this._socketHandler.bind(this);
|
|
37
|
+
this._sendEndHandler = this._sendEndHandler.bind(this);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Sends the request
|
|
42
|
+
*/
|
|
43
|
+
async send(): Promise<IRequestLog> {
|
|
44
|
+
this.abort();
|
|
45
|
+
this.aborted = false;
|
|
46
|
+
const promise = this.wrapExecution();
|
|
47
|
+
this.sendRequest();
|
|
48
|
+
return promise;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private async sendRequest(): Promise<void> {
|
|
52
|
+
try {
|
|
53
|
+
const message = await this._prepareMessage();
|
|
54
|
+
const request = this.opts.proxy ? await this._connectProxy(this.opts.proxy, message) : this._connect(message);
|
|
55
|
+
if (request) {
|
|
56
|
+
this.client = request;
|
|
57
|
+
const { timeout } = this;
|
|
58
|
+
if (timeout > 0) {
|
|
59
|
+
request.setTimeout(timeout);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
} catch (cause) {
|
|
63
|
+
console.warn(cause);
|
|
64
|
+
const e = cause as any;
|
|
65
|
+
const err = new SerializableError(e.message, { cause: e });
|
|
66
|
+
if (e.code || e.code === 0) {
|
|
67
|
+
err.code = e.code as string;
|
|
68
|
+
}
|
|
69
|
+
this.finalizeRequest(e);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Prepares the request body (the payload) and the headers.
|
|
75
|
+
*
|
|
76
|
+
* @return Resolved promise to a `Buffer`. Undefined when no message.
|
|
77
|
+
*/
|
|
78
|
+
async _prepareMessage(): Promise<Buffer|undefined> {
|
|
79
|
+
const { method='GET', headers } = this.request;
|
|
80
|
+
let { payload } = this.request;
|
|
81
|
+
if (['get', 'head'].includes(method.toLowerCase())) {
|
|
82
|
+
payload = undefined;
|
|
83
|
+
}
|
|
84
|
+
const engineHeaders = new Headers(headers);
|
|
85
|
+
this.prepareHeaders(engineHeaders);
|
|
86
|
+
let buffer: Buffer | undefined;
|
|
87
|
+
if (payload) {
|
|
88
|
+
buffer = await PayloadSupport.payloadToBuffer(payload, engineHeaders);
|
|
89
|
+
if (buffer) {
|
|
90
|
+
addContentLength(method, buffer, engineHeaders);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
this._handleAuthorization(engineHeaders);
|
|
94
|
+
this.sentRequest.headers = engineHeaders.toString();
|
|
95
|
+
// if (this.auth) {
|
|
96
|
+
// // This restores altered by the authorization original headers
|
|
97
|
+
// // so it can be safe to use when redirecting
|
|
98
|
+
// if (this.auth.headers) {
|
|
99
|
+
// this.request.headers = this.auth.headers;
|
|
100
|
+
// delete this.auth.headers;
|
|
101
|
+
// }
|
|
102
|
+
// }
|
|
103
|
+
return buffer;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Connects to the remote machine.
|
|
108
|
+
*/
|
|
109
|
+
_connect(message?: Buffer): http.ClientRequest {
|
|
110
|
+
const uri = new URL(this.request.url);
|
|
111
|
+
const port = getPort(uri.port, uri.protocol);
|
|
112
|
+
if (port === 443 || uri.protocol === 'https:') {
|
|
113
|
+
return this._connectHttps(uri, message);
|
|
114
|
+
}
|
|
115
|
+
return this._connectHttp(uri, message);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Creates a connection using regular transport.
|
|
120
|
+
*/
|
|
121
|
+
_connectHttp(uri: URL, message?: Buffer): http.ClientRequest {
|
|
122
|
+
if (!uri.port) {
|
|
123
|
+
uri.port = '80';
|
|
124
|
+
}
|
|
125
|
+
const options = this._createGenericOptions(uri);
|
|
126
|
+
options.agent = new http.Agent({ keepAlive: true });
|
|
127
|
+
const startTime = Date.now();
|
|
128
|
+
this.stats.startTime = startTime;
|
|
129
|
+
this.sentRequest.startTime = startTime;
|
|
130
|
+
|
|
131
|
+
const request = http.request(options);
|
|
132
|
+
this._setCommonListeners(request);
|
|
133
|
+
if (message) {
|
|
134
|
+
request.write(message);
|
|
135
|
+
}
|
|
136
|
+
this.stats.messageStart = Date.now();
|
|
137
|
+
request.end();
|
|
138
|
+
// This is a hack to read sent data.
|
|
139
|
+
// In the https://github.com/nodejs/node/blob/0a62026f32d513a8a5d9ed857481df5f5fa18e8b/lib/_http_outgoing.js#L960
|
|
140
|
+
// library it hold the data until it is flushed.
|
|
141
|
+
// @ts-ignore
|
|
142
|
+
const pending = request.outputData;
|
|
143
|
+
if (Array.isArray(pending)) {
|
|
144
|
+
this._sentHttpMessage = pending;
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
this.emit('loadstart');
|
|
148
|
+
} catch (_) {
|
|
149
|
+
//
|
|
150
|
+
}
|
|
151
|
+
return request;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Creates a connection using SSL transport.
|
|
156
|
+
*/
|
|
157
|
+
_connectHttps(uri: URL, message?: Buffer): http.ClientRequest {
|
|
158
|
+
if (!uri.port) {
|
|
159
|
+
uri.port = '443';
|
|
160
|
+
}
|
|
161
|
+
const options = this._createGenericOptions(uri);
|
|
162
|
+
this._addSslOptions(options);
|
|
163
|
+
const startTime = Date.now();
|
|
164
|
+
this.stats.startTime = startTime;
|
|
165
|
+
this.sentRequest.startTime = startTime;
|
|
166
|
+
|
|
167
|
+
const request = https.request(options);
|
|
168
|
+
this._setCommonListeners(request);
|
|
169
|
+
if (message) {
|
|
170
|
+
request.write(message);
|
|
171
|
+
}
|
|
172
|
+
this.stats.messageStart = Date.now();
|
|
173
|
+
this.stats.sentTime = this.stats.messageStart + 1;
|
|
174
|
+
request.end();
|
|
175
|
+
// This is a hack to read sent data.
|
|
176
|
+
// In the https://github.com/nodejs/node/blob/0a62026f32d513a8a5d9ed857481df5f5fa18e8b/lib/_http_outgoing.js#L960
|
|
177
|
+
// library it hold the data until it is flushed.
|
|
178
|
+
// @ts-ignore
|
|
179
|
+
const pending = request.outputData;
|
|
180
|
+
if (Array.isArray(pending)) {
|
|
181
|
+
this._sentHttpMessage = pending;
|
|
182
|
+
}
|
|
183
|
+
try {
|
|
184
|
+
this.emit('loadstart');
|
|
185
|
+
} catch (_) {
|
|
186
|
+
//
|
|
187
|
+
}
|
|
188
|
+
return request;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Sets listeners on a socket
|
|
193
|
+
* @param request The request object
|
|
194
|
+
*/
|
|
195
|
+
_setCommonListeners(request: http.ClientRequest): void {
|
|
196
|
+
// request.shouldKeepAlive = false;
|
|
197
|
+
request.once('socket', this._socketHandler);
|
|
198
|
+
request.once('error', this._errorHandler);
|
|
199
|
+
request.once('response', this._responseHandler);
|
|
200
|
+
request.once('close', this._closeHandler);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Handler for connection error.
|
|
205
|
+
*/
|
|
206
|
+
_errorHandler(e: ResponseErrorInit): void {
|
|
207
|
+
if (this.aborted) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
this._errorRequest({
|
|
211
|
+
code: e.code,
|
|
212
|
+
message: e.message,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Handler for DNS lookup.
|
|
218
|
+
*/
|
|
219
|
+
_lookupHandler(): void {
|
|
220
|
+
this.stats.lookupTime = Date.now();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Handler for connected event.
|
|
225
|
+
*/
|
|
226
|
+
_secureConnectHandler(): void {
|
|
227
|
+
this.stats.secureConnectedTime = Date.now();
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Handler for connecting event.
|
|
232
|
+
*/
|
|
233
|
+
_connectHandler(): void {
|
|
234
|
+
this.stats.connectedTime = Date.now();
|
|
235
|
+
this.stats.secureStartTime = Date.now();
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Handler for sending finished event
|
|
240
|
+
*/
|
|
241
|
+
_sendEndHandler(): void {
|
|
242
|
+
if (!this.stats.sentTime) {
|
|
243
|
+
this.stats.sentTime = Date.now();
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Handler for timeout event
|
|
249
|
+
*/
|
|
250
|
+
_timeoutHandler(): void {
|
|
251
|
+
this._errorRequest({
|
|
252
|
+
code: 7,
|
|
253
|
+
});
|
|
254
|
+
this.abort();
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* A handler for response data event
|
|
259
|
+
*/
|
|
260
|
+
_responseHandler(res: http.IncomingMessage): void {
|
|
261
|
+
this.receivingResponse = true;
|
|
262
|
+
|
|
263
|
+
this.emit('firstbyte');
|
|
264
|
+
this.stats.firstReceiveTime = Date.now();
|
|
265
|
+
this.stats.responseTime = Date.now();
|
|
266
|
+
if (this._sentHttpMessage) {
|
|
267
|
+
this.sentRequest.httpMessage = this._readSentMessage(this._sentHttpMessage);
|
|
268
|
+
} else {
|
|
269
|
+
this.sentRequest.httpMessage = '';
|
|
270
|
+
}
|
|
271
|
+
const status = res.statusCode;
|
|
272
|
+
if (!status) {
|
|
273
|
+
this._errorRequest({
|
|
274
|
+
message: 'The response has no status.',
|
|
275
|
+
});
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
const headers = this.computeResponseHeaders(res);
|
|
279
|
+
const rawHeaders = headers.toString();
|
|
280
|
+
const response = ArcResponse.fromValues(status, res.statusMessage, rawHeaders);
|
|
281
|
+
this.currentResponse = response;
|
|
282
|
+
this.currentHeaders = headers;
|
|
283
|
+
const detail: HeadersReceivedDetail = {
|
|
284
|
+
returnValue: true,
|
|
285
|
+
value: rawHeaders,
|
|
286
|
+
};
|
|
287
|
+
this.emit('headersreceived', detail);
|
|
288
|
+
if (!detail.returnValue) {
|
|
289
|
+
this.abort();
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
// if (status === 401 && this.auth) {
|
|
293
|
+
// switch (this.auth.method) {
|
|
294
|
+
// case 'ntlm': this._handleNtlmResponse(); break;
|
|
295
|
+
// }
|
|
296
|
+
// }
|
|
297
|
+
res.on('data', (chunk) => {
|
|
298
|
+
if (!this._rawBody) {
|
|
299
|
+
this._rawBody = chunk;
|
|
300
|
+
} else {
|
|
301
|
+
const endTime = Date.now();
|
|
302
|
+
this.stats.lastReceivedTime = endTime;
|
|
303
|
+
this._rawBody = Buffer.concat([this._rawBody, chunk]);
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
res.once('end', () => {
|
|
307
|
+
const endTime = Date.now();
|
|
308
|
+
this.sentRequest.endTime = endTime;
|
|
309
|
+
this.stats.receivingTime = endTime;
|
|
310
|
+
this._reportResponse();
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Handler for connection close event
|
|
316
|
+
*/
|
|
317
|
+
_closeHandler(): void {
|
|
318
|
+
if (this.responseReported || this.receivingResponse || this.aborted || this.redirecting) {
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
if (!this.currentResponse) {
|
|
322
|
+
const e = new Error('Connection closed unexpectedly.');
|
|
323
|
+
// console.log(e.stack);
|
|
324
|
+
// console.log(this.sentRequest);
|
|
325
|
+
this._errorRequest(e);
|
|
326
|
+
} else {
|
|
327
|
+
// There is an issue with the response. Size mismatch? Anyway,
|
|
328
|
+
// it tries to create a response from current data.
|
|
329
|
+
this.emit('loadend');
|
|
330
|
+
this._publishResponse();
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
_socketHandler(socket: net.Socket): void {
|
|
335
|
+
this.socket = socket;
|
|
336
|
+
socket.once('lookup', this._lookupHandler);
|
|
337
|
+
socket.once('connect', this._connectHandler);
|
|
338
|
+
socket.once('timeout', this._timeoutHandler);
|
|
339
|
+
socket.once('end', this._sendEndHandler);
|
|
340
|
+
socket.once('secureConnect', this._secureConnectHandler);
|
|
341
|
+
this.stats.connectionTime = Date.now();
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Creates and publishes a response.
|
|
346
|
+
*/
|
|
347
|
+
_reportResponse(): void {
|
|
348
|
+
const { aborted, currentResponse } = this;
|
|
349
|
+
if (aborted || !currentResponse) {
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
const { status } = currentResponse;
|
|
353
|
+
if (status >= 300 && status < 400) {
|
|
354
|
+
if (this.followRedirects !== false && this._reportRedirect(status)) {
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
if (this.responseReported) {
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
this.responseReported = true;
|
|
362
|
+
this.emit('loadend');
|
|
363
|
+
this._publishResponse();
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Transforms a message from the client to a string.
|
|
368
|
+
* It uses `opts.sentMessageLimit` to limit number of data returned
|
|
369
|
+
* by the client.
|
|
370
|
+
*/
|
|
371
|
+
_readSentMessage(messages: string|any[]): string {
|
|
372
|
+
let result = '';
|
|
373
|
+
if (typeof messages === 'string') {
|
|
374
|
+
result = messages;
|
|
375
|
+
} else {
|
|
376
|
+
for (let i = 0, len = messages.length; i < len; i++) {
|
|
377
|
+
const chunk = messages[i].data;
|
|
378
|
+
if (!chunk) {
|
|
379
|
+
continue;
|
|
380
|
+
}
|
|
381
|
+
if (typeof chunk === 'string') {
|
|
382
|
+
result += chunk;
|
|
383
|
+
} else if (chunk instanceof Uint8Array) {
|
|
384
|
+
result += chunk.toString();
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
const limit = this.opts.sentMessageLimit;
|
|
389
|
+
if (limit && limit > 0 && result.length >= limit) {
|
|
390
|
+
result = result.substr(0, limit);
|
|
391
|
+
result += ' ...';
|
|
392
|
+
}
|
|
393
|
+
return result;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Connects to the remote machine via a proxy.
|
|
398
|
+
*/
|
|
399
|
+
async _connectProxy(proxy: string, message?: Buffer): Promise<http.ClientRequest | undefined> {
|
|
400
|
+
const { url } = this.request;
|
|
401
|
+
const isTargetSsl = url.startsWith('https:');
|
|
402
|
+
const isProxySsl = proxy.startsWith('https:');
|
|
403
|
+
const uri = new URL(url);
|
|
404
|
+
|
|
405
|
+
if (!isProxySsl && !isTargetSsl) {
|
|
406
|
+
return this._proxyHttpOverHttp(uri, proxy, message);
|
|
407
|
+
}
|
|
408
|
+
if (!isProxySsl && isTargetSsl) {
|
|
409
|
+
return this._proxyHttpsOverHttp(uri, proxy, message);
|
|
410
|
+
}
|
|
411
|
+
if (isProxySsl && !isTargetSsl) {
|
|
412
|
+
return this._proxyHttpOverHttps(uri, proxy, message);
|
|
413
|
+
}
|
|
414
|
+
return this._proxyHttpsOverHttps(uri, proxy, message);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Creates a default options for a request.
|
|
419
|
+
* @param uri Instance of URL class for current URL.
|
|
420
|
+
*/
|
|
421
|
+
_createGenericOptions(uri: URL | UrlWithStringQuery): http.RequestOptions {
|
|
422
|
+
const result: http.RequestOptions = {
|
|
423
|
+
protocol: uri.protocol,
|
|
424
|
+
host: uri.hostname,
|
|
425
|
+
// hash: uri.hash,
|
|
426
|
+
method: this.request.method.toUpperCase(),
|
|
427
|
+
};
|
|
428
|
+
result.headers = {};
|
|
429
|
+
if (uri.port) {
|
|
430
|
+
result.port = uri.port;
|
|
431
|
+
}
|
|
432
|
+
result.path = `${uri.pathname}${uri.search}`;
|
|
433
|
+
// Note, the final headers are set on the `sentRequest` object.
|
|
434
|
+
// The `request` object is not changed.
|
|
435
|
+
const headers = new Headers(this.sentRequest.headers);
|
|
436
|
+
for (const [key, value] of headers.entries()) {
|
|
437
|
+
result.headers[key] = value;
|
|
438
|
+
}
|
|
439
|
+
return result;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Adds SSL options to the request.
|
|
444
|
+
*/
|
|
445
|
+
_addSslOptions(options: any): void {
|
|
446
|
+
if (this.opts.validateCertificates) {
|
|
447
|
+
options.checkServerIdentity = this._checkServerIdentity.bind(this);
|
|
448
|
+
} else {
|
|
449
|
+
options.rejectUnauthorized = false;
|
|
450
|
+
options.requestOCSP = false;
|
|
451
|
+
}
|
|
452
|
+
const certs = this.opts.certificates;
|
|
453
|
+
if (Array.isArray(certs)) {
|
|
454
|
+
certs.forEach(cert => this._addClientCertificate(cert, options));
|
|
455
|
+
}
|
|
456
|
+
options.agent = new https.Agent(options);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Creates options to be set on the proxy request.
|
|
461
|
+
* It replaces the original `host` and `port` values with the ones defined
|
|
462
|
+
* for the proxy server.
|
|
463
|
+
*
|
|
464
|
+
* @param proxy The proxy URI. (e.g. 10.0.0.12:8118)
|
|
465
|
+
* @param requestUri The original request URI.
|
|
466
|
+
* @param requestOptions The original request options
|
|
467
|
+
*/
|
|
468
|
+
_createProxyOptions(proxy: string, requestUri: URL, requestOptions: http.RequestOptions): http.RequestOptions {
|
|
469
|
+
let proxyUrl = proxy;
|
|
470
|
+
const options = requestOptions;
|
|
471
|
+
const isSsl = proxyUrl.startsWith('https:');
|
|
472
|
+
const isHttp = proxyUrl.startsWith('http:');
|
|
473
|
+
if (!isSsl && !isHttp) {
|
|
474
|
+
proxyUrl = `http://${proxyUrl}`;
|
|
475
|
+
}
|
|
476
|
+
const proxyUri = new URL(proxyUrl);
|
|
477
|
+
if (!options.headers) {
|
|
478
|
+
options.headers = {};
|
|
479
|
+
}
|
|
480
|
+
const auth = this._proxyAuthHeader();
|
|
481
|
+
if (auth) {
|
|
482
|
+
if (!options.headers['proxy-authorization']) {
|
|
483
|
+
options.headers['proxy-authorization'] = auth;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
options.headers.host = `${requestUri.hostname}:${requestUri.port || 80}`;
|
|
487
|
+
delete options.headers.Host;
|
|
488
|
+
return {
|
|
489
|
+
...options,
|
|
490
|
+
protocol: proxyUri.protocol,
|
|
491
|
+
host: proxyUri.hostname,
|
|
492
|
+
hostname: proxyUri.hostname,
|
|
493
|
+
port: proxyUri.port || 80,
|
|
494
|
+
path: requestUri.toString(),
|
|
495
|
+
agent: false,
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* Creates a connection to non-ssl target via a non-ssl proxy.
|
|
501
|
+
*
|
|
502
|
+
* @param message The message to send
|
|
503
|
+
* @param uri The target URI
|
|
504
|
+
* @param proxy The proxy URI
|
|
505
|
+
*/
|
|
506
|
+
_proxyHttpOverHttp(uri: URL, proxy: string, message?: Buffer): http.ClientRequest {
|
|
507
|
+
const targetOptions = this._createGenericOptions(uri);
|
|
508
|
+
const options = this._createProxyOptions(proxy, uri, targetOptions);
|
|
509
|
+
const startTime = Date.now();
|
|
510
|
+
this.stats.startTime = startTime;
|
|
511
|
+
this.sentRequest.startTime = startTime;
|
|
512
|
+
const request = http.request(options);
|
|
513
|
+
this._setCommonListeners(request);
|
|
514
|
+
if (message) {
|
|
515
|
+
request.write(message);
|
|
516
|
+
}
|
|
517
|
+
this.stats.messageStart = Date.now();
|
|
518
|
+
this.stats.sentTime = this.stats.messageStart + 1;
|
|
519
|
+
request.end();
|
|
520
|
+
try {
|
|
521
|
+
this.emit('loadstart');
|
|
522
|
+
} catch (_) {
|
|
523
|
+
//
|
|
524
|
+
}
|
|
525
|
+
return request;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* Creates a connection to non-ssl target via an ssl proxy.
|
|
530
|
+
*
|
|
531
|
+
* @param message The message to send
|
|
532
|
+
* @param uri The target URI
|
|
533
|
+
* @param proxy The proxy URI
|
|
534
|
+
*/
|
|
535
|
+
async _proxyHttpsOverHttp(uri: URL, proxy: string, message?: Buffer): Promise<http.ClientRequest|undefined> {
|
|
536
|
+
let proxyUrl = proxy;
|
|
537
|
+
if (!proxyUrl.startsWith('http:')) {
|
|
538
|
+
proxyUrl = `http://${proxyUrl}`;
|
|
539
|
+
}
|
|
540
|
+
const proxyUri = new URL(proxyUrl);
|
|
541
|
+
const proxyPort = proxyUri.port || 80;
|
|
542
|
+
const targetPort = uri.port || 443; // target is always SSL so 443.
|
|
543
|
+
const authority = `${uri.hostname}:${targetPort}`;
|
|
544
|
+
const connectOptions: http.RequestOptions = {
|
|
545
|
+
host: proxyUri.hostname,
|
|
546
|
+
port: proxyPort,
|
|
547
|
+
method: 'CONNECT',
|
|
548
|
+
path: authority,
|
|
549
|
+
headers: {
|
|
550
|
+
host: authority,
|
|
551
|
+
},
|
|
552
|
+
};
|
|
553
|
+
const auth = this._proxyAuthHeader();
|
|
554
|
+
if (auth) {
|
|
555
|
+
connectOptions.headers = {
|
|
556
|
+
'proxy-authorization': auth,
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
return new Promise((resolve, reject) => {
|
|
560
|
+
const connectRequest = http.request(connectOptions);
|
|
561
|
+
connectRequest.on('connect', (res, socket, head) => {
|
|
562
|
+
if (res.statusCode === 200) {
|
|
563
|
+
const options = this._createGenericOptions(uri);
|
|
564
|
+
this._addSslOptions(options);
|
|
565
|
+
delete options.agent;
|
|
566
|
+
const startTime = Date.now();
|
|
567
|
+
this.stats.startTime = startTime;
|
|
568
|
+
this.sentRequest.startTime = startTime;
|
|
569
|
+
const agent = new https.Agent({
|
|
570
|
+
socket,
|
|
571
|
+
});
|
|
572
|
+
const request = https.request({ ...options, agent });
|
|
573
|
+
this._connectHandler();
|
|
574
|
+
this._setCommonListeners(request);
|
|
575
|
+
if (message) {
|
|
576
|
+
request.write(message);
|
|
577
|
+
}
|
|
578
|
+
request.end();
|
|
579
|
+
this.stats.messageStart = Date.now();
|
|
580
|
+
this.stats.sentTime = this.stats.messageStart + 1;
|
|
581
|
+
resolve(request);
|
|
582
|
+
} else if (res.statusCode === 401) {
|
|
583
|
+
this.currentHeaders = this.computeResponseHeaders(res);
|
|
584
|
+
const response = ArcResponse.fromValues(res.statusCode, res.statusMessage, this.currentHeaders.toString());
|
|
585
|
+
this.currentResponse = response;
|
|
586
|
+
if (head.length) {
|
|
587
|
+
this._rawBody = head;
|
|
588
|
+
this.currentResponse.payload = {
|
|
589
|
+
type: 'buffer',
|
|
590
|
+
data: [...head],
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
connectRequest.destroy();
|
|
594
|
+
resolve(undefined);
|
|
595
|
+
setTimeout(() => {
|
|
596
|
+
// const e = new NetError('The proxy requires authentication.', 127);
|
|
597
|
+
this._publishResponse();
|
|
598
|
+
});
|
|
599
|
+
} else {
|
|
600
|
+
connectRequest.destroy();
|
|
601
|
+
const e = new SerializableError('A tunnel connection through the proxy could not be established', 111);
|
|
602
|
+
reject(e);
|
|
603
|
+
}
|
|
604
|
+
});
|
|
605
|
+
connectRequest.once('error', (err) => reject(err));
|
|
606
|
+
try {
|
|
607
|
+
this.emit('loadstart');
|
|
608
|
+
} catch (_) {
|
|
609
|
+
//
|
|
610
|
+
}
|
|
611
|
+
connectRequest.end();
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
/**
|
|
616
|
+
* Creates a connection to a non-ssl target using SSL proxy.
|
|
617
|
+
*
|
|
618
|
+
* @param proxy The proxy URI
|
|
619
|
+
*/
|
|
620
|
+
_proxyHttpOverHttps(uri: URL, proxy: string, message?: Buffer): http.ClientRequest {
|
|
621
|
+
const targetOptions = this._createGenericOptions(uri);
|
|
622
|
+
const options: https.RequestOptions = this._createProxyOptions(proxy, uri, targetOptions);
|
|
623
|
+
options.rejectUnauthorized = false;
|
|
624
|
+
// @ts-ignore
|
|
625
|
+
options.requestOCSP = false;
|
|
626
|
+
const startTime = Date.now();
|
|
627
|
+
this.stats.startTime = startTime;
|
|
628
|
+
this.sentRequest.startTime = startTime;
|
|
629
|
+
const request = https.request(options);
|
|
630
|
+
this._setCommonListeners(request);
|
|
631
|
+
if (message) {
|
|
632
|
+
request.write(message);
|
|
633
|
+
}
|
|
634
|
+
this.stats.messageStart = Date.now();
|
|
635
|
+
this.stats.sentTime = this.stats.messageStart + 1;
|
|
636
|
+
request.end();
|
|
637
|
+
// @ts-ignore
|
|
638
|
+
const pending = request.outputData;
|
|
639
|
+
if (Array.isArray(pending)) {
|
|
640
|
+
this._sentHttpMessage = pending;
|
|
641
|
+
}
|
|
642
|
+
try {
|
|
643
|
+
this.emit('loadstart');
|
|
644
|
+
} catch (_) {
|
|
645
|
+
//
|
|
646
|
+
}
|
|
647
|
+
return request;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* Creates a connection to a non-ssl target using SSL proxy.
|
|
652
|
+
*
|
|
653
|
+
* @param proxy The proxy URI
|
|
654
|
+
*/
|
|
655
|
+
_proxyHttpsOverHttps(uri: URL, proxy: string, message?: Buffer): http.ClientRequest {
|
|
656
|
+
let proxyUrl = proxy;
|
|
657
|
+
if (!proxyUrl.startsWith('https:')) {
|
|
658
|
+
proxyUrl = `https://${proxyUrl}`;
|
|
659
|
+
}
|
|
660
|
+
const proxyUri = new URL(proxyUrl);
|
|
661
|
+
const connectOptions: https.RequestOptions = {
|
|
662
|
+
host: proxyUri.hostname, // IP address of proxy server
|
|
663
|
+
port: proxyUri.port || 443, // port of proxy server
|
|
664
|
+
method: 'CONNECT',
|
|
665
|
+
path: `${uri.hostname}:${uri.port || 443}`,
|
|
666
|
+
headers: {
|
|
667
|
+
host: `${uri.hostname}:${uri.port || 443}`,
|
|
668
|
+
},
|
|
669
|
+
rejectUnauthorized: false,
|
|
670
|
+
// @ts-ignore
|
|
671
|
+
requestOCSP: false,
|
|
672
|
+
};
|
|
673
|
+
const auth = this._proxyAuthHeader();
|
|
674
|
+
if (auth) {
|
|
675
|
+
connectOptions.headers = {
|
|
676
|
+
'proxy-authorization': auth,
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
const connectRequest = https.request(connectOptions);
|
|
680
|
+
connectRequest.on('connect', (res, socket) => {
|
|
681
|
+
if (res.statusCode === 200) {
|
|
682
|
+
const agent = new https.Agent({ socket });
|
|
683
|
+
const options = this._createGenericOptions(uri);
|
|
684
|
+
this._addSslOptions(options);
|
|
685
|
+
const startTime = Date.now();
|
|
686
|
+
this.stats.startTime = startTime;
|
|
687
|
+
this.sentRequest.startTime = startTime;
|
|
688
|
+
const sslRequest = https.request({ ...options, agent, protocol: 'https:' });
|
|
689
|
+
sslRequest.on('error', () => {
|
|
690
|
+
console.log('sslRequest error');
|
|
691
|
+
});
|
|
692
|
+
this._connectHandler();
|
|
693
|
+
this._setCommonListeners(sslRequest);
|
|
694
|
+
if (message) {
|
|
695
|
+
sslRequest.write(message);
|
|
696
|
+
}
|
|
697
|
+
this.stats.messageStart = Date.now();
|
|
698
|
+
this.stats.sentTime = this.stats.messageStart + 1;
|
|
699
|
+
sslRequest.end();
|
|
700
|
+
// @ts-ignore
|
|
701
|
+
const pending = sslRequest.outputData;
|
|
702
|
+
if (Array.isArray(pending)) {
|
|
703
|
+
this._sentHttpMessage = pending;
|
|
704
|
+
}
|
|
705
|
+
} else {
|
|
706
|
+
this._errorRequest({
|
|
707
|
+
code: 111,
|
|
708
|
+
message: 'A tunnel connection through the proxy could not be established.',
|
|
709
|
+
});
|
|
710
|
+
connectRequest.destroy();
|
|
711
|
+
}
|
|
712
|
+
});
|
|
713
|
+
connectRequest.once('error', this._errorHandler);
|
|
714
|
+
try {
|
|
715
|
+
this.emit('loadstart');
|
|
716
|
+
} catch (_) {
|
|
717
|
+
//
|
|
718
|
+
}
|
|
719
|
+
connectRequest.end();
|
|
720
|
+
return connectRequest;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
/**
|
|
724
|
+
* Alters authorization header depending on the `auth` object
|
|
725
|
+
* @param {ArcHeaders} headers A headers object where to append headers if
|
|
726
|
+
* needed
|
|
727
|
+
*/
|
|
728
|
+
_handleAuthorization(headers: Headers): void {
|
|
729
|
+
const { authorization } = this.opts;
|
|
730
|
+
const enabled = Array.isArray(authorization) ? authorization.filter((i) => i.enabled) : [];
|
|
731
|
+
if (!enabled.length) {
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
734
|
+
const ntlm = enabled.find((i) => i.type === 'ntlm');
|
|
735
|
+
if (ntlm) {
|
|
736
|
+
this._authorizeNtlm(ntlm.config as INtlmAuthorization, headers);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
/**
|
|
741
|
+
* Authorize the request with NTLM
|
|
742
|
+
* @param authData The credentials to use
|
|
743
|
+
* @param headers A headers object where to append headers if needed
|
|
744
|
+
*/
|
|
745
|
+
_authorizeNtlm(authData: INtlmAuthorization, headers: Headers): void {
|
|
746
|
+
const init = { ...authData, url: this.request.url } as INtlmAuthConfig;
|
|
747
|
+
const auth = new NtlmAuth(init);
|
|
748
|
+
if (!this.auth) {
|
|
749
|
+
this.auth = {
|
|
750
|
+
method: 'ntlm',
|
|
751
|
+
state: 0,
|
|
752
|
+
headers: headers.toString(),
|
|
753
|
+
};
|
|
754
|
+
const msg = auth.createMessage1(this.uri.host);
|
|
755
|
+
headers.set('Authorization', `NTLM ${msg.toBase64()}`);
|
|
756
|
+
headers.set('Connection', 'keep-alive');
|
|
757
|
+
} else if (this.auth && this.auth.state === 1) {
|
|
758
|
+
const msg = auth.createMessage3(this.auth.challengeHeader!, this.uri.host);
|
|
759
|
+
this.auth.state = 2;
|
|
760
|
+
headers.set('Authorization', `NTLM ${msg.toBase64()}`);
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
/**
|
|
765
|
+
* Handles the response with NTLM authorization
|
|
766
|
+
*/
|
|
767
|
+
async _handleNtlmResponse(res: http.IncomingMessage): Promise<void> {
|
|
768
|
+
const headers = this.computeResponseHeaders(res);
|
|
769
|
+
const { auth } = this;
|
|
770
|
+
if (auth && auth.state === 0) {
|
|
771
|
+
console.log('Handling 401 2');
|
|
772
|
+
if (headers.has('www-authenticate')) {
|
|
773
|
+
auth.state = 1;
|
|
774
|
+
auth.challengeHeader = headers.get('www-authenticate');
|
|
775
|
+
this._cleanUpRedirect();
|
|
776
|
+
console.log('Preparing message');
|
|
777
|
+
|
|
778
|
+
const message = await this._prepareMessage();
|
|
779
|
+
console.log('The message', message);
|
|
780
|
+
|
|
781
|
+
if (message) {
|
|
782
|
+
console.log('writing the message');
|
|
783
|
+
this.socket?.write(message);
|
|
784
|
+
}
|
|
785
|
+
return;
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
delete this.auth;
|
|
789
|
+
this.emit('loadend');
|
|
790
|
+
this._publishResponse();
|
|
791
|
+
}
|
|
792
|
+
}
|