@opra/core 0.20.3 → 0.21.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.
Files changed (77) hide show
  1. package/cjs/adapter/adapter.js +2 -2
  2. package/cjs/adapter/http/express-adapter.js +29 -7
  3. package/cjs/adapter/http/helpers/common.js +66 -0
  4. package/cjs/adapter/http/helpers/convert-to-headers.js +65 -0
  5. package/cjs/adapter/http/helpers/convert-to-raw-headers.js +25 -0
  6. package/cjs/adapter/http/helpers/match-known-fields.js +47 -0
  7. package/cjs/adapter/http/http-adapter.js +76 -438
  8. package/cjs/adapter/http/impl/http-incoming-message-host.js +127 -0
  9. package/cjs/adapter/http/impl/http-outgoing-message-host.js +210 -0
  10. package/cjs/adapter/http/impl/http-server-request.js +125 -0
  11. package/cjs/adapter/http/impl/http-server-response.js +226 -0
  12. package/cjs/adapter/http/request-parsers/batch-request-parser.js +169 -0
  13. package/cjs/adapter/http/request-parsers/parse-collection-request.js +165 -0
  14. package/cjs/adapter/http/request-parsers/parse-request.js +24 -0
  15. package/cjs/adapter/http/request-parsers/parse-singleton-request.js +96 -0
  16. package/cjs/adapter/request-context.host.js +17 -3
  17. package/cjs/adapter/request.host.js +6 -3
  18. package/cjs/adapter/response.host.js +5 -3
  19. package/cjs/index.js +4 -2
  20. package/esm/adapter/adapter.js +2 -2
  21. package/esm/adapter/http/express-adapter.js +6 -6
  22. package/esm/adapter/http/helpers/common.js +60 -0
  23. package/esm/adapter/http/helpers/convert-to-headers.js +60 -0
  24. package/esm/adapter/http/helpers/convert-to-raw-headers.js +21 -0
  25. package/esm/adapter/http/helpers/match-known-fields.js +43 -0
  26. package/esm/adapter/http/http-adapter.js +77 -439
  27. package/esm/adapter/http/impl/http-incoming-message-host.js +122 -0
  28. package/esm/adapter/http/impl/http-outgoing-message-host.js +205 -0
  29. package/esm/adapter/http/impl/http-server-request.js +121 -0
  30. package/esm/adapter/http/impl/http-server-response.js +222 -0
  31. package/esm/adapter/http/request-parsers/batch-request-parser.js +169 -0
  32. package/esm/adapter/http/request-parsers/parse-collection-request.js +161 -0
  33. package/esm/adapter/http/request-parsers/parse-request.js +20 -0
  34. package/esm/adapter/http/request-parsers/parse-singleton-request.js +92 -0
  35. package/esm/adapter/request-context.host.js +17 -3
  36. package/esm/adapter/request.host.js +6 -3
  37. package/esm/adapter/response.host.js +5 -3
  38. package/esm/index.js +4 -2
  39. package/package.json +20 -16
  40. package/types/adapter/adapter.d.ts +1 -1
  41. package/types/adapter/http/helpers/common.d.ts +17 -0
  42. package/types/adapter/http/helpers/convert-to-headers.d.ts +2 -0
  43. package/types/adapter/http/helpers/convert-to-raw-headers.d.ts +3 -0
  44. package/types/adapter/http/helpers/match-known-fields.d.ts +6 -0
  45. package/types/adapter/http/http-adapter.d.ts +7 -12
  46. package/types/adapter/http/impl/http-incoming-message-host.d.ts +58 -0
  47. package/types/adapter/http/impl/http-outgoing-message-host.d.ts +72 -0
  48. package/types/adapter/http/{http-request-message.d.ts → impl/http-server-request.d.ts} +52 -85
  49. package/types/adapter/http/impl/http-server-response.d.ts +137 -0
  50. package/types/adapter/http/request-parsers/batch-request-parser.d.ts +0 -0
  51. package/types/adapter/http/request-parsers/parse-collection-request.d.ts +4 -0
  52. package/types/adapter/http/request-parsers/parse-request.d.ts +4 -0
  53. package/types/adapter/http/request-parsers/parse-singleton-request.d.ts +4 -0
  54. package/types/adapter/interfaces/request-context.interface.d.ts +14 -10
  55. package/types/adapter/interfaces/request.interface.d.ts +3 -2
  56. package/types/adapter/interfaces/response.interface.d.ts +2 -2
  57. package/types/adapter/request-context.host.d.ts +9 -6
  58. package/types/adapter/request.host.d.ts +8 -4
  59. package/types/adapter/response.host.d.ts +6 -4
  60. package/types/index.d.ts +4 -2
  61. package/cjs/adapter/http/http-message.host.js +0 -251
  62. package/cjs/adapter/http/http-request-context.host.js +0 -28
  63. package/cjs/adapter/http/http-request-message.js +0 -152
  64. package/cjs/adapter/http/http-request.host.js +0 -14
  65. package/cjs/adapter/http/http-response-message.js +0 -238
  66. package/cjs/adapter/http/http-response.host.js +0 -14
  67. package/esm/adapter/http/http-message.host.js +0 -246
  68. package/esm/adapter/http/http-request-context.host.js +0 -24
  69. package/esm/adapter/http/http-request-message.js +0 -148
  70. package/esm/adapter/http/http-request.host.js +0 -10
  71. package/esm/adapter/http/http-response-message.js +0 -233
  72. package/esm/adapter/http/http-response.host.js +0 -10
  73. package/types/adapter/http/http-message.host.d.ts +0 -122
  74. package/types/adapter/http/http-request-context.host.d.ts +0 -16
  75. package/types/adapter/http/http-request.host.d.ts +0 -7
  76. package/types/adapter/http/http-response-message.d.ts +0 -321
  77. package/types/adapter/http/http-response.host.d.ts +0 -7
@@ -0,0 +1,210 @@
1
+ "use strict";
2
+ /*
3
+ This file contains code blocks from open source NodeJs project
4
+ https://github.com/nodejs/
5
+ */
6
+ var _a;
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.HttpOutgoingMessageHost = exports.kErrored = exports.kOutTrailers = exports.kOutHeaders = void 0;
9
+ const tslib_1 = require("tslib");
10
+ const stream = tslib_1.__importStar(require("stream"));
11
+ const common_js_1 = require("../helpers/common.js");
12
+ exports.kOutHeaders = Symbol('kOutHeaders');
13
+ exports.kOutTrailers = Symbol('kOutTrailers');
14
+ exports.kErrored = Symbol('kErrored');
15
+ // noinspection JSUnusedLocalSymbols
16
+ /**
17
+ *
18
+ * @class HttpOutgoingMessageHost
19
+ */
20
+ class HttpOutgoingMessageHost {
21
+ constructor() {
22
+ this._headersSent = false;
23
+ this._closed = false;
24
+ this[_a] = null;
25
+ this.finished = false;
26
+ stream.Stream.apply(this);
27
+ }
28
+ get headersSent() {
29
+ return this._headersSent;
30
+ }
31
+ get closed() {
32
+ return this._closed;
33
+ }
34
+ get errored() {
35
+ return this[exports.kErrored];
36
+ }
37
+ appendHeader(name, value) {
38
+ if (this.headersSent)
39
+ throw new Error(`Cannot set headers after they are sent to the client`);
40
+ (0, common_js_1.validateHeaderName)(name);
41
+ (0, common_js_1.validateHeaderValue)(name, value);
42
+ const field = name.toLowerCase();
43
+ const headers = this[exports.kOutHeaders];
44
+ if (headers == null || !headers[field]) {
45
+ return this.setHeader(name, value);
46
+ }
47
+ // Prepare the field for appending, if required
48
+ if (!Array.isArray(headers[field][1])) {
49
+ headers[field][1] = [headers[field][1]];
50
+ }
51
+ const existingValues = headers[field][1];
52
+ if (Array.isArray(value)) {
53
+ for (let i = 0, length = value.length; i < length; i++) {
54
+ existingValues.push(value[i]);
55
+ }
56
+ }
57
+ else {
58
+ existingValues.push(value);
59
+ }
60
+ return this;
61
+ }
62
+ addTrailers(headers) {
63
+ if (headers && typeof headers === 'object') {
64
+ const entries = typeof headers.entries === 'function'
65
+ ? headers.entries() : Object.entries(headers);
66
+ let trailers = this[exports.kOutTrailers];
67
+ if (trailers == null)
68
+ this[exports.kOutTrailers] = trailers = { __proto__: null };
69
+ for (const [name, value] of entries) {
70
+ (0, common_js_1.validateHeaderName)(name);
71
+ (0, common_js_1.validateHeaderValue)(name, value);
72
+ trailers[String(name).toLowerCase()] = [String(name), value];
73
+ }
74
+ return;
75
+ }
76
+ throw new TypeError('Invalid "headers" argument. Value must be an object or raw headers array');
77
+ }
78
+ setHeader(name, value) {
79
+ if (this.headersSent)
80
+ throw new Error(`Cannot set headers after they are sent to the client`);
81
+ (0, common_js_1.validateHeaderName)(name);
82
+ (0, common_js_1.validateHeaderValue)(name, value);
83
+ let headers = this[exports.kOutHeaders];
84
+ if (headers == null)
85
+ this[exports.kOutHeaders] = headers = { __proto__: null };
86
+ headers[name.toLowerCase()] = [name, value];
87
+ return this;
88
+ }
89
+ setHeaders(headers) {
90
+ if (this.headersSent)
91
+ throw new Error(`Cannot set headers after they are sent to the client`);
92
+ if (headers && typeof headers === 'object' && !Array.isArray(headers)) {
93
+ const entries = typeof headers.entries === 'function'
94
+ ? headers.entries() : Object.entries(headers);
95
+ for (const entry of entries) {
96
+ this.setHeader(entry[0], entry[1]);
97
+ }
98
+ return this;
99
+ }
100
+ throw new TypeError('Invalid "headers" argument. Value must be an instance of "Headers" or "Map"');
101
+ }
102
+ getHeader(name) {
103
+ (0, common_js_1.validateString)(name);
104
+ const headers = this[exports.kOutHeaders];
105
+ if (headers == null)
106
+ return;
107
+ const entry = headers[name.toLowerCase()];
108
+ return entry && entry[1];
109
+ }
110
+ getHeaderNames() {
111
+ return this[exports.kOutHeaders] != null ? Object.keys(this[exports.kOutHeaders]) : [];
112
+ }
113
+ getRawHeaderNames() {
114
+ const headersMap = this[exports.kOutHeaders];
115
+ if (!headersMap)
116
+ return [];
117
+ const values = Object.values(headersMap);
118
+ const headers = Array(values.length);
119
+ for (let i = 0, l = values.length; i < l; i++) {
120
+ headers[i] = values[i][0];
121
+ }
122
+ return headers;
123
+ }
124
+ getHeaders() {
125
+ const headers = this[exports.kOutHeaders];
126
+ // @ts-ignore
127
+ const ret = { __proto__: null };
128
+ if (headers) {
129
+ const keys = Object.keys(headers);
130
+ let key;
131
+ let val;
132
+ for (let i = 0; i < keys.length; ++i) {
133
+ key = keys[i];
134
+ val = headers[key][1];
135
+ ret[key] = val;
136
+ }
137
+ }
138
+ return ret;
139
+ }
140
+ hasHeader(name) {
141
+ (0, common_js_1.validateString)(name);
142
+ return this[exports.kOutHeaders] != null &&
143
+ !!this[exports.kOutHeaders][name.toLowerCase()];
144
+ }
145
+ removeHeader(name) {
146
+ (0, common_js_1.validateString)(name);
147
+ if (this.headersSent)
148
+ throw new Error(`Cannot remove headers after they are sent to the client`);
149
+ const key = name.toLowerCase();
150
+ // switch (key) {
151
+ // case 'connection':
152
+ // this._removedConnection = true;
153
+ // break;
154
+ // case 'content-length':
155
+ // this._removedContLen = true;
156
+ // break;
157
+ // case 'transfer-encoding':
158
+ // this._removedTE = true;
159
+ // break;
160
+ // case 'date':
161
+ // this.sendDate = false;
162
+ // break;
163
+ // }
164
+ if (this[exports.kOutHeaders] != null) {
165
+ delete this[exports.kOutHeaders][key];
166
+ }
167
+ }
168
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
169
+ end(arg0, arg1, arg2) {
170
+ // let cb: (() => void) | undefined;
171
+ // let chunk: any;
172
+ // let encoding: BufferEncoding | undefined;
173
+ //
174
+ // if (typeof arg0 === 'function')
175
+ // cb = arg0;
176
+ // else {
177
+ // chunk = arg0;
178
+ // if (typeof arg1 === 'function')
179
+ // cb = arg1;
180
+ // else {
181
+ // encoding = arg1;
182
+ // cb = arg2;
183
+ // }
184
+ // }
185
+ //
186
+ return this;
187
+ }
188
+ _readConfig(init) {
189
+ this.req = init.req;
190
+ this.statusCode = init?.statusCode || 0;
191
+ this.statusMessage = init?.statusMessage || '';
192
+ this.chunkedEncoding = !!init?.chunkedEncoding;
193
+ this.sendDate = !!init?.sendDate;
194
+ this.strictContentLength = !!init?.strictContentLength;
195
+ if (init.headers) {
196
+ this.setHeaders(Array.isArray(init.headers) ? new Map([init.headers]) : init.headers);
197
+ }
198
+ this.body = init.body;
199
+ }
200
+ static create(init) {
201
+ const msg = new HttpOutgoingMessageHost();
202
+ if (init)
203
+ msg._readConfig(init);
204
+ return msg;
205
+ }
206
+ }
207
+ exports.HttpOutgoingMessageHost = HttpOutgoingMessageHost;
208
+ _a = exports.kErrored;
209
+ // Apply mixins
210
+ Object.assign(HttpOutgoingMessageHost.prototype, stream.Stream.prototype);
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ /*
3
+ Some parts of this file contains codes from open source express library
4
+ https://github.com/expressjs
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.HttpServerRequest = void 0;
8
+ const tslib_1 = require("tslib");
9
+ const accepts_1 = tslib_1.__importDefault(require("accepts"));
10
+ const fresh_1 = tslib_1.__importDefault(require("fresh"));
11
+ const range_parser_1 = tslib_1.__importDefault(require("range-parser"));
12
+ const type_is_1 = tslib_1.__importDefault(require("type-is"));
13
+ const common_1 = require("@opra/common");
14
+ const http_incoming_message_host_js_1 = require("./http-incoming-message-host.js");
15
+ function isHttpIncomingMessage(v) {
16
+ return v && Array.isArray(v.rawHeaders) && (0, common_1.isReadable)(v);
17
+ }
18
+ var HttpServerRequest;
19
+ (function (HttpServerRequest) {
20
+ function create(instance) {
21
+ if (!isHttpIncomingMessage(instance))
22
+ instance = http_incoming_message_host_js_1.HttpIncomingMessageHost.create(instance);
23
+ (0, common_1.mergePrototype)(instance, HttpServerRequestHost.prototype);
24
+ return instance;
25
+ }
26
+ HttpServerRequest.create = create;
27
+ })(HttpServerRequest || (exports.HttpServerRequest = HttpServerRequest = {}));
28
+ class HttpServerRequestHost {
29
+ get protocol() {
30
+ const proto = this.header('X-Forwarded-Proto') || 'http';
31
+ const index = proto.indexOf(',');
32
+ return index !== -1
33
+ ? proto.substring(0, index).trim()
34
+ : proto.trim();
35
+ }
36
+ get secure() {
37
+ return this.protocol === 'https';
38
+ }
39
+ get hostname() {
40
+ let host = this.get('X-Forwarded-Host');
41
+ if (!host) {
42
+ host = this.get('Host');
43
+ }
44
+ else if (host.indexOf(',') !== -1) {
45
+ // Note: X-Forwarded-Host is normally only ever a
46
+ // single value, but this is to be safe.
47
+ host = host.substring(0, host.indexOf(',')).trim();
48
+ }
49
+ if (!host)
50
+ return;
51
+ // IPv6 literal support
52
+ const offset = host[0] === '['
53
+ ? host.indexOf(']') + 1
54
+ : 0;
55
+ const index = host.indexOf(':', offset);
56
+ return index !== -1
57
+ ? host.substring(0, index)
58
+ : host;
59
+ }
60
+ get fresh() {
61
+ const method = this.method;
62
+ // GET or HEAD for weak freshness validation only
63
+ if ('GET' !== method && 'HEAD' !== method)
64
+ return false;
65
+ const status = this.res?.statusCode;
66
+ // 2xx or 304 as per rfc2616 14.26
67
+ if ((status >= 200 && status < 300) || 304 === status) {
68
+ return (0, fresh_1.default)(this.headers, {
69
+ 'etag': this.res.getHeader('ETag'),
70
+ 'last-modified': this.res.getHeader('Last-Modified')
71
+ });
72
+ }
73
+ return false;
74
+ }
75
+ get xhr() {
76
+ const val = this.get('X-Requested-With') || '';
77
+ return val.toLowerCase() === 'xmlhttprequest';
78
+ }
79
+ header(name) {
80
+ name = name.toLowerCase();
81
+ const headers = this.headers;
82
+ switch (name) {
83
+ case 'referer':
84
+ return headers.referer || headers.referrer;
85
+ case 'referrer':
86
+ return headers.referrer || headers.referer;
87
+ default:
88
+ return headers[name];
89
+ }
90
+ }
91
+ get(name) {
92
+ return this.header(name);
93
+ }
94
+ accepts(...types) {
95
+ const accept = (0, accepts_1.default)(this);
96
+ return accept.types.call(accept, ...types);
97
+ }
98
+ acceptsCharsets(...charsets) {
99
+ const accept = (0, accepts_1.default)(this);
100
+ return accept.charsets.call(accept, ...charsets);
101
+ }
102
+ acceptsEncodings(...encoding) {
103
+ const accept = (0, accepts_1.default)(this);
104
+ // eslint-disable-next-line prefer-spread
105
+ return accept.encodings.apply(accept, encoding);
106
+ }
107
+ acceptsLanguages(...lang) {
108
+ const accept = (0, accepts_1.default)(this);
109
+ // eslint-disable-next-line prefer-spread
110
+ return accept.languages.apply(accept, lang);
111
+ }
112
+ is(type, ...otherTypes) {
113
+ const types = Array.isArray(type) ? type : [type];
114
+ if (otherTypes.length)
115
+ types.push(...otherTypes);
116
+ const contentType = this.header('content-type');
117
+ return contentType ? type_is_1.default.is(contentType, types) : null;
118
+ }
119
+ range(size, options) {
120
+ const range = this.header('range');
121
+ if (!range)
122
+ return;
123
+ return (0, range_parser_1.default)(size, range, options);
124
+ }
125
+ }
@@ -0,0 +1,226 @@
1
+ "use strict";
2
+ /*
3
+ Some parts of this file contains codes from open source express library
4
+ https://github.com/expressjs
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.HttpServerResponse = void 0;
8
+ const tslib_1 = require("tslib");
9
+ const content_disposition_1 = tslib_1.__importDefault(require("content-disposition"));
10
+ const content_type_1 = tslib_1.__importDefault(require("content-type"));
11
+ const cookie_1 = tslib_1.__importDefault(require("cookie"));
12
+ const cookie_signature_1 = tslib_1.__importDefault(require("cookie-signature"));
13
+ const encodeurl_1 = tslib_1.__importDefault(require("encodeurl"));
14
+ const mime_types_1 = tslib_1.__importDefault(require("mime-types"));
15
+ const path_1 = tslib_1.__importDefault(require("path"));
16
+ const putil_varhelpers_1 = require("putil-varhelpers");
17
+ const vary_1 = tslib_1.__importDefault(require("vary"));
18
+ const common_1 = require("@opra/common");
19
+ const http_outgoing_message_host_js_1 = require("./http-outgoing-message-host.js");
20
+ const charsetRegExp = /;\s*charset\s*=/;
21
+ function isHttpIncomingMessage(v) {
22
+ return v && typeof v.getHeaders === 'function' && (0, common_1.isStream)(v);
23
+ }
24
+ var HttpServerResponse;
25
+ (function (HttpServerResponse) {
26
+ function create(instance) {
27
+ if (!isHttpIncomingMessage(instance))
28
+ instance = http_outgoing_message_host_js_1.HttpOutgoingMessageHost.create(instance);
29
+ (0, common_1.mergePrototype)(instance, HttpServerResponseHost.prototype);
30
+ return instance;
31
+ }
32
+ HttpServerResponse.create = create;
33
+ })(HttpServerResponse || (exports.HttpServerResponse = HttpServerResponse = {}));
34
+ class HttpServerResponseHost {
35
+ attachment(filename) {
36
+ if (filename)
37
+ this.contentType(path_1.default.extname(filename));
38
+ this.setHeader('Content-Disposition', (0, content_disposition_1.default)(filename));
39
+ return this;
40
+ }
41
+ contentType(type) {
42
+ const ct = type.indexOf('/') === -1
43
+ ? mime_types_1.default.lookup(type)
44
+ : type;
45
+ this.setHeader('Content-Type', ct);
46
+ return this;
47
+ }
48
+ setHeader(field, val) {
49
+ const setHeader = Object.getPrototypeOf(this).setHeader;
50
+ if (typeof field === 'string') {
51
+ let value = Array.isArray(val)
52
+ ? val.map(String)
53
+ : (val ? String(val) : '');
54
+ // add charset to content-type
55
+ if (field.toLowerCase() === 'content-type') {
56
+ if (Array.isArray(value)) {
57
+ throw new TypeError('Content-Type cannot be set to an Array');
58
+ }
59
+ if (!charsetRegExp.test(value)) {
60
+ const charset = mime_types_1.default.charsets.lookup(value.split(';')[0]);
61
+ if (charset)
62
+ value += '; charset=' + charset.toLowerCase();
63
+ }
64
+ }
65
+ setHeader.call(this, field, value);
66
+ }
67
+ else {
68
+ for (const [k, v] of Object.entries(field)) {
69
+ this.setHeader(k, v);
70
+ }
71
+ }
72
+ return this;
73
+ }
74
+ clearCookie(name, options) {
75
+ const opts = {
76
+ expires: new Date(1),
77
+ path: '/',
78
+ ...options
79
+ };
80
+ return this.cookie(name, '', opts);
81
+ }
82
+ cookie(name, value, options) {
83
+ const opts = { ...options };
84
+ let val = typeof value === 'object'
85
+ ? 'j:' + JSON.stringify(value)
86
+ : String(value);
87
+ if (opts.signed) {
88
+ const secret = opts.secret || this.req?.secret;
89
+ if (!secret)
90
+ throw new Error('"secret" required for signed cookies');
91
+ val = 's:' + cookie_signature_1.default.sign(val, secret);
92
+ }
93
+ if (opts.maxAge != null) {
94
+ const maxAge = opts.maxAge - 0;
95
+ if (!isNaN(maxAge)) {
96
+ opts.expires = new Date(Date.now() + maxAge);
97
+ opts.maxAge = Math.floor(maxAge / 1000);
98
+ }
99
+ }
100
+ if (opts.path == null)
101
+ opts.path = '/';
102
+ this.appendHeader('Set-Cookie', cookie_1.default.serialize(name, String(val), opts));
103
+ return this;
104
+ }
105
+ status(code) {
106
+ this.statusCode = code;
107
+ return this;
108
+ }
109
+ sendStatus(statusCode) {
110
+ const body = common_1.HttpStatusCodes[statusCode] || String(statusCode);
111
+ this.statusCode = statusCode;
112
+ this.contentType('txt');
113
+ return this.send(body);
114
+ }
115
+ links(links) {
116
+ let link = this.getHeader('Link') || '';
117
+ if (link)
118
+ link += ', ';
119
+ this.setHeader('Link', link +
120
+ Object.keys(links)
121
+ .map(rel => '<' + links[rel] + '>; rel="' + rel + '"')
122
+ .join(', '));
123
+ return this;
124
+ }
125
+ location(url) {
126
+ let loc = url;
127
+ // "back" is an alias for the referrer
128
+ if (url === 'back')
129
+ loc = this.req?.get('Referrer') || '/';
130
+ // set location
131
+ return this.setHeader('Location', (0, encodeurl_1.default)(loc));
132
+ }
133
+ redirect(arg0, arg1) {
134
+ const address = String(arg1 || arg0);
135
+ const status = typeof arg0 === 'number' ? arg0 : 302;
136
+ // Set location header
137
+ this.location(address);
138
+ // Respond
139
+ this.statusCode = status;
140
+ this.end();
141
+ }
142
+ send(body) {
143
+ let chunk = body;
144
+ let encoding;
145
+ const req = this.req;
146
+ let ctype = (0, putil_varhelpers_1.toString)(this.getHeader('Content-Type'));
147
+ if (typeof chunk !== 'string') {
148
+ if (chunk === null)
149
+ chunk = '';
150
+ else if (Buffer.isBuffer(chunk)) {
151
+ if (!ctype)
152
+ this.contentType('bin');
153
+ }
154
+ else {
155
+ ctype = 'json';
156
+ chunk = JSON.stringify(chunk);
157
+ }
158
+ }
159
+ // write strings in utf-8
160
+ if (typeof chunk === 'string') {
161
+ encoding = 'utf-8';
162
+ this.setHeader('Content-Type', setCharset(ctype || 'txt', encoding));
163
+ }
164
+ // populate Content-Length
165
+ let len = 0;
166
+ if (chunk !== undefined) {
167
+ if (Buffer.isBuffer(chunk)) {
168
+ // get length of Buffer
169
+ len = chunk.length;
170
+ }
171
+ else if (chunk.length < 1000) {
172
+ // just calculate length when small chunk
173
+ len = Buffer.byteLength(chunk, encoding);
174
+ }
175
+ else {
176
+ // convert chunk to Buffer and calculate
177
+ chunk = Buffer.from(chunk, encoding);
178
+ encoding = undefined;
179
+ len = chunk.length;
180
+ }
181
+ this.setHeader('Content-Length', len);
182
+ }
183
+ // freshness
184
+ if (req?.fresh)
185
+ this.statusCode = 304;
186
+ // strip irrelevant headers
187
+ if (204 === this.statusCode || 304 === this.statusCode) {
188
+ this.removeHeader('Content-Type');
189
+ this.removeHeader('Content-Length');
190
+ this.removeHeader('Transfer-Encoding');
191
+ chunk = '';
192
+ }
193
+ // alter headers for 205
194
+ if (this.statusCode === 205) {
195
+ this.setHeader('Content-Length', '0');
196
+ this.removeHeader('Transfer-Encoding');
197
+ chunk = '';
198
+ }
199
+ if (req?.method === 'HEAD') {
200
+ // skip body for HEAD
201
+ this.end();
202
+ }
203
+ else {
204
+ // respond
205
+ if (encoding)
206
+ this.end(chunk, encoding);
207
+ else
208
+ this.end(chunk);
209
+ }
210
+ return this;
211
+ }
212
+ vary(field) {
213
+ (0, vary_1.default)(this, field);
214
+ return this;
215
+ }
216
+ }
217
+ function setCharset(type, charset) {
218
+ if (!(type && charset))
219
+ return type;
220
+ // parse type
221
+ const parsed = content_type_1.default.parse(type);
222
+ // set charset
223
+ parsed.parameters.charset = charset;
224
+ // format type
225
+ return content_type_1.default.format(parsed);
226
+ }