objective-http 1.3.0 → 1.4.0
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/README.md +10 -19
- package/package.json +1 -1
- package/src/js/bun/Bunttp.js +2 -5
- package/src/js/bun/server/request/InputRequest.js +5 -6
- package/src/js/bun/server/response/OutputResponse.js +1 -25
- package/src/js/client/request/OutputRequest.js +27 -55
- package/src/js/client/response/InputResponse.js +20 -30
- package/src/js/index.js +1 -5
- package/src/js/server/LoggedServer.js +6 -7
- package/src/js/server/Server.js +30 -26
- package/src/js/server/endpoint/Endpoint.js +7 -14
- package/src/js/server/endpoint/Endpoints.js +25 -15
- package/src/js/server/endpoint/index.js +0 -1
- package/src/js/server/request/InputRequest.js +23 -24
- package/src/js/server/request/LoggedInputRequest.js +13 -13
- package/src/js/server/request/index.js +0 -1
- package/src/js/server/response/LoggedOutputResponse.js +0 -4
- package/src/js/server/response/OutputResponse.js +1 -25
- package/src/js/server/response/index.js +0 -1
- package/src/js/server/endpoint/LoggedEndpoint.js +0 -30
- package/src/js/server/request/JsonInputRequest.js +0 -51
- package/src/js/server/response/JsonOutputResponse.js +0 -45
package/README.md
CHANGED
|
@@ -15,17 +15,14 @@ const {
|
|
|
15
15
|
LoggedServer,
|
|
16
16
|
endpoint: {
|
|
17
17
|
Endpoint,
|
|
18
|
-
LoggedEndpoint,
|
|
19
18
|
Endpoints
|
|
20
19
|
},
|
|
21
20
|
request: {
|
|
22
21
|
InputRequest,
|
|
23
|
-
JsonInputRequest,
|
|
24
22
|
LoggedInputRequest,
|
|
25
23
|
},
|
|
26
24
|
response: {
|
|
27
25
|
OutputResponse,
|
|
28
|
-
JsonOutputResponse,
|
|
29
26
|
LoggedOutputResponse
|
|
30
27
|
}
|
|
31
28
|
} = require('objective-http').server;
|
|
@@ -33,13 +30,13 @@ const {
|
|
|
33
30
|
new LoggedServer(
|
|
34
31
|
new Server(
|
|
35
32
|
new Endpoints([
|
|
36
|
-
new
|
|
37
|
-
new
|
|
38
|
-
new
|
|
33
|
+
new MyFirstEndpoint(),
|
|
34
|
+
new MySecondEndpoint(),
|
|
35
|
+
new MyThirdEndpoint()
|
|
39
36
|
]),
|
|
40
37
|
{port: server_port},
|
|
41
|
-
new LoggedInputRequest(new
|
|
42
|
-
new LoggedOutputResponse(new
|
|
38
|
+
new LoggedInputRequest(new InputRequest(), console),
|
|
39
|
+
new LoggedOutputResponse(new OutputResponse(), console),
|
|
43
40
|
createServerFunction
|
|
44
41
|
),
|
|
45
42
|
console
|
|
@@ -139,17 +136,14 @@ const {
|
|
|
139
136
|
LoggedServer,
|
|
140
137
|
endpoint: {
|
|
141
138
|
Endpoint,
|
|
142
|
-
LoggedEndpoint,
|
|
143
139
|
Endpoints
|
|
144
140
|
},
|
|
145
141
|
request: {
|
|
146
142
|
InputRequest,
|
|
147
|
-
JsonInputRequest,
|
|
148
143
|
LoggedInputRequest,
|
|
149
144
|
},
|
|
150
145
|
response: {
|
|
151
146
|
OutputResponse,
|
|
152
|
-
JsonOutputResponse,
|
|
153
147
|
LoggedOutputResponse
|
|
154
148
|
}
|
|
155
149
|
} = require('objective-http').server;
|
|
@@ -157,13 +151,13 @@ const {
|
|
|
157
151
|
new LoggedServer(
|
|
158
152
|
new Server(
|
|
159
153
|
new Endpoints([
|
|
160
|
-
new
|
|
161
|
-
new
|
|
162
|
-
new
|
|
154
|
+
new MyFirstEndpoint(),
|
|
155
|
+
new MySecondEndpoint(),
|
|
156
|
+
new MyThirdEndpoint()
|
|
163
157
|
]),
|
|
164
158
|
{port: server_port},
|
|
165
|
-
new LoggedInputRequest(new
|
|
166
|
-
new LoggedOutputResponse(new
|
|
159
|
+
new LoggedInputRequest(new InputRequest(), console),
|
|
160
|
+
new LoggedOutputResponse(new OutputResponse(), console),
|
|
167
161
|
createServerFunction
|
|
168
162
|
),
|
|
169
163
|
console
|
|
@@ -181,15 +175,12 @@ const {
|
|
|
181
175
|
LoggedServer,
|
|
182
176
|
endpoint: {
|
|
183
177
|
Endpoint,
|
|
184
|
-
LoggedEndpoint,
|
|
185
178
|
Endpoints
|
|
186
179
|
},
|
|
187
180
|
request: {
|
|
188
|
-
JsonInputRequest,
|
|
189
181
|
LoggedInputRequest,
|
|
190
182
|
},
|
|
191
183
|
response: {
|
|
192
|
-
JsonOutputResponse,
|
|
193
184
|
LoggedOutputResponse
|
|
194
185
|
}
|
|
195
186
|
} = require('objective-http').server;
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"objective-http","version":"1.
|
|
1
|
+
{"name":"objective-http","version":"1.4.0","description":"Proxy classes for creating a http server","keywords":["web","web-server","http","http-server","oop"],"author":{"name":"volatilization","email":"volatilization@yandex.ru"},"repository":{"url":"git+https://github.com/volatilization/objective-http.git"},"license":"LGPL-3.0-only","main":"src/js/index.js"}
|
package/src/js/bun/Bunttp.js
CHANGED
|
@@ -12,16 +12,13 @@ module.exports = class Bunttp {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
listen(options, cb) {
|
|
15
|
-
|
|
16
|
-
const server = Bun.serve(config);
|
|
15
|
+
this.#server = Bun.serve({...this.#serverConfig, port: options.port});
|
|
17
16
|
cb();
|
|
18
|
-
return new Bunttp(config, server);
|
|
19
17
|
}
|
|
20
18
|
|
|
21
19
|
close(cb) {
|
|
22
|
-
|
|
20
|
+
this.#server.stop();
|
|
23
21
|
cb();
|
|
24
|
-
return new Bunttp(this.#serverConfig, server);
|
|
25
22
|
}
|
|
26
23
|
|
|
27
24
|
request = fetch;
|
|
@@ -16,8 +16,10 @@ module.exports = class InputRequest {
|
|
|
16
16
|
return new InputRequest(
|
|
17
17
|
this.#inputStream,
|
|
18
18
|
{
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
route: {
|
|
20
|
+
method: this.#inputStream.method,
|
|
21
|
+
path: new URL(this.#inputStream.url).pathname
|
|
22
|
+
},
|
|
21
23
|
query: new URL(this.#inputStream.url).searchParams,
|
|
22
24
|
headers: this.#inputStream.headers,
|
|
23
25
|
body: Buffer.from(await (await this.#inputStream.blob()).arrayBuffer())
|
|
@@ -30,10 +32,7 @@ module.exports = class InputRequest {
|
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
route() {
|
|
33
|
-
return
|
|
34
|
-
method: this.#options.method.toString().toUpperCase(),
|
|
35
|
-
path: this.#options.path.toString().toLowerCase()
|
|
36
|
-
}
|
|
35
|
+
return this.#options.route;
|
|
37
36
|
}
|
|
38
37
|
|
|
39
38
|
query() {
|
|
@@ -7,14 +7,10 @@ module.exports = class OutputResponse {
|
|
|
7
7
|
this.#outputStream = outputStream;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
copy(
|
|
10
|
+
copy(outputStream = this.#outputStream, options = this.#options) {
|
|
11
11
|
return new OutputResponse({...{statusCode: 200, headers: {}}, ...options}, outputStream);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
update(options) {
|
|
15
|
-
return new OutputResponse(this.#mergeOptions(this.#options, options), this.#outputStream);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
14
|
flush() {
|
|
19
15
|
try {
|
|
20
16
|
return new Response(this.#options.body, {
|
|
@@ -26,24 +22,4 @@ module.exports = class OutputResponse {
|
|
|
26
22
|
throw new Error(e.message, {cause: 'INVALID_RESPONSE'});
|
|
27
23
|
}
|
|
28
24
|
}
|
|
29
|
-
|
|
30
|
-
#mergeOptions(existedOptions, newOptions) {
|
|
31
|
-
if (newOptions == null) {
|
|
32
|
-
return existedOptions;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (newOptions.statusCode != null) {
|
|
36
|
-
existedOptions.statusCode = newOptions.statusCode;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (newOptions.body != null) {
|
|
40
|
-
existedOptions.body = newOptions.body;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (newOptions.headers != null) {
|
|
44
|
-
existedOptions.headers = {...existedOptions.headers, ...newOptions.headers};
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return existedOptions;
|
|
48
|
-
}
|
|
49
25
|
}
|
|
@@ -10,72 +10,44 @@ module.exports = class OutputRequest {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
copy(options = this.#options, response = this.#response, http = this.#requestFunction) {
|
|
13
|
-
return new OutputRequest(response, http,
|
|
13
|
+
return new OutputRequest(response, http, {method: 'GET', ...options});
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
this.#
|
|
20
|
-
this.#
|
|
16
|
+
send() {
|
|
17
|
+
return new Promise((resolve, reject) => {
|
|
18
|
+
try {
|
|
19
|
+
const requestOutputStream = this.#requestFunction(
|
|
20
|
+
this.#options.url,
|
|
21
21
|
this.#options,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
async (responseInputStream) => {
|
|
23
|
+
try {
|
|
24
|
+
resolve(await this.#response
|
|
25
|
+
.copy(responseInputStream)
|
|
26
|
+
.flush());
|
|
27
|
+
|
|
28
|
+
} catch (e) {
|
|
29
|
+
reject(new Error(e.message, {cause: 'INVALID_REQUEST'}));
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
requestOutputStream.once('error', e => {
|
|
34
|
+
reject(new Error(e.message, {cause: 'INVALID_REQUEST'}));
|
|
35
|
+
});
|
|
29
36
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
37
|
+
if (this.#needToByWritten(this.#options)) {
|
|
38
|
+
requestOutputStream.write(this.#options.body);
|
|
39
|
+
}
|
|
33
40
|
|
|
34
|
-
|
|
35
|
-
try {
|
|
36
|
-
requestOutputStream.once('error', e => reject(e));
|
|
41
|
+
requestOutputStream.end();
|
|
37
42
|
|
|
38
|
-
|
|
39
|
-
|
|
43
|
+
} catch (e) {
|
|
44
|
+
reject(new Error(e.message, {cause: 'INVALID_REQUEST'}));
|
|
40
45
|
}
|
|
41
|
-
|
|
42
|
-
requestOutputStream.end();
|
|
43
|
-
|
|
44
|
-
} catch (e) {
|
|
45
|
-
reject(e);
|
|
46
|
-
}
|
|
46
|
+
});
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
#needToByWritten(options) {
|
|
50
50
|
return ['POST', 'PUT'].some(method => method === options.method.toString().toUpperCase())
|
|
51
51
|
&& (options.body != null && typeof options.body === 'string');
|
|
52
52
|
}
|
|
53
|
-
|
|
54
|
-
#configureRequestOutputStream(requestFunction, response, options, resolve, reject) {
|
|
55
|
-
if (options.url != null) {
|
|
56
|
-
return requestFunction(
|
|
57
|
-
options.url,
|
|
58
|
-
options,
|
|
59
|
-
async (responseInputStream) => {
|
|
60
|
-
await this.#flushResponseInputStream(responseInputStream, response, resolve, reject);
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return requestFunction(
|
|
65
|
-
options,
|
|
66
|
-
async (responseInputStream) => {
|
|
67
|
-
await this.#flushResponseInputStream(responseInputStream, response, resolve, reject);
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
async #flushResponseInputStream(responseInputStream, response, resolve, reject) {
|
|
72
|
-
try {
|
|
73
|
-
resolve(await response
|
|
74
|
-
.copy(responseInputStream)
|
|
75
|
-
.flush());
|
|
76
|
-
|
|
77
|
-
} catch (e) {
|
|
78
|
-
reject(e);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
53
|
};
|
|
@@ -24,35 +24,25 @@ module.exports = class InputResponse {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
async flush() {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
this.#
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
new
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
statusCode: inputStream.statusCode,
|
|
48
|
-
headers: new Headers(inputStream.headers),
|
|
49
|
-
body: Buffer.concat(chunks)
|
|
50
|
-
}
|
|
51
|
-
)
|
|
52
|
-
));
|
|
53
|
-
|
|
54
|
-
} catch (e) {
|
|
55
|
-
reject(e);
|
|
56
|
-
}
|
|
27
|
+
return await new Promise((resolve, reject) => {
|
|
28
|
+
try {
|
|
29
|
+
this.#inputStream.once('error', (e) => reject(new Error(e.message, {cause: 'INVALID_RESPONSE'})));
|
|
30
|
+
|
|
31
|
+
let chunks = [];
|
|
32
|
+
this.#inputStream.on('data', (chunk) => chunks.push(chunk));
|
|
33
|
+
this.#inputStream.on('end', () => resolve(
|
|
34
|
+
new InputResponse(
|
|
35
|
+
this.#inputStream,
|
|
36
|
+
{
|
|
37
|
+
statusCode: this.#inputStream.statusCode,
|
|
38
|
+
headers: new Headers(this.#inputStream.headers),
|
|
39
|
+
body: Buffer.concat(chunks)
|
|
40
|
+
}
|
|
41
|
+
)
|
|
42
|
+
));
|
|
43
|
+
} catch (e) {
|
|
44
|
+
throw new Error(e.message, {cause: 'INVALID_RESPONSE'});
|
|
45
|
+
}
|
|
46
|
+
});
|
|
57
47
|
}
|
|
58
48
|
};
|
package/src/js/index.js
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
module.exports = {
|
|
2
2
|
server: require('./server'),
|
|
3
3
|
client: require('./client'),
|
|
4
|
-
bun:
|
|
5
|
-
server: {...require('./server'), ...require('./bun').server},
|
|
6
|
-
client: {...require('./client'), ...require('./bun').client},
|
|
7
|
-
bunttp: require('./bun').bunttp
|
|
8
|
-
}
|
|
4
|
+
bun: require('./bun')
|
|
9
5
|
}
|
|
@@ -7,10 +7,14 @@ module.exports = class LoggedServer {
|
|
|
7
7
|
this.#logger = logger;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
options() {
|
|
11
|
+
return this.#origin.options();
|
|
12
|
+
}
|
|
13
|
+
|
|
10
14
|
async start() {
|
|
11
15
|
const server = await this.#origin.start();
|
|
12
16
|
|
|
13
|
-
this.#logger.debug(`HttpServer is running at port: ${
|
|
17
|
+
this.#logger.debug(`HttpServer is running at port: ${this.#origin.options().port}`);
|
|
14
18
|
|
|
15
19
|
return new LoggedServer(server, this.#logger);
|
|
16
20
|
}
|
|
@@ -18,13 +22,8 @@ module.exports = class LoggedServer {
|
|
|
18
22
|
async stop() {
|
|
19
23
|
const server = await this.#origin.stop();
|
|
20
24
|
|
|
21
|
-
this.#logger.debug(`HttpServer at port: ${
|
|
25
|
+
this.#logger.debug(`HttpServer at port: ${this.#origin.options().port} is stopped`);
|
|
22
26
|
|
|
23
27
|
return new LoggedServer(server, this.#logger);
|
|
24
28
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
options() {
|
|
28
|
-
return this.#origin.options();
|
|
29
|
-
}
|
|
30
29
|
}
|
package/src/js/server/Server.js
CHANGED
|
@@ -15,31 +15,39 @@ module.exports = class Server {
|
|
|
15
15
|
this.#server = server;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
options() {
|
|
19
|
+
return this.#options;
|
|
20
|
+
}
|
|
21
|
+
|
|
18
22
|
start() {
|
|
19
23
|
const server = this.#createServerFunction(async (requestStream, responseStream) => {
|
|
20
24
|
try {
|
|
21
|
-
return await
|
|
22
|
-
.copy(
|
|
23
|
-
|
|
24
|
-
.
|
|
25
|
-
|
|
25
|
+
return await this.#response
|
|
26
|
+
.copy(responseStream,
|
|
27
|
+
await this.#endpoints
|
|
28
|
+
.handle(await this.#request
|
|
29
|
+
.copy(requestStream)
|
|
30
|
+
.flush()))
|
|
26
31
|
.flush();
|
|
27
32
|
|
|
28
33
|
} catch (e) {
|
|
29
34
|
if (e.cause === 'INVALID_REQUEST') {
|
|
30
35
|
return this.#response
|
|
31
|
-
.copy(
|
|
32
|
-
statusCode: 400,
|
|
33
|
-
|
|
34
|
-
|
|
36
|
+
.copy(responseStream,
|
|
37
|
+
{statusCode: 400, body: e.message})
|
|
38
|
+
.flush();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (e.cause === 'HANDLER_NOT_FOUND') {
|
|
42
|
+
return this.#response
|
|
43
|
+
.copy(responseStream,
|
|
44
|
+
{statusCode: 501, body: e.message})
|
|
35
45
|
.flush();
|
|
36
46
|
}
|
|
37
47
|
|
|
38
48
|
return this.#response
|
|
39
|
-
.copy(
|
|
40
|
-
statusCode: 500,
|
|
41
|
-
body: 'Unexpected server error.'
|
|
42
|
-
}, responseStream)
|
|
49
|
+
.copy(responseStream,
|
|
50
|
+
{statusCode: 500, body: 'Unexpected server error.'})
|
|
43
51
|
.flush();
|
|
44
52
|
}
|
|
45
53
|
});
|
|
@@ -47,21 +55,21 @@ module.exports = class Server {
|
|
|
47
55
|
return new Promise(resolve => {
|
|
48
56
|
server.listen(
|
|
49
57
|
this.#options,
|
|
50
|
-
() =>
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
server));
|
|
58
|
-
}
|
|
58
|
+
() => resolve(new Server(
|
|
59
|
+
this.#endpoints,
|
|
60
|
+
this.#options,
|
|
61
|
+
this.#request,
|
|
62
|
+
this.#response,
|
|
63
|
+
this.#createServerFunction,
|
|
64
|
+
server))
|
|
59
65
|
);
|
|
60
66
|
});
|
|
61
67
|
}
|
|
62
68
|
|
|
63
69
|
stop() {
|
|
64
70
|
return new Promise(resolve => {
|
|
71
|
+
console.log('stop ', this.#server);
|
|
72
|
+
|
|
65
73
|
this.#server.close(
|
|
66
74
|
() => resolve(new Server(
|
|
67
75
|
this.#endpoints,
|
|
@@ -72,8 +80,4 @@ module.exports = class Server {
|
|
|
72
80
|
);
|
|
73
81
|
});
|
|
74
82
|
}
|
|
75
|
-
|
|
76
|
-
options() {
|
|
77
|
-
return this.#options;
|
|
78
|
-
}
|
|
79
83
|
};
|
|
@@ -1,24 +1,17 @@
|
|
|
1
1
|
module.exports = class Endpoint {
|
|
2
|
-
#
|
|
3
|
-
#path;
|
|
2
|
+
#route;
|
|
4
3
|
|
|
5
|
-
constructor(
|
|
6
|
-
this.#
|
|
7
|
-
this.#path = path;
|
|
4
|
+
constructor(route) {
|
|
5
|
+
this.#route = route;
|
|
8
6
|
}
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
return
|
|
8
|
+
route() {
|
|
9
|
+
return this.#route;
|
|
12
10
|
}
|
|
13
11
|
|
|
14
|
-
|
|
12
|
+
async handle() {
|
|
15
13
|
return {
|
|
16
|
-
|
|
17
|
-
path: this.#path.toString().toLowerCase()
|
|
14
|
+
statusCode: 200
|
|
18
15
|
};
|
|
19
16
|
}
|
|
20
|
-
|
|
21
|
-
async handle(request) {
|
|
22
|
-
return {};
|
|
23
|
-
}
|
|
24
17
|
}
|
|
@@ -1,26 +1,36 @@
|
|
|
1
1
|
module.exports = class Endpoints {
|
|
2
|
-
#
|
|
2
|
+
#map;
|
|
3
3
|
|
|
4
|
-
constructor(collection = []) {
|
|
5
|
-
this.#
|
|
4
|
+
constructor(collection = [], map = new Map()) {
|
|
5
|
+
this.#map = map;
|
|
6
|
+
collection.forEach((endpoint) => {
|
|
7
|
+
if (!this.#map.has(endpoint.route().path.toString().toLowerCase())) {
|
|
8
|
+
this.#map.set(endpoint.route().path.toString().toLowerCase(), new Map());
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
this.#map
|
|
12
|
+
.get(endpoint.route().path.toString().toLowerCase())
|
|
13
|
+
.set(endpoint.route().method.toString().toUpperCase(),
|
|
14
|
+
endpoint);
|
|
15
|
+
});
|
|
6
16
|
}
|
|
7
17
|
|
|
8
|
-
copy(collection = this.#
|
|
9
|
-
return new Endpoints(collection);
|
|
18
|
+
copy(collection, map = this.#map) {
|
|
19
|
+
return new Endpoints(collection, map);
|
|
10
20
|
}
|
|
11
21
|
|
|
12
22
|
async handle(request) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
statusCode: 501,
|
|
20
|
-
body: 'There are no handler for request.'
|
|
21
|
-
}
|
|
23
|
+
if (!this.#map.has(request.route().path.toString().toLowerCase())
|
|
24
|
+
|| !this.#map
|
|
25
|
+
.get(request.route().path.toString().toLowerCase())
|
|
26
|
+
.has(request.route().method.toString().toUpperCase())
|
|
27
|
+
) {
|
|
28
|
+
throw new Error('There are no handler for request.', {cause: 'HANDLER_NOT_FOUND'});
|
|
22
29
|
}
|
|
23
30
|
|
|
24
|
-
return await
|
|
31
|
+
return await this.#map
|
|
32
|
+
.get(request.route().path.toString().toLowerCase())
|
|
33
|
+
.get(request.route().method.toString().toUpperCase())
|
|
34
|
+
.handle(request);
|
|
25
35
|
}
|
|
26
36
|
}
|
|
@@ -11,6 +11,22 @@ module.exports = class InputRequest {
|
|
|
11
11
|
return new InputRequest(inputStream, options);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
route() {
|
|
15
|
+
return this.#options.route;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
query() {
|
|
19
|
+
return this.#options.query;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
body() {
|
|
23
|
+
return this.#options.body;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
headers() {
|
|
27
|
+
return this.#options.headers;
|
|
28
|
+
}
|
|
29
|
+
|
|
14
30
|
flush() {
|
|
15
31
|
return new Promise((resolve, reject) => {
|
|
16
32
|
try {
|
|
@@ -23,36 +39,19 @@ module.exports = class InputRequest {
|
|
|
23
39
|
this.#inputStream.on('end', () => resolve(new InputRequest(
|
|
24
40
|
this.#inputStream,
|
|
25
41
|
{
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
42
|
+
route: {
|
|
43
|
+
method: this.#inputStream.method,
|
|
44
|
+
path: new URL(this.#inputStream.url, 'http://url').pathname
|
|
45
|
+
},
|
|
46
|
+
query: new URL(this.#inputStream.url, 'http://url').searchParams,
|
|
29
47
|
headers: new Headers(this.#inputStream.headers),
|
|
30
|
-
body: Buffer.concat(chunks)
|
|
48
|
+
body: Buffer.concat(chunks),
|
|
31
49
|
}
|
|
32
50
|
)));
|
|
33
51
|
|
|
34
52
|
} catch (e) {
|
|
35
|
-
|
|
53
|
+
reject(new Error(e.message, {cause: 'INVALID_REQUEST'}));
|
|
36
54
|
}
|
|
37
55
|
});
|
|
38
56
|
}
|
|
39
|
-
|
|
40
|
-
route() {
|
|
41
|
-
return {
|
|
42
|
-
method: this.#options.method.toString().toUpperCase(),
|
|
43
|
-
path: this.#options.path.toString().toLowerCase()
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
query() {
|
|
48
|
-
return this.#options.query;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
body() {
|
|
52
|
-
return this.#options.body;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
headers() {
|
|
56
|
-
return this.#options.headers;
|
|
57
|
-
}
|
|
58
57
|
};
|
|
@@ -13,19 +13,6 @@ module.exports = class LoggedInputRequest {
|
|
|
13
13
|
return new LoggedInputRequest(origin, logger, inputStream);
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
async flush() {
|
|
17
|
-
this.#logger.debug(`HttpRequest: [${this.#inputStream.method}] ${this.#inputStream.url} ${JSON.stringify(this.#inputStream.headers)}`);
|
|
18
|
-
|
|
19
|
-
try {
|
|
20
|
-
return new LoggedInputRequest(await this.#origin.flush(), this.#logger);
|
|
21
|
-
|
|
22
|
-
} catch (e) {
|
|
23
|
-
this.#logger.error(`HttpRequest: [${this.#inputStream.method}] ${this.#inputStream.url} error: ${e.message}`, e);
|
|
24
|
-
|
|
25
|
-
throw e;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
16
|
route() {
|
|
30
17
|
return this.#origin.route();
|
|
31
18
|
}
|
|
@@ -41,4 +28,17 @@ module.exports = class LoggedInputRequest {
|
|
|
41
28
|
headers() {
|
|
42
29
|
return this.#origin.headers();
|
|
43
30
|
}
|
|
31
|
+
|
|
32
|
+
async flush() {
|
|
33
|
+
this.#logger.debug(`HttpRequest: [${this.#inputStream.method}] ${this.#inputStream.url} ${JSON.stringify(this.#inputStream.headers)}`);
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
return new LoggedInputRequest(await this.#origin.flush(), this.#logger);
|
|
37
|
+
|
|
38
|
+
} catch (e) {
|
|
39
|
+
this.#logger.error(`HttpRequest: [${this.#inputStream.method}] ${this.#inputStream.url} error: ${e.message}`, e);
|
|
40
|
+
|
|
41
|
+
throw e;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
44
|
}
|
|
@@ -11,10 +11,6 @@ module.exports = class LoggedOutputResponse {
|
|
|
11
11
|
return new LoggedOutputResponse(origin, logger);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
update(options) {
|
|
15
|
-
return new LoggedOutputResponse(this.#origin.update(options), this.#logger);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
14
|
flush() {
|
|
19
15
|
const outputStream = this.#loggedFlush();
|
|
20
16
|
|
|
@@ -7,14 +7,10 @@ module.exports = class OutputResponse {
|
|
|
7
7
|
this.#outputStream = outputStream;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
copy(
|
|
10
|
+
copy(outputStream = this.#outputStream, options = this.#options) {
|
|
11
11
|
return new OutputResponse({...{statusCode: 200, headers: {}}, ...options}, outputStream);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
update(options) {
|
|
15
|
-
return new OutputResponse(this.#mergeOptions(this.#options, options), this.#outputStream);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
14
|
flush() {
|
|
19
15
|
try {
|
|
20
16
|
this.#outputStream.writeHead(this.#options.statusCode, this.#options.headers)
|
|
@@ -29,24 +25,4 @@ module.exports = class OutputResponse {
|
|
|
29
25
|
this.#outputStream.end();
|
|
30
26
|
}
|
|
31
27
|
}
|
|
32
|
-
|
|
33
|
-
#mergeOptions(existedOptions, newOptions) {
|
|
34
|
-
if (newOptions == null) {
|
|
35
|
-
return existedOptions;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (newOptions.statusCode != null) {
|
|
39
|
-
existedOptions.statusCode = newOptions.statusCode;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (newOptions.body != null) {
|
|
43
|
-
existedOptions.body = newOptions.body;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (newOptions.headers != null) {
|
|
47
|
-
existedOptions.headers = {...existedOptions.headers, ...newOptions.headers};
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return existedOptions;
|
|
51
|
-
}
|
|
52
28
|
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
module.exports = class LoggedEndpoint {
|
|
2
|
-
#origin;
|
|
3
|
-
#logger;
|
|
4
|
-
|
|
5
|
-
constructor(origin, logger) {
|
|
6
|
-
this.#origin = origin;
|
|
7
|
-
this.#logger = logger;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
copy(method, path, logger = this.#logger, origin = this.#origin.copy(method, path)) {
|
|
11
|
-
return new LoggedEndpoint(origin, logger);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
route() {
|
|
15
|
-
return this.#origin.route();
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
async handle(request) {
|
|
19
|
-
this.#logger.debug(`HttpEndpoint's handling [${request.route().method}] ${request.route().path}`);
|
|
20
|
-
|
|
21
|
-
try {
|
|
22
|
-
return await this.#origin.handle(request);
|
|
23
|
-
|
|
24
|
-
} catch (e) {
|
|
25
|
-
this.#logger.error(`HttpEndpoint's handling [${request.route().method}] ${request.route().path} error: ${e.message}`, e);
|
|
26
|
-
|
|
27
|
-
throw e;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
module.exports = class JsonInputRequest {
|
|
2
|
-
#origin;
|
|
3
|
-
#inputStream;
|
|
4
|
-
|
|
5
|
-
constructor(origin, inputStream) {
|
|
6
|
-
this.#origin = origin;
|
|
7
|
-
this.#inputStream = inputStream;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
copy(inputStream, options, origin = this.#origin.copy(inputStream, options)) {
|
|
11
|
-
return new JsonInputRequest(origin, inputStream);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
async flush() {
|
|
15
|
-
if (this.#useChunkMethod(this.#inputStream.method) && !this.#validHeaders(new Headers(this.#inputStream.headers))) {
|
|
16
|
-
throw new Error('Wrong content-type. Only application/json accepted.', {cause: 'INVALID_REQUEST'});
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return new JsonInputRequest(await this.#origin.flush(), this.#inputStream);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
route() {
|
|
23
|
-
return this.#origin.route();
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
query() {
|
|
27
|
-
return this.#origin.query();
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
body() {
|
|
31
|
-
try {
|
|
32
|
-
return JSON.parse(this.#origin.body().toString());
|
|
33
|
-
|
|
34
|
-
} catch (e) {
|
|
35
|
-
throw new Error('Wrong body format. Only JSON accepted.', {cause: 'INVALID_REQUEST'});
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
headers() {
|
|
40
|
-
return this.#origin.headers();
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
#useChunkMethod(requestMethod) {
|
|
44
|
-
return ['POST', 'PUT'].some(method => method === requestMethod.toString().toUpperCase())
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
#validHeaders(requestHeaders) {
|
|
48
|
-
return new Headers(requestHeaders).has('content-type')
|
|
49
|
-
&& new RegExp('^application\/json').test(new Headers(requestHeaders).get('content-type'));
|
|
50
|
-
}
|
|
51
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
module.exports = class JsonOutputResponse {
|
|
2
|
-
#origin;
|
|
3
|
-
#options;
|
|
4
|
-
|
|
5
|
-
constructor(origin, options) {
|
|
6
|
-
this.#origin = origin;
|
|
7
|
-
this.#options = options;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
copy(options, outputStream, origin = this.#origin.copy(options, outputStream)) {
|
|
11
|
-
return new JsonOutputResponse(origin, options);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
update(options) {
|
|
15
|
-
return new JsonOutputResponse(this.#origin.update(options));
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
flush() {
|
|
19
|
-
const body = this.#options.body;
|
|
20
|
-
|
|
21
|
-
if (body == null) {
|
|
22
|
-
return this.#origin.flush();
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if (typeof body === 'string') {
|
|
26
|
-
try {
|
|
27
|
-
JSON.parse(body);
|
|
28
|
-
|
|
29
|
-
return this.#origin
|
|
30
|
-
.update({headers: {'Content-Type': 'application/json; charset=utf-8'}})
|
|
31
|
-
.flush();
|
|
32
|
-
|
|
33
|
-
} catch (e) {
|
|
34
|
-
return this.#origin.flush();
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return this.#origin
|
|
39
|
-
.update({
|
|
40
|
-
headers: {'Content-Type': 'application/json; charset=utf-8'},
|
|
41
|
-
body: JSON.stringify(body)
|
|
42
|
-
})
|
|
43
|
-
.flush();
|
|
44
|
-
}
|
|
45
|
-
};
|