@opra/http 1.21.0 → 1.22.1

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.
Files changed (70) hide show
  1. package/{esm/express-adapter.js → express-adapter.js} +2 -1
  2. package/{esm/http-adapter.js → http-adapter.js} +5 -1
  3. package/{esm/http-context.js → http-context.js} +10 -1
  4. package/{esm/http-handler.js → http-handler.js} +3 -0
  5. package/{esm/impl → impl}/http-incoming.host.js +1 -0
  6. package/{esm/impl → impl}/multipart-reader.js +10 -5
  7. package/{esm/impl → impl}/node-incoming-message.host.js +15 -4
  8. package/{esm/impl → impl}/node-outgoing-message.host.js +7 -2
  9. package/package.json +14 -31
  10. package/{esm/utils → utils}/body-reader.js +10 -2
  11. package/cjs/express-adapter.js +0 -134
  12. package/cjs/http-adapter.js +0 -25
  13. package/cjs/http-context.js +0 -114
  14. package/cjs/http-handler.js +0 -668
  15. package/cjs/impl/http-incoming.host.js +0 -112
  16. package/cjs/impl/http-outgoing.host.js +0 -207
  17. package/cjs/impl/multipart-reader.js +0 -209
  18. package/cjs/impl/node-incoming-message.host.js +0 -115
  19. package/cjs/impl/node-outgoing-message.host.js +0 -201
  20. package/cjs/index.js +0 -27
  21. package/cjs/interfaces/http-incoming.interface.js +0 -25
  22. package/cjs/interfaces/http-outgoing.interface.js +0 -22
  23. package/cjs/interfaces/node-incoming-message.interface.js +0 -65
  24. package/cjs/interfaces/node-outgoing-message.interface.js +0 -15
  25. package/cjs/package.json +0 -3
  26. package/cjs/type-guards.js +0 -27
  27. package/cjs/utils/body-reader.js +0 -227
  28. package/cjs/utils/common.js +0 -67
  29. package/cjs/utils/concat-readable.js +0 -19
  30. package/cjs/utils/convert-to-headers.js +0 -64
  31. package/cjs/utils/convert-to-raw-headers.js +0 -25
  32. package/cjs/utils/match-known-fields.js +0 -49
  33. package/cjs/utils/wrap-exception.js +0 -33
  34. package/esm/package.json +0 -3
  35. package/types/index.d.cts +0 -22
  36. /package/{types/express-adapter.d.ts → express-adapter.d.ts} +0 -0
  37. /package/{types/http-adapter.d.ts → http-adapter.d.ts} +0 -0
  38. /package/{types/http-context.d.ts → http-context.d.ts} +0 -0
  39. /package/{types/http-handler.d.ts → http-handler.d.ts} +0 -0
  40. /package/{types/impl → impl}/http-incoming.host.d.ts +0 -0
  41. /package/{types/impl → impl}/http-outgoing.host.d.ts +0 -0
  42. /package/{esm/impl → impl}/http-outgoing.host.js +0 -0
  43. /package/{types/impl → impl}/multipart-reader.d.ts +0 -0
  44. /package/{types/impl → impl}/node-incoming-message.host.d.ts +0 -0
  45. /package/{types/impl → impl}/node-outgoing-message.host.d.ts +0 -0
  46. /package/{types/index.d.ts → index.d.ts} +0 -0
  47. /package/{esm/index.js → index.js} +0 -0
  48. /package/{types/interfaces → interfaces}/http-incoming.interface.d.ts +0 -0
  49. /package/{esm/interfaces → interfaces}/http-incoming.interface.js +0 -0
  50. /package/{types/interfaces → interfaces}/http-outgoing.interface.d.ts +0 -0
  51. /package/{esm/interfaces → interfaces}/http-outgoing.interface.js +0 -0
  52. /package/{types/interfaces → interfaces}/node-incoming-message.interface.d.ts +0 -0
  53. /package/{esm/interfaces → interfaces}/node-incoming-message.interface.js +0 -0
  54. /package/{types/interfaces → interfaces}/node-outgoing-message.interface.d.ts +0 -0
  55. /package/{esm/interfaces → interfaces}/node-outgoing-message.interface.js +0 -0
  56. /package/{types/type-guards.d.ts → type-guards.d.ts} +0 -0
  57. /package/{esm/type-guards.js → type-guards.js} +0 -0
  58. /package/{types/utils → utils}/body-reader.d.ts +0 -0
  59. /package/{types/utils → utils}/common.d.ts +0 -0
  60. /package/{esm/utils → utils}/common.js +0 -0
  61. /package/{types/utils → utils}/concat-readable.d.ts +0 -0
  62. /package/{esm/utils → utils}/concat-readable.js +0 -0
  63. /package/{types/utils → utils}/convert-to-headers.d.ts +0 -0
  64. /package/{esm/utils → utils}/convert-to-headers.js +0 -0
  65. /package/{types/utils → utils}/convert-to-raw-headers.d.ts +0 -0
  66. /package/{esm/utils → utils}/convert-to-raw-headers.js +0 -0
  67. /package/{types/utils → utils}/match-known-fields.d.ts +0 -0
  68. /package/{esm/utils → utils}/match-known-fields.js +0 -0
  69. /package/{types/utils → utils}/wrap-exception.d.ts +0 -0
  70. /package/{esm/utils → utils}/wrap-exception.js +0 -0
@@ -1,201 +0,0 @@
1
- "use strict";
2
- /*
3
- This file contains code blocks from open source NodeJs project
4
- https://github.com/nodejs/
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.NodeOutgoingMessageHost = exports.kOutTrailers = exports.kOutHeaders = void 0;
8
- const stream_1 = require("stream");
9
- const common_js_1 = require("../utils/common.js");
10
- exports.kOutHeaders = Symbol.for('kOutHeaders');
11
- exports.kOutTrailers = Symbol.for('kOutTrailers');
12
- // noinspection JSUnusedLocalSymbols
13
- /**
14
- *
15
- * @class NodeOutgoingMessageHost
16
- */
17
- class NodeOutgoingMessageHost extends stream_1.Duplex {
18
- constructor(init) {
19
- super();
20
- this._headersSent = false;
21
- this.finished = false;
22
- if (init) {
23
- this.req = init.req;
24
- this.statusCode = init?.statusCode || 0;
25
- this.statusMessage = init?.statusMessage || '';
26
- this.chunkedEncoding = !!init?.chunkedEncoding;
27
- this.sendDate = !!init?.sendDate;
28
- this.strictContentLength = !!init?.strictContentLength;
29
- if (init.headers)
30
- this.setHeaders(Array.isArray(init.headers)
31
- ? new Map([init.headers])
32
- : init.headers);
33
- this.body = init.body;
34
- }
35
- }
36
- get httpVersionMajor() {
37
- return this.req?.httpVersionMajor || this._httpVersionMajor;
38
- }
39
- get httpVersionMinor() {
40
- return this.req?.httpVersionMinor || this._httpVersionMinor;
41
- }
42
- get headersSent() {
43
- return this._headersSent;
44
- }
45
- appendHeader(name, value) {
46
- if (this.headersSent)
47
- throw new Error(`Cannot set headers after they are sent to the client`);
48
- (0, common_js_1.validateHeaderName)(name);
49
- (0, common_js_1.validateHeaderValue)(name, value);
50
- const field = name.toLowerCase();
51
- const headers = this[exports.kOutHeaders];
52
- if (headers == null || !headers[field]) {
53
- return this.setHeader(name, value);
54
- }
55
- // Prepare the field for appending, if required
56
- if (!Array.isArray(headers[field][1])) {
57
- headers[field][1] = [headers[field][1]];
58
- }
59
- const existingValues = headers[field][1];
60
- if (Array.isArray(value)) {
61
- for (let i = 0, length = value.length; i < length; i++) {
62
- existingValues.push(value[i]);
63
- }
64
- }
65
- else {
66
- existingValues.push(value);
67
- }
68
- return this;
69
- }
70
- addTrailers(headers) {
71
- if (headers && typeof headers === 'object') {
72
- const entries = typeof headers.entries === 'function'
73
- ? headers.entries()
74
- : Object.entries(headers);
75
- let trailers = this[exports.kOutTrailers];
76
- if (trailers == null)
77
- this[exports.kOutTrailers] = trailers = { __proto__: null };
78
- for (const [name, value] of entries) {
79
- (0, common_js_1.validateHeaderName)(name);
80
- (0, common_js_1.validateHeaderValue)(name, value);
81
- trailers[String(name).toLowerCase()] = [String(name), value];
82
- }
83
- return;
84
- }
85
- throw new TypeError('Invalid "headers" argument. Value must be an object or raw headers array');
86
- }
87
- flushHeaders() {
88
- // nothing to do
89
- }
90
- setHeader(name, value) {
91
- if (this.headersSent)
92
- throw new Error(`Cannot set headers after they are sent to the client`);
93
- (0, common_js_1.validateHeaderName)(name);
94
- (0, common_js_1.validateHeaderValue)(name, value);
95
- let headers = this[exports.kOutHeaders];
96
- if (headers == null)
97
- this[exports.kOutHeaders] = headers = { __proto__: null };
98
- headers[name.toLowerCase()] = [name, value];
99
- return this;
100
- }
101
- setHeaders(headers) {
102
- if (this.headersSent)
103
- throw new Error(`Cannot set headers after they are sent to the client`);
104
- if (headers && typeof headers === 'object' && !Array.isArray(headers)) {
105
- const entries = typeof headers.entries === 'function'
106
- ? headers.entries()
107
- : Object.entries(headers);
108
- for (const entry of entries) {
109
- this.setHeader(entry[0], entry[1]);
110
- }
111
- return this;
112
- }
113
- throw new TypeError('Invalid "headers" argument. Value must be an instance of "Headers" or "Map"');
114
- }
115
- getHeader(name) {
116
- (0, common_js_1.validateString)(name);
117
- const headers = this[exports.kOutHeaders];
118
- if (headers == null)
119
- return;
120
- const entry = headers[name.toLowerCase()];
121
- return entry && entry[1];
122
- }
123
- getHeaderNames() {
124
- return this[exports.kOutHeaders] != null ? Object.keys(this[exports.kOutHeaders]) : [];
125
- }
126
- getRawHeaderNames() {
127
- const headersMap = this[exports.kOutHeaders];
128
- if (!headersMap)
129
- return [];
130
- const values = Object.values(headersMap);
131
- const headers = Array(values.length);
132
- for (let i = 0, l = values.length; i < l; i++) {
133
- headers[i] = values[i][0];
134
- }
135
- return headers;
136
- }
137
- getHeaders() {
138
- const headers = this[exports.kOutHeaders];
139
- // @ts-ignore
140
- const ret = { __proto__: null };
141
- if (headers) {
142
- const keys = Object.keys(headers);
143
- let key;
144
- let val;
145
- for (let i = 0; i < keys.length; ++i) {
146
- key = keys[i];
147
- val = headers[key][1];
148
- ret[key] = val;
149
- }
150
- }
151
- return ret;
152
- }
153
- hasHeader(name) {
154
- (0, common_js_1.validateString)(name);
155
- return this[exports.kOutHeaders] != null && !!this[exports.kOutHeaders][name.toLowerCase()];
156
- }
157
- removeHeader(name) {
158
- (0, common_js_1.validateString)(name);
159
- if (this.headersSent)
160
- throw new Error(`Cannot remove headers after they are sent to the client`);
161
- const key = name.toLowerCase();
162
- // switch (key) {
163
- // case 'connection':
164
- // this._removedConnection = true;
165
- // break;
166
- // case 'content-length':
167
- // this._removedContLen = true;
168
- // break;
169
- // case 'transfer-encoding':
170
- // this._removedTE = true;
171
- // break;
172
- // case 'date':
173
- // this.sendDate = false;
174
- // break;
175
- // }
176
- if (this[exports.kOutHeaders] != null) {
177
- delete this[exports.kOutHeaders][key];
178
- }
179
- }
180
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
181
- end(arg0, arg1, arg2) {
182
- // let cb: (() => void) | undefined;
183
- // let chunk: any;
184
- // let encoding: BufferEncoding | undefined;
185
- //
186
- // if (typeof arg0 === 'function')
187
- // cb = arg0;
188
- // else {
189
- // chunk = arg0;
190
- // if (typeof arg1 === 'function')
191
- // cb = arg1;
192
- // else {
193
- // encoding = arg1;
194
- // cb = arg2;
195
- // }
196
- // }
197
- //
198
- return this;
199
- }
200
- }
201
- exports.NodeOutgoingMessageHost = NodeOutgoingMessageHost;
package/cjs/index.js DELETED
@@ -1,27 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.classes = void 0;
4
- const tslib_1 = require("tslib");
5
- require("reflect-metadata");
6
- const HttpIncomingHost_ = tslib_1.__importStar(require("./impl/http-incoming.host.js"));
7
- const HttpOutgoingHost_ = tslib_1.__importStar(require("./impl/http-outgoing.host.js"));
8
- const NodeIncomingMessageHost_ = tslib_1.__importStar(require("./impl/node-incoming-message.host.js"));
9
- const NodeOutgoingMessageHost_ = tslib_1.__importStar(require("./impl/node-outgoing-message.host.js"));
10
- tslib_1.__exportStar(require("./express-adapter.js"), exports);
11
- tslib_1.__exportStar(require("./http-adapter.js"), exports);
12
- tslib_1.__exportStar(require("./http-context.js"), exports);
13
- tslib_1.__exportStar(require("./http-handler.js"), exports);
14
- tslib_1.__exportStar(require("./impl/multipart-reader.js"), exports);
15
- tslib_1.__exportStar(require("./interfaces/http-incoming.interface.js"), exports);
16
- tslib_1.__exportStar(require("./interfaces/http-outgoing.interface.js"), exports);
17
- tslib_1.__exportStar(require("./interfaces/node-incoming-message.interface.js"), exports);
18
- tslib_1.__exportStar(require("./interfaces/node-outgoing-message.interface.js"), exports);
19
- tslib_1.__exportStar(require("./type-guards.js"), exports);
20
- tslib_1.__exportStar(require("./utils/wrap-exception.js"), exports);
21
- var classes;
22
- (function (classes) {
23
- classes.HttpIncomingHost = HttpIncomingHost_.HttpIncomingHost;
24
- classes.HttpOutgoingHost = HttpOutgoingHost_.HttpOutgoingHost;
25
- classes.NodeIncomingMessageHost = NodeIncomingMessageHost_.NodeIncomingMessageHost;
26
- classes.NodeOutgoingMessageHost = NodeOutgoingMessageHost_.NodeOutgoingMessageHost;
27
- })(classes || (exports.classes = classes = {}));
@@ -1,25 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HttpIncoming = void 0;
4
- const common_1 = require("@opra/common");
5
- const http_incoming_host_js_1 = require("../impl/http-incoming.host.js");
6
- const type_guards_js_1 = require("../type-guards.js");
7
- const node_incoming_message_interface_js_1 = require("./node-incoming-message.interface.js");
8
- /**
9
- * @namespace HttpIncoming
10
- */
11
- var HttpIncoming;
12
- (function (HttpIncoming) {
13
- function from(instance) {
14
- if ((0, type_guards_js_1.isHttpIncoming)(instance))
15
- return instance;
16
- if (!(0, type_guards_js_1.isNodeIncomingMessage)(instance))
17
- instance = node_incoming_message_interface_js_1.NodeIncomingMessage.from(instance);
18
- (0, common_1.mergePrototype)(instance, http_incoming_host_js_1.HttpIncomingHost.prototype);
19
- const req = instance;
20
- req.baseUrl = req.baseUrl || '';
21
- req.params = req.params || {};
22
- return req;
23
- }
24
- HttpIncoming.from = from;
25
- })(HttpIncoming || (exports.HttpIncoming = HttpIncoming = {}));
@@ -1,22 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HttpOutgoing = void 0;
4
- const common_1 = require("@opra/common");
5
- const http_outgoing_host_js_1 = require("../impl/http-outgoing.host.js");
6
- const type_guards_js_1 = require("../type-guards.js");
7
- const node_outgoing_message_interface_js_1 = require("./node-outgoing-message.interface.js");
8
- /**
9
- * @namespace HttpIncoming
10
- */
11
- var HttpOutgoing;
12
- (function (HttpOutgoing) {
13
- function from(instance) {
14
- if ((0, type_guards_js_1.isHttpOutgoing)(instance))
15
- return instance;
16
- if (!(0, type_guards_js_1.isNodeOutgoingMessage)(instance))
17
- instance = node_outgoing_message_interface_js_1.NodeOutgoingMessage.from(instance);
18
- (0, common_1.mergePrototype)(instance, http_outgoing_host_js_1.HttpOutgoingHost.prototype);
19
- return instance;
20
- }
21
- HttpOutgoing.from = from;
22
- })(HttpOutgoing || (exports.HttpOutgoing = HttpOutgoing = {}));
@@ -1,65 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.NodeIncomingMessage = void 0;
4
- const http_parser_1 = require("@browsery/http-parser");
5
- const objects_1 = require("@jsopen/objects");
6
- const stream_1 = require("stream");
7
- const node_incoming_message_host_js_1 = require("../impl/node-incoming-message.host.js");
8
- const concat_readable_js_1 = require("../utils/concat-readable.js");
9
- /**
10
- *
11
- * @namespace NodeIncomingMessage
12
- */
13
- var NodeIncomingMessage;
14
- (function (NodeIncomingMessage) {
15
- /**
16
- * Creates a new NodeIncomingMessage from given argument
17
- * @param iterable
18
- */
19
- function from(iterable) {
20
- if (typeof iterable === 'object' &&
21
- !((0, objects_1.isIterable)(iterable) || (0, objects_1.isAsyncIterable)(iterable))) {
22
- return new node_incoming_message_host_js_1.NodeIncomingMessageHost(iterable);
23
- }
24
- const msg = new node_incoming_message_host_js_1.NodeIncomingMessageHost();
25
- const parser = (msg[node_incoming_message_host_js_1.kHttpParser] = new http_parser_1.HTTPParser(http_parser_1.HTTPParser.REQUEST));
26
- let bodyChunks;
27
- parser[http_parser_1.HTTPParser.kOnHeadersComplete] = (info) => {
28
- msg.httpVersionMajor = info.versionMajor;
29
- msg.httpVersionMinor = info.versionMinor;
30
- msg.rawHeaders = info.headers;
31
- msg.method = http_parser_1.HTTPParser.methods[info.method];
32
- msg.url = info.url;
33
- msg.emit('headers');
34
- };
35
- parser[http_parser_1.HTTPParser.kOnHeaders] = (trailers) => {
36
- msg.rawTrailers = trailers;
37
- };
38
- parser[http_parser_1.HTTPParser.kOnBody] = (chunk, offset, length) => {
39
- bodyChunks = bodyChunks || [];
40
- bodyChunks.push(chunk.subarray(offset, offset + length));
41
- };
42
- const readable = (0, concat_readable_js_1.concatReadable)(stream_1.Readable.from(iterable), stream_1.Readable.from(node_incoming_message_host_js_1.CRLF));
43
- msg.once('finish', () => {
44
- parser.finish();
45
- msg.complete = true;
46
- if (bodyChunks)
47
- msg.body = Buffer.concat(bodyChunks);
48
- });
49
- readable.pipe(msg);
50
- return msg;
51
- }
52
- NodeIncomingMessage.from = from;
53
- /**
54
- * Creates a new NodeIncomingMessage from given argument
55
- * @param iterable
56
- */
57
- async function fromAsync(iterable) {
58
- return new Promise((resolve, reject) => {
59
- const msg = from(iterable);
60
- msg.once('finish', () => resolve(msg));
61
- msg.once('error', error => reject(error));
62
- });
63
- }
64
- NodeIncomingMessage.fromAsync = fromAsync;
65
- })(NodeIncomingMessage || (exports.NodeIncomingMessage = NodeIncomingMessage = {}));
@@ -1,15 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.NodeOutgoingMessage = void 0;
4
- const node_outgoing_message_host_js_1 = require("../impl/node-outgoing-message.host.js");
5
- /**
6
- *
7
- * @namespace NodeOutgoingMessage
8
- */
9
- var NodeOutgoingMessage;
10
- (function (NodeOutgoingMessage) {
11
- function from(init) {
12
- return new node_outgoing_message_host_js_1.NodeOutgoingMessageHost(init);
13
- }
14
- NodeOutgoingMessage.from = from;
15
- })(NodeOutgoingMessage || (exports.NodeOutgoingMessage = NodeOutgoingMessage = {}));
package/cjs/package.json DELETED
@@ -1,3 +0,0 @@
1
- {
2
- "type": "commonjs"
3
- }
@@ -1,27 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isNodeIncomingMessage = isNodeIncomingMessage;
4
- exports.isHttpIncoming = isHttpIncoming;
5
- exports.isNodeOutgoingMessage = isNodeOutgoingMessage;
6
- exports.isHttpOutgoing = isHttpOutgoing;
7
- const common_1 = require("@opra/common");
8
- function isNodeIncomingMessage(v) {
9
- return (v &&
10
- typeof v.method === 'string' &&
11
- Array.isArray(v.rawHeaders) &&
12
- (0, common_1.isReadable)(v));
13
- }
14
- function isHttpIncoming(v) {
15
- return (isNodeIncomingMessage(v) &&
16
- typeof v.header === 'function' &&
17
- typeof v.acceptsLanguages === 'function' &&
18
- typeof v.readBody === 'function');
19
- }
20
- function isNodeOutgoingMessage(v) {
21
- return v && typeof v.getHeaders === 'function' && (0, common_1.isStream)(v);
22
- }
23
- function isHttpOutgoing(v) {
24
- return (isNodeOutgoingMessage(v) &&
25
- typeof v.clearCookie === 'function' &&
26
- typeof v.cookie === 'function');
27
- }
@@ -1,227 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.BodyReader = void 0;
4
- const tslib_1 = require("tslib");
5
- const type_is_1 = tslib_1.__importDefault(require("@browsery/type-is"));
6
- const common_1 = require("@opra/common");
7
- const base64_stream_1 = require("base64-stream");
8
- const bytes_1 = tslib_1.__importDefault(require("bytes"));
9
- const content_type_1 = require("content-type");
10
- const events_1 = require("events");
11
- const iconv_lite_1 = tslib_1.__importDefault(require("iconv-lite"));
12
- const stream_1 = require("stream");
13
- const zlib = tslib_1.__importStar(require("zlib"));
14
- /**
15
- *
16
- * @class BodyReader
17
- */
18
- class BodyReader extends events_1.EventEmitter {
19
- constructor(req, options) {
20
- super();
21
- this.req = req;
22
- this._completed = false;
23
- this._receivedSize = 0;
24
- this.onAborted = () => this._onAborted();
25
- this.onData = (chunk) => this._onData(chunk);
26
- this.onEnd = (err) => this._onEnd(err);
27
- this.cleanup = () => this._cleanup();
28
- this.limit = options?.limit
29
- ? typeof options.limit === 'number'
30
- ? options.limit
31
- : (0, bytes_1.default)(options.limit) || undefined
32
- : undefined;
33
- }
34
- async read() {
35
- /* istanbul ignore next */
36
- if (this._completed) {
37
- throw new common_1.InternalServerError({
38
- message: 'Stream already read',
39
- code: 'STREAM_ALREADY_READ',
40
- });
41
- }
42
- if (!this.req.readable) {
43
- throw new common_1.InternalServerError({
44
- message: 'Stream is not readable',
45
- code: 'STREAM_NOT_READABLE',
46
- });
47
- }
48
- return new Promise((resolve, reject) => {
49
- // eslint-disable-next-line prefer-const
50
- let sizeStream;
51
- this.once('finish', (error, data) => {
52
- if (sizeStream)
53
- this.req.unpipe(sizeStream);
54
- if (error)
55
- return reject(error);
56
- resolve(data);
57
- });
58
- /**
59
- * Check if a request has a request body.
60
- * A request with a body __must__ either have `transfer-encoding`
61
- * or `content-length` headers set.
62
- * http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.3
63
- */
64
- const contentLength = parseInt(this.req.headers['content-length'] || '0', 10);
65
- if (this.req.headers['transfer-encoding'] === undefined &&
66
- !(contentLength && !isNaN(contentLength))) {
67
- return this.onEnd();
68
- }
69
- // check the length and limit options.
70
- // note: we intentionally leave the stream paused,
71
- // so users should handle the stream themselves.
72
- if (this.limit != null &&
73
- contentLength != null &&
74
- contentLength > this.limit) {
75
- return this.onEnd(new common_1.OpraHttpError({
76
- message: 'Content Too Large',
77
- code: 'HTTP.CONTENT_TOO_LARGE',
78
- details: {
79
- length: contentLength,
80
- limit: this.limit,
81
- },
82
- }, 413));
83
- }
84
- // Pipe to a Writable stream to count received bytes
85
- const _this = this;
86
- sizeStream = new stream_1.Writable({
87
- write(chunk, encoding, callback) {
88
- if (_this._completed)
89
- return;
90
- _this._receivedSize += chunk.length;
91
- if (_this.limit != null && _this._receivedSize > _this.limit) {
92
- callback(new common_1.OpraHttpError({
93
- message: 'Content Too Large',
94
- code: 'HTTP.CONTENT_TOO_LARGE',
95
- details: {
96
- limit: _this.limit,
97
- received: _this._receivedSize,
98
- },
99
- }, 413));
100
- }
101
- },
102
- });
103
- this.req.pipe(sizeStream);
104
- let stream = BodyReader.encoderPipeline(this.req);
105
- const mediaType = (0, content_type_1.parse)(this.req.headers['content-type'] || '');
106
- let charset = (mediaType.parameters.charset || '').toLowerCase();
107
- if (!charset && type_is_1.default.is(mediaType.type, ['json', 'xml', 'txt']))
108
- charset = 'utf-8';
109
- if (charset) {
110
- const newStream = iconv_lite_1.default.decodeStream(charset);
111
- stream.pipe(newStream);
112
- stream = newStream;
113
- }
114
- this._stream = stream;
115
- // attach listeners
116
- stream.on('aborted', this.onAborted);
117
- stream.on('close', this.cleanup);
118
- stream.on('data', this.onData);
119
- stream.on('end', this.onEnd);
120
- stream.on('error', this.onEnd);
121
- });
122
- }
123
- _onEnd(error) {
124
- if (this._completed)
125
- return;
126
- this._completed = true;
127
- if (error) {
128
- this._stream?.unpipe();
129
- this._stream?.pause();
130
- }
131
- if (error)
132
- this.emit('finish', error);
133
- else if (Array.isArray(this._buffer))
134
- this.emit('finish', error, Buffer.concat(this._buffer));
135
- else
136
- this.emit('finish', error, this._buffer);
137
- this._cleanup();
138
- }
139
- _cleanup() {
140
- if (this._stream) {
141
- this._stream.removeListener('aborted', this.onAborted);
142
- this._stream.removeListener('close', this.cleanup);
143
- this._stream.removeListener('data', this.onData);
144
- this._stream.removeListener('end', this.onEnd);
145
- this._stream.removeListener('error', this.onEnd);
146
- }
147
- }
148
- _onAborted() {
149
- if (this._completed)
150
- return;
151
- this.onEnd(new common_1.BadRequestError({
152
- message: 'request aborted',
153
- code: 'ECONNABORTED',
154
- details: {
155
- received: this._receivedSize,
156
- },
157
- }));
158
- }
159
- _onData(chunk) {
160
- if (this._completed)
161
- return;
162
- if (typeof chunk === 'string') {
163
- this._buffer = this._buffer || '';
164
- this._buffer += chunk;
165
- }
166
- else {
167
- this._buffer = this._buffer || [];
168
- this._buffer.push(chunk);
169
- }
170
- }
171
- static async read(req, options) {
172
- const bodyReady = new BodyReader(req, options);
173
- return bodyReady.read();
174
- }
175
- static encoderPipeline(req) {
176
- const contentEncoding = req.headers['content-encoding'] || 'identity';
177
- const contentEncodings = (Array.isArray(contentEncoding)
178
- ? contentEncoding
179
- : contentEncoding.split(/\s*,\s*/))
180
- .map(s => s.toLowerCase())
181
- .reverse();
182
- return contentEncodings.reduce((prev, encoding) => {
183
- switch (encoding) {
184
- case 'gzip':
185
- case 'x-gzip': {
186
- const newStream = zlib.createGunzip();
187
- prev.pipe(newStream);
188
- return newStream;
189
- }
190
- case 'deflate':
191
- case 'x-deflate': {
192
- const newStream = zlib.createDeflate();
193
- prev.pipe(newStream);
194
- return newStream;
195
- }
196
- case 'inflate':
197
- case 'x-inflate': {
198
- const newStream = zlib.createInflate();
199
- prev.pipe(newStream);
200
- return newStream;
201
- }
202
- case 'br': {
203
- const newStream = zlib.createBrotliDecompress();
204
- prev.pipe(newStream);
205
- return newStream;
206
- }
207
- case 'base64': {
208
- const newStream = new base64_stream_1.Base64Decode();
209
- prev.pipe(newStream);
210
- return newStream;
211
- }
212
- case 'identity':
213
- // prev.length = 0;
214
- return prev;
215
- default:
216
- throw new common_1.BadRequestError({
217
- message: 'unsupported content encoding "' + encoding + '"',
218
- code: '',
219
- details: {
220
- encoding,
221
- },
222
- }, 415);
223
- }
224
- }, req);
225
- }
226
- }
227
- exports.BodyReader = BodyReader;