@opra/core 0.20.1 → 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.
- package/cjs/adapter/adapter.js +2 -2
- package/cjs/adapter/http/express-adapter.js +29 -7
- package/cjs/adapter/http/helpers/common.js +66 -0
- package/cjs/adapter/http/helpers/convert-to-headers.js +65 -0
- package/cjs/adapter/http/helpers/convert-to-raw-headers.js +25 -0
- package/cjs/adapter/http/helpers/match-known-fields.js +47 -0
- package/cjs/adapter/http/http-adapter.js +76 -438
- package/cjs/adapter/http/impl/http-incoming-message-host.js +127 -0
- package/cjs/adapter/http/impl/http-outgoing-message-host.js +210 -0
- package/cjs/adapter/http/impl/http-server-request.js +125 -0
- package/cjs/adapter/http/impl/http-server-response.js +226 -0
- package/cjs/adapter/http/request-parsers/batch-request-parser.js +169 -0
- package/cjs/adapter/http/request-parsers/parse-collection-request.js +165 -0
- package/cjs/adapter/http/request-parsers/parse-request.js +24 -0
- package/cjs/adapter/http/request-parsers/parse-singleton-request.js +96 -0
- package/cjs/adapter/request-context.host.js +17 -3
- package/cjs/adapter/request.host.js +6 -3
- package/cjs/adapter/response.host.js +5 -3
- package/cjs/index.js +4 -2
- package/esm/adapter/adapter.js +2 -2
- package/esm/adapter/http/express-adapter.js +6 -6
- package/esm/adapter/http/helpers/common.js +60 -0
- package/esm/adapter/http/helpers/convert-to-headers.js +60 -0
- package/esm/adapter/http/helpers/convert-to-raw-headers.js +21 -0
- package/esm/adapter/http/helpers/match-known-fields.js +43 -0
- package/esm/adapter/http/http-adapter.js +77 -439
- package/esm/adapter/http/impl/http-incoming-message-host.js +122 -0
- package/esm/adapter/http/impl/http-outgoing-message-host.js +205 -0
- package/esm/adapter/http/impl/http-server-request.js +121 -0
- package/esm/adapter/http/impl/http-server-response.js +222 -0
- package/esm/adapter/http/request-parsers/batch-request-parser.js +169 -0
- package/esm/adapter/http/request-parsers/parse-collection-request.js +161 -0
- package/esm/adapter/http/request-parsers/parse-request.js +20 -0
- package/esm/adapter/http/request-parsers/parse-singleton-request.js +92 -0
- package/esm/adapter/request-context.host.js +17 -3
- package/esm/adapter/request.host.js +6 -3
- package/esm/adapter/response.host.js +5 -3
- package/esm/index.js +4 -2
- package/package.json +20 -16
- package/types/adapter/adapter.d.ts +1 -1
- package/types/adapter/http/helpers/common.d.ts +17 -0
- package/types/adapter/http/helpers/convert-to-headers.d.ts +2 -0
- package/types/adapter/http/helpers/convert-to-raw-headers.d.ts +3 -0
- package/types/adapter/http/helpers/match-known-fields.d.ts +6 -0
- package/types/adapter/http/http-adapter.d.ts +7 -12
- package/types/adapter/http/impl/http-incoming-message-host.d.ts +58 -0
- package/types/adapter/http/impl/http-outgoing-message-host.d.ts +72 -0
- package/types/adapter/http/{http-request-message.d.ts → impl/http-server-request.d.ts} +52 -85
- package/types/adapter/http/impl/http-server-response.d.ts +137 -0
- package/types/adapter/http/request-parsers/batch-request-parser.d.ts +0 -0
- package/types/adapter/http/request-parsers/parse-collection-request.d.ts +4 -0
- package/types/adapter/http/request-parsers/parse-request.d.ts +4 -0
- package/types/adapter/http/request-parsers/parse-singleton-request.d.ts +4 -0
- package/types/adapter/interfaces/request-context.interface.d.ts +14 -10
- package/types/adapter/interfaces/request.interface.d.ts +3 -2
- package/types/adapter/interfaces/response.interface.d.ts +2 -2
- package/types/adapter/request-context.host.d.ts +9 -6
- package/types/adapter/request.host.d.ts +8 -4
- package/types/adapter/response.host.d.ts +6 -4
- package/types/index.d.ts +4 -2
- package/cjs/adapter/http/http-message.host.js +0 -251
- package/cjs/adapter/http/http-request-context.host.js +0 -28
- package/cjs/adapter/http/http-request-message.js +0 -152
- package/cjs/adapter/http/http-request.host.js +0 -14
- package/cjs/adapter/http/http-response-message.js +0 -238
- package/cjs/adapter/http/http-response.host.js +0 -14
- package/esm/adapter/http/http-message.host.js +0 -246
- package/esm/adapter/http/http-request-context.host.js +0 -24
- package/esm/adapter/http/http-request-message.js +0 -148
- package/esm/adapter/http/http-request.host.js +0 -10
- package/esm/adapter/http/http-response-message.js +0 -233
- package/esm/adapter/http/http-response.host.js +0 -10
- package/types/adapter/http/http-message.host.d.ts +0 -122
- package/types/adapter/http/http-request-context.host.d.ts +0 -16
- package/types/adapter/http/http-request.host.d.ts +0 -7
- package/types/adapter/http/http-response-message.d.ts +0 -321
- 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
|
+
}
|