@opra/core 1.0.0-beta.1 → 1.0.0-beta.3

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 (85) hide show
  1. package/cjs/execution-context.js +2 -14
  2. package/cjs/index.js +3 -25
  3. package/cjs/platform-adapter.js +3 -3
  4. package/esm/execution-context.js +1 -13
  5. package/esm/index.js +3 -24
  6. package/esm/platform-adapter.js +2 -2
  7. package/package.json +5 -39
  8. package/types/execution-context.d.ts +3 -8
  9. package/types/index.d.cts +3 -23
  10. package/types/index.d.ts +3 -23
  11. package/types/interfaces/logger.interface.d.ts +1 -1
  12. package/types/platform-adapter.d.ts +3 -3
  13. package/types/service-base.d.ts +10 -0
  14. package/cjs/augmentation/http-controller.augmentation.js +0 -25
  15. package/cjs/http/express-adapter.js +0 -155
  16. package/cjs/http/http-adapter.js +0 -24
  17. package/cjs/http/http-context.js +0 -104
  18. package/cjs/http/http-handler.js +0 -609
  19. package/cjs/http/impl/http-incoming.host.js +0 -112
  20. package/cjs/http/impl/http-outgoing.host.js +0 -207
  21. package/cjs/http/impl/multipart-reader.js +0 -196
  22. package/cjs/http/impl/node-incoming-message.host.js +0 -109
  23. package/cjs/http/impl/node-outgoing-message.host.js +0 -195
  24. package/cjs/http/interfaces/http-incoming.interface.js +0 -25
  25. package/cjs/http/interfaces/http-outgoing.interface.js +0 -22
  26. package/cjs/http/interfaces/node-incoming-message.interface.js +0 -64
  27. package/cjs/http/interfaces/node-outgoing-message.interface.js +0 -15
  28. package/cjs/http/utils/body-reader.js +0 -216
  29. package/cjs/http/utils/common.js +0 -67
  30. package/cjs/http/utils/concat-readable.js +0 -19
  31. package/cjs/http/utils/convert-to-headers.js +0 -64
  32. package/cjs/http/utils/convert-to-raw-headers.js +0 -23
  33. package/cjs/http/utils/match-known-fields.js +0 -49
  34. package/cjs/http/utils/wrap-exception.js +0 -33
  35. package/cjs/type-guards.js +0 -22
  36. package/esm/augmentation/http-controller.augmentation.js +0 -23
  37. package/esm/http/express-adapter.js +0 -150
  38. package/esm/http/http-adapter.js +0 -20
  39. package/esm/http/http-context.js +0 -99
  40. package/esm/http/http-handler.js +0 -604
  41. package/esm/http/impl/http-incoming.host.js +0 -107
  42. package/esm/http/impl/http-outgoing.host.js +0 -202
  43. package/esm/http/impl/multipart-reader.js +0 -191
  44. package/esm/http/impl/node-incoming-message.host.js +0 -105
  45. package/esm/http/impl/node-outgoing-message.host.js +0 -191
  46. package/esm/http/interfaces/http-incoming.interface.js +0 -22
  47. package/esm/http/interfaces/http-outgoing.interface.js +0 -19
  48. package/esm/http/interfaces/node-incoming-message.interface.js +0 -61
  49. package/esm/http/interfaces/node-outgoing-message.interface.js +0 -12
  50. package/esm/http/utils/body-reader.js +0 -211
  51. package/esm/http/utils/common.js +0 -61
  52. package/esm/http/utils/concat-readable.js +0 -16
  53. package/esm/http/utils/convert-to-headers.js +0 -60
  54. package/esm/http/utils/convert-to-raw-headers.js +0 -20
  55. package/esm/http/utils/match-known-fields.js +0 -45
  56. package/esm/http/utils/wrap-exception.js +0 -30
  57. package/esm/type-guards.js +0 -16
  58. package/types/augmentation/http-controller.augmentation.d.ts +0 -20
  59. package/types/helpers/service-base.d.ts +0 -10
  60. package/types/http/express-adapter.d.ts +0 -13
  61. package/types/http/http-adapter.d.ts +0 -54
  62. package/types/http/http-context.d.ts +0 -44
  63. package/types/http/http-handler.d.ts +0 -75
  64. package/types/http/impl/http-incoming.host.d.ts +0 -22
  65. package/types/http/impl/http-outgoing.host.d.ts +0 -17
  66. package/types/http/impl/multipart-reader.d.ts +0 -46
  67. package/types/http/impl/node-incoming-message.host.d.ts +0 -45
  68. package/types/http/impl/node-outgoing-message.host.d.ts +0 -49
  69. package/types/http/interfaces/http-incoming.interface.d.ts +0 -192
  70. package/types/http/interfaces/http-outgoing.interface.d.ts +0 -144
  71. package/types/http/interfaces/node-incoming-message.interface.d.ts +0 -36
  72. package/types/http/interfaces/node-outgoing-message.interface.d.ts +0 -27
  73. package/types/http/utils/body-reader.d.ts +0 -38
  74. package/types/http/utils/common.d.ts +0 -17
  75. package/types/http/utils/concat-readable.d.ts +0 -2
  76. package/types/http/utils/convert-to-headers.d.ts +0 -2
  77. package/types/http/utils/convert-to-raw-headers.d.ts +0 -2
  78. package/types/http/utils/match-known-fields.d.ts +0 -6
  79. package/types/http/utils/wrap-exception.d.ts +0 -2
  80. package/types/type-guards.d.ts +0 -8
  81. /package/cjs/{http/impl/asset-cache.js → asset-cache.js} +0 -0
  82. /package/cjs/{helpers/service-base.js → service-base.js} +0 -0
  83. /package/esm/{http/impl/asset-cache.js → asset-cache.js} +0 -0
  84. /package/esm/{helpers/service-base.js → service-base.js} +0 -0
  85. /package/types/{http/impl/asset-cache.d.ts → asset-cache.d.ts} +0 -0
@@ -1,107 +0,0 @@
1
- /*
2
- Some parts of this file contains codes from open source express library
3
- https://github.com/expressjs
4
- */
5
- import typeIs from '@browsery/type-is';
6
- import accepts from 'accepts';
7
- import fresh from 'fresh';
8
- import parseRange from 'range-parser';
9
- import { BodyReader } from '../utils/body-reader.js';
10
- export class HttpIncomingHost {
11
- get protocol() {
12
- const proto = this.header('X-Forwarded-Proto') || 'http';
13
- const index = proto.indexOf(',');
14
- return index !== -1 ? proto.substring(0, index).trim() : proto.trim();
15
- }
16
- get secure() {
17
- return this.protocol === 'https';
18
- }
19
- get hostname() {
20
- let host = this.get('X-Forwarded-Host');
21
- if (!host) {
22
- host = this.get('Host');
23
- }
24
- else if (host.indexOf(',') !== -1) {
25
- // Note: X-Forwarded-Host is normally only ever a
26
- // single value, but this is to be safe.
27
- host = host.substring(0, host.indexOf(',')).trim();
28
- }
29
- if (host) {
30
- // IPv6 literal support
31
- const offset = host[0] === '[' ? host.indexOf(']') + 1 : 0;
32
- const index = host.indexOf(':', offset);
33
- return index !== -1 ? host.substring(0, index) : host;
34
- }
35
- return '';
36
- }
37
- get fresh() {
38
- const method = this.method;
39
- // GET or HEAD for weak freshness validation only
40
- if (method !== 'GET' && method !== 'HEAD')
41
- return false;
42
- const status = this.res?.statusCode;
43
- // 2xx or 304 as per rfc2616 14.26
44
- if ((status >= 200 && status < 300) || status === 304) {
45
- return fresh(this.headers, {
46
- etag: this.res.getHeader('ETag'),
47
- 'last-modified': this.res.getHeader('Last-Modified'),
48
- });
49
- }
50
- return false;
51
- }
52
- get xhr() {
53
- const val = this.get('X-Requested-With') || '';
54
- return val.toLowerCase() === 'xmlhttprequest';
55
- }
56
- header(name) {
57
- name = name.toLowerCase();
58
- const headers = this.headers;
59
- switch (name) {
60
- case 'referer':
61
- return headers.referer || headers.referrer;
62
- case 'referrer':
63
- return headers.referrer || headers.referer;
64
- default:
65
- return headers[name];
66
- }
67
- }
68
- get(name) {
69
- return this.header(name);
70
- }
71
- accepts(...types) {
72
- const accept = accepts(this);
73
- return accept.types.call(accept, ...types);
74
- }
75
- acceptsCharsets(...charsets) {
76
- const accept = accepts(this);
77
- return accept.charsets.call(accept, ...charsets);
78
- }
79
- acceptsEncodings(...encoding) {
80
- const accept = accepts(this);
81
- // eslint-disable-next-line prefer-spread
82
- return accept.encodings.apply(accept, encoding);
83
- }
84
- acceptsLanguages(...lang) {
85
- const accept = accepts(this);
86
- // eslint-disable-next-line prefer-spread
87
- return accept.languages.apply(accept, lang);
88
- }
89
- is(type, ...otherTypes) {
90
- const types = Array.isArray(type) ? type : [type];
91
- if (otherTypes.length)
92
- types.push(...otherTypes);
93
- const contentType = this.header('content-type');
94
- return contentType ? typeIs.is(contentType, types) : null;
95
- }
96
- range(size, options) {
97
- const range = this.header('range');
98
- if (!range)
99
- return;
100
- return parseRange(size, range, options);
101
- }
102
- async readBody(options) {
103
- if (!this.complete)
104
- this.body = await BodyReader.read(this, options);
105
- return this.body;
106
- }
107
- }
@@ -1,202 +0,0 @@
1
- /*
2
- Some parts of this file contains codes from open source express library
3
- https://github.com/expressjs
4
- */
5
- import path from 'node:path';
6
- import { HttpStatusCode } from '@opra/common';
7
- import contentDisposition from 'content-disposition';
8
- import contentType from 'content-type';
9
- import cookie from 'cookie';
10
- import cookieSignature from 'cookie-signature';
11
- import encodeUrl from 'encodeurl';
12
- import mime from 'mime-types';
13
- import { toString } from 'putil-varhelpers';
14
- import vary from 'vary';
15
- const charsetRegExp = /;\s*charset\s*=/;
16
- export class HttpOutgoingHost {
17
- attachment(filename) {
18
- if (filename)
19
- this.contentType(path.extname(filename));
20
- this.setHeader('Content-Disposition', contentDisposition(filename));
21
- return this;
22
- }
23
- contentType(type) {
24
- const ct = type.indexOf('/') === -1 ? mime.lookup(type) : type;
25
- this.setHeader('Content-Type', ct);
26
- return this;
27
- }
28
- setHeader(field, val) {
29
- const setHeader = Object.getPrototypeOf(this).setHeader;
30
- if (typeof field === 'object') {
31
- for (const [k, v] of Object.entries(field)) {
32
- this.setHeader(k, v);
33
- }
34
- return this;
35
- }
36
- const fieldLower = field.toLowerCase();
37
- let value = Array.isArray(val) ? val.map(String) : val ? String(val) : '';
38
- // add charset to content-type
39
- if (fieldLower === 'content-type') {
40
- if (Array.isArray(value)) {
41
- throw new TypeError('Content-Type cannot be set to an Array');
42
- }
43
- if (!charsetRegExp.test(value)) {
44
- const charset = mime.charsets.lookup(value.split(';')[0]);
45
- if (charset)
46
- value += '; charset=' + charset.toLowerCase();
47
- }
48
- }
49
- setHeader.call(this, field, value);
50
- return this;
51
- }
52
- clearCookie(name, options) {
53
- const opts = {
54
- expires: new Date(1),
55
- path: '/',
56
- ...options,
57
- };
58
- return this.cookie(name, '', opts);
59
- }
60
- cookie(name, value, options) {
61
- const opts = { ...options };
62
- let val = typeof value === 'object' ? 'j:' + JSON.stringify(value) : String(value);
63
- if (opts.signed) {
64
- const secret = opts.secret || this.req?.secret;
65
- if (!secret)
66
- throw new Error('"secret" required for signed cookies');
67
- val = 's:' + cookieSignature.sign(val, secret);
68
- }
69
- if (opts.maxAge != null) {
70
- const maxAge = opts.maxAge - 0;
71
- if (!isNaN(maxAge)) {
72
- opts.expires = new Date(Date.now() + maxAge);
73
- opts.maxAge = Math.floor(maxAge / 1000);
74
- }
75
- }
76
- if (opts.path == null)
77
- opts.path = '/';
78
- this.appendHeader('Set-Cookie', cookie.serialize(name, String(val), opts));
79
- return this;
80
- }
81
- status(code) {
82
- this.statusCode = code;
83
- return this;
84
- }
85
- sendStatus(statusCode) {
86
- const body = HttpStatusCode[statusCode] || String(statusCode);
87
- this.statusCode = statusCode;
88
- this.contentType('txt');
89
- return this.send(body);
90
- }
91
- links(links) {
92
- let link = this.getHeader('Link') || '';
93
- if (link)
94
- link += ', ';
95
- this.setHeader('Link', link +
96
- Object.keys(links)
97
- .map(rel => '<' + links[rel] + '>; rel="' + rel + '"')
98
- .join(', '));
99
- return this;
100
- }
101
- location(url) {
102
- let loc = url;
103
- // "back" is an alias for the referrer
104
- if (url === 'back')
105
- loc = this.req?.get('Referrer') || '/';
106
- // set location
107
- return this.setHeader('Location', encodeUrl(loc));
108
- }
109
- redirect(arg0, arg1) {
110
- const address = String(arg1 || arg0);
111
- const status = typeof arg0 === 'number' ? arg0 : 302;
112
- // Set location header
113
- this.location(address);
114
- // Respond
115
- this.statusCode = status;
116
- this.end();
117
- }
118
- send(body) {
119
- let chunk = body;
120
- let encoding;
121
- const req = this.req;
122
- let ctype = toString(this.getHeader('Content-Type'));
123
- if (typeof chunk !== 'string') {
124
- if (chunk === null)
125
- chunk = '';
126
- else if (Buffer.isBuffer(chunk)) {
127
- if (!ctype)
128
- this.contentType('bin');
129
- }
130
- else {
131
- ctype = 'json';
132
- chunk = JSON.stringify(chunk);
133
- }
134
- }
135
- // write strings in utf-8
136
- if (typeof chunk === 'string') {
137
- encoding = 'utf-8';
138
- this.setHeader('Content-Type', setCharset(ctype || 'txt', encoding));
139
- }
140
- // populate Content-Length
141
- let len = 0;
142
- if (chunk !== undefined) {
143
- if (Buffer.isBuffer(chunk)) {
144
- // get length of Buffer
145
- len = chunk.length;
146
- }
147
- else if (chunk.length < 1000) {
148
- // just calculate length when small chunk
149
- len = Buffer.byteLength(chunk, encoding);
150
- }
151
- else {
152
- // convert chunk to Buffer and calculate
153
- chunk = Buffer.from(chunk, encoding);
154
- encoding = undefined;
155
- len = chunk.length;
156
- }
157
- this.setHeader('Content-Length', len);
158
- }
159
- // freshness
160
- if (req?.fresh)
161
- this.statusCode = 304;
162
- // strip irrelevant headers
163
- if (this.statusCode === 204 || this.statusCode === 304) {
164
- this.removeHeader('Content-Type');
165
- this.removeHeader('Content-Length');
166
- this.removeHeader('Transfer-Encoding');
167
- chunk = '';
168
- }
169
- // alter headers for 205
170
- if (this.statusCode === 205) {
171
- this.setHeader('Content-Length', '0');
172
- this.removeHeader('Transfer-Encoding');
173
- chunk = '';
174
- }
175
- if (req?.method === 'HEAD') {
176
- // skip body for HEAD
177
- this.end();
178
- }
179
- else {
180
- // respond
181
- if (encoding)
182
- this.end(chunk, encoding);
183
- else
184
- this.end(chunk);
185
- }
186
- return this;
187
- }
188
- vary(field) {
189
- vary(this, field);
190
- return this;
191
- }
192
- }
193
- function setCharset(type, charset) {
194
- if (!(type && charset))
195
- return type;
196
- // parse type
197
- const parsed = contentType.parse(type);
198
- // set charset
199
- parsed.parameters.charset = charset;
200
- // format type
201
- return contentType.format(parsed);
202
- }
@@ -1,191 +0,0 @@
1
- import { randomFillSync } from 'node:crypto';
2
- import fs from 'node:fs';
3
- import os from 'node:os';
4
- import nodePath from 'node:path';
5
- import typeIs from '@browsery/type-is';
6
- import { BadRequestError } from '@opra/common';
7
- import busboy from 'busboy';
8
- import { EventEmitter } from 'events';
9
- import fsPromise from 'fs/promises';
10
- import { isNotNullish } from 'valgen';
11
- export class MultipartReader extends EventEmitter {
12
- constructor(context, options, mediaType) {
13
- super();
14
- this.context = context;
15
- this.mediaType = mediaType;
16
- this._started = false;
17
- this._finished = false;
18
- this._cancelled = false;
19
- this._items = [];
20
- this._stack = [];
21
- this.setMaxListeners(1000);
22
- this.tempDirectory = options?.tempDirectory || os.tmpdir();
23
- const { request } = context;
24
- const form = busboy({ headers: request.headers });
25
- this._form = form;
26
- form.once('error', (e) => {
27
- this._cancelled = true;
28
- this._finished = true;
29
- if (this.listenerCount('error') > 0)
30
- this.emit('error', e);
31
- });
32
- form.on('close', () => {
33
- this._finished = true;
34
- });
35
- form.on('field', (field, value, info) => {
36
- const item = {
37
- kind: 'field',
38
- field,
39
- value,
40
- mimeType: info.mimeType,
41
- encoding: info.encoding,
42
- };
43
- this._items.push(item);
44
- this._stack.push(item);
45
- this.emit('field', item);
46
- this.emit('item', item);
47
- });
48
- form.on('file', (field, file, info) => {
49
- const saveTo = nodePath.join(this.tempDirectory, `opra-${generateFileName()}`);
50
- file.pipe(fs.createWriteStream(saveTo));
51
- file.once('end', () => {
52
- const item = {
53
- kind: 'file',
54
- field,
55
- storedPath: saveTo,
56
- filename: info.filename,
57
- mimeType: info.mimeType,
58
- encoding: info.encoding,
59
- };
60
- this._items.push(item);
61
- this._stack.push(item);
62
- this.emit('file', item);
63
- this.emit('item', item);
64
- });
65
- });
66
- }
67
- get items() {
68
- return this._items;
69
- }
70
- async getNext() {
71
- let item = this._stack.shift();
72
- if (!item && !this._finished) {
73
- this.resume();
74
- item = await new Promise((resolve, reject) => {
75
- let resolved = false;
76
- if (this._stack.length)
77
- return resolve(this._stack.shift());
78
- if (this._form.ended)
79
- return resolve(undefined);
80
- this._form.once('close', () => {
81
- if (resolved)
82
- return;
83
- resolved = true;
84
- resolve(this._stack.shift());
85
- });
86
- this.once('item', () => {
87
- this.pause();
88
- if (resolved)
89
- return;
90
- resolved = true;
91
- resolve(this._stack.shift());
92
- });
93
- this.once('error', e => reject(e));
94
- });
95
- }
96
- if (item && this.mediaType) {
97
- const field = this.mediaType.findMultipartField(item.field);
98
- if (!field)
99
- throw new BadRequestError(`Unknown multipart field (${item.field})`);
100
- if (item.kind === 'field') {
101
- const decode = field.generateCodec('decode', { ignoreReadonlyFields: true, projection: '*' });
102
- item.value = decode(item.value, {
103
- onFail: issue => `Multipart field (${item.field}) validation failed: ` + issue.message,
104
- });
105
- }
106
- else if (item.kind === 'file') {
107
- if (field.contentType) {
108
- const arr = Array.isArray(field.contentType) ? field.contentType : [field.contentType];
109
- if (!(item.mimeType && arr.find(ct => typeIs.is(item.mimeType, [ct])))) {
110
- throw new BadRequestError(`Multipart field (${item.field}) do not accept this content type`);
111
- }
112
- }
113
- }
114
- }
115
- /** if all items received we check for required items */
116
- if (this._finished && this.mediaType && this.mediaType.multipartFields?.length > 0) {
117
- const fieldsLeft = new Set(this.mediaType.multipartFields);
118
- for (const x of this._items) {
119
- const field = this.mediaType.findMultipartField(x.field);
120
- if (field)
121
- fieldsLeft.delete(field);
122
- }
123
- let issues;
124
- for (const field of fieldsLeft) {
125
- if (!field.required)
126
- continue;
127
- try {
128
- isNotNullish(null, { onFail: () => `Multi part field "${String(field.fieldName)}" is required` });
129
- }
130
- catch (e) {
131
- if (!issues) {
132
- issues = e.issues;
133
- this.context.errors.push(e);
134
- }
135
- else
136
- issues.push(...e.issues);
137
- }
138
- }
139
- if (this.context.errors.length)
140
- throw this.context.errors[0];
141
- }
142
- return item;
143
- }
144
- async getAll() {
145
- const items = [...this._items];
146
- let item;
147
- while (!this._cancelled && (item = await this.getNext())) {
148
- items.push(item);
149
- }
150
- return items;
151
- }
152
- getAll_() {
153
- if (this._form.ended)
154
- return Promise.resolve([...this._items]);
155
- this.resume();
156
- return new Promise((resolve, reject) => {
157
- this._form.once('error', reject);
158
- this._form.once('end', () => {
159
- resolve([...this._items]);
160
- });
161
- });
162
- }
163
- cancel() {
164
- this._cancelled = true;
165
- if (this._form.req)
166
- this.resume();
167
- }
168
- resume() {
169
- if (!this._started) {
170
- this._started = true;
171
- this.context.request.pipe(this._form);
172
- }
173
- this.context.request.resume();
174
- }
175
- pause() {
176
- this.context.request.pause();
177
- }
178
- async purge() {
179
- const promises = [];
180
- this._items.forEach(item => {
181
- if (item.kind !== 'file')
182
- return;
183
- promises.push(fsPromise.unlink(item.storedPath));
184
- });
185
- return Promise.allSettled(promises);
186
- }
187
- }
188
- function generateFileName() {
189
- const buf = Buffer.alloc(10);
190
- return new Date().toISOString().substring(0, 10).replace(/-/g, '') + randomFillSync(buf).toString('hex');
191
- }
@@ -1,105 +0,0 @@
1
- import { isAsyncIterable, isIterable } from '@opra/common';
2
- import { Duplex, Readable } from 'stream';
3
- import { convertToHeaders, convertToHeadersDistinct } from '../utils/convert-to-headers.js';
4
- import { convertToRawHeaders } from '../utils/convert-to-raw-headers.js';
5
- export const CRLF = Buffer.from('\r\n');
6
- export const kHeaders = Symbol.for('kHeaders');
7
- export const kHeadersDistinct = Symbol.for('kHeadersDistinct');
8
- export const kTrailers = Symbol.for('kTrailers');
9
- export const kTrailersDistinct = Symbol.for('kTrailersDistinct');
10
- export const kHttpParser = Symbol.for('kHttpParser');
11
- /**
12
- *
13
- * @class NodeIncomingMessageHost
14
- */
15
- export class NodeIncomingMessageHost extends Duplex {
16
- constructor(init) {
17
- super();
18
- this.rawHeaders = [];
19
- this.rawTrailers = [];
20
- this.complete = false;
21
- this.joinDuplicateHeaders = false;
22
- if (init) {
23
- this.complete = true;
24
- this.httpVersionMajor = init.httpVersionMajor || 1;
25
- this.httpVersionMinor = init.httpVersionMinor || 0;
26
- this.method = (init.method || 'GET').toUpperCase();
27
- this.url = init.url || '';
28
- if (init.body != null) {
29
- if (Buffer.isBuffer(init.body))
30
- this.body = init.body;
31
- else if (typeof init.body === 'string')
32
- this.body = Buffer.from(init.body, 'utf-8');
33
- else
34
- this.body = Buffer.from(JSON.stringify(init.body), 'utf-8');
35
- }
36
- if (init.headers) {
37
- this.rawHeaders = Array.isArray(init.headers) ? init.headers : convertToRawHeaders(init.headers);
38
- }
39
- if (init.trailers) {
40
- this.rawTrailers = Array.isArray(init.trailers) ? init.trailers : convertToRawHeaders(init.trailers);
41
- }
42
- this.ip = init.ip || '';
43
- this.ips = init.ips || (this.ip ? [this.ip] : []);
44
- if (this.body && !this.headers['content-length'])
45
- this.headers['content-length'] = String(this.body.length);
46
- if (init.params)
47
- this.params = init.params;
48
- if (init.cookies)
49
- this.cookies = init.cookies;
50
- }
51
- }
52
- get httpVersion() {
53
- return this.httpVersionMajor ? this.httpVersionMajor + '.' + this.httpVersionMinor : '';
54
- }
55
- get headers() {
56
- if (!this[kHeaders])
57
- this[kHeaders] = convertToHeaders(this.rawHeaders, {}, this.joinDuplicateHeaders);
58
- return this[kHeaders];
59
- }
60
- set headers(headers) {
61
- this[kHeaders] = headers;
62
- }
63
- get headersDistinct() {
64
- if (!this[kHeadersDistinct])
65
- this[kHeadersDistinct] = convertToHeadersDistinct(this.rawHeaders, {});
66
- return this[kHeadersDistinct];
67
- }
68
- get trailers() {
69
- if (!this[kTrailers])
70
- this[kTrailers] = convertToHeaders(this.rawTrailers, {}, this.joinDuplicateHeaders);
71
- return this[kTrailers];
72
- }
73
- set trailers(trailers) {
74
- this[kTrailers] = trailers;
75
- }
76
- get trailersDistinct() {
77
- if (!this[kTrailersDistinct])
78
- this[kTrailersDistinct] = convertToHeadersDistinct(this.rawTrailers, {});
79
- return this[kTrailersDistinct];
80
- }
81
- _read(size) {
82
- if (!this.body) {
83
- this.push(null);
84
- return;
85
- }
86
- if (!this._readStream) {
87
- if (isIterable(this.body) || isAsyncIterable(this.body))
88
- this._readStream = Readable.from(this.body);
89
- else if (typeof this.body === 'string') {
90
- this._readStream = Readable.from(Buffer.from(this.body, 'utf-8'));
91
- }
92
- else
93
- this._readStream = Readable.from(Buffer.from(JSON.stringify(this.body), 'utf-8'));
94
- }
95
- const chunk = this._readStream.read(size);
96
- this.push(chunk);
97
- }
98
- _write(chunk, encoding, callback) {
99
- const error = this[kHttpParser]?.execute(chunk);
100
- if (error && typeof error === 'object')
101
- callback(error);
102
- else
103
- callback();
104
- }
105
- }