UNPKG

12.2 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.ExpressAdapter = void 0;
4const common_1 = require("@nestjs/common");
5const shared_utils_1 = require("@nestjs/common/utils/shared.utils");
6const http_adapter_1 = require("@nestjs/core/adapters/http-adapter");
7const router_method_factory_1 = require("@nestjs/core/helpers/router-method-factory");
8const body_parser_1 = require("body-parser");
9const cors = require("cors");
10const express = require("express");
11const http = require("http");
12const https = require("https");
13const stream_1 = require("stream");
14const get_body_parser_options_util_1 = require("./utils/get-body-parser-options.util");
15class ExpressAdapter extends http_adapter_1.AbstractHttpAdapter {
16 constructor(instance) {
17 super(instance || express());
18 this.routerMethodFactory = new router_method_factory_1.RouterMethodFactory();
19 this.logger = new common_1.Logger(ExpressAdapter.name);
20 this.openConnections = new Set();
21 }
22 reply(response, body, statusCode) {
23 if (statusCode) {
24 response.status(statusCode);
25 }
26 if ((0, shared_utils_1.isNil)(body)) {
27 return response.send();
28 }
29 if (body instanceof common_1.StreamableFile) {
30 const streamHeaders = body.getHeaders();
31 if (response.getHeader('Content-Type') === undefined &&
32 streamHeaders.type !== undefined) {
33 response.setHeader('Content-Type', streamHeaders.type);
34 }
35 if (response.getHeader('Content-Disposition') === undefined &&
36 streamHeaders.disposition !== undefined) {
37 response.setHeader('Content-Disposition', streamHeaders.disposition);
38 }
39 if (response.getHeader('Content-Length') === undefined &&
40 streamHeaders.length !== undefined) {
41 response.setHeader('Content-Length', streamHeaders.length);
42 }
43 return (0, stream_1.pipeline)(body.getStream().once('error', (err) => {
44 body.errorHandler(err, response);
45 }), response, (err) => {
46 if (err) {
47 this.logger.error(err.message, err.stack);
48 }
49 });
50 }
51 return (0, shared_utils_1.isObject)(body) ? response.json(body) : response.send(String(body));
52 }
53 status(response, statusCode) {
54 return response.status(statusCode);
55 }
56 end(response, message) {
57 return response.end(message);
58 }
59 render(response, view, options) {
60 return response.render(view, options);
61 }
62 redirect(response, statusCode, url) {
63 return response.redirect(statusCode, url);
64 }
65 setErrorHandler(handler, prefix) {
66 return this.use(handler);
67 }
68 setNotFoundHandler(handler, prefix) {
69 return this.use(handler);
70 }
71 isHeadersSent(response) {
72 return response.headersSent;
73 }
74 setHeader(response, name, value) {
75 return response.set(name, value);
76 }
77 listen(port, ...args) {
78 return this.httpServer.listen(port, ...args);
79 }
80 close() {
81 this.closeOpenConnections();
82 if (!this.httpServer) {
83 return undefined;
84 }
85 return new Promise(resolve => this.httpServer.close(resolve));
86 }
87 set(...args) {
88 return this.instance.set(...args);
89 }
90 enable(...args) {
91 return this.instance.enable(...args);
92 }
93 disable(...args) {
94 return this.instance.disable(...args);
95 }
96 engine(...args) {
97 return this.instance.engine(...args);
98 }
99 useStaticAssets(path, options) {
100 if (options && options.prefix) {
101 return this.use(options.prefix, express.static(path, options));
102 }
103 return this.use(express.static(path, options));
104 }
105 setBaseViewsDir(path) {
106 return this.set('views', path);
107 }
108 setViewEngine(engine) {
109 return this.set('view engine', engine);
110 }
111 getRequestHostname(request) {
112 return request.hostname;
113 }
114 getRequestMethod(request) {
115 return request.method;
116 }
117 getRequestUrl(request) {
118 return request.originalUrl;
119 }
120 enableCors(options) {
121 return this.use(cors(options));
122 }
123 createMiddlewareFactory(requestMethod) {
124 return this.routerMethodFactory
125 .get(this.instance, requestMethod)
126 .bind(this.instance);
127 }
128 initHttpServer(options) {
129 const isHttpsEnabled = options && options.httpsOptions;
130 if (isHttpsEnabled) {
131 this.httpServer = https.createServer(options.httpsOptions, this.getInstance());
132 }
133 else {
134 this.httpServer = http.createServer(this.getInstance());
135 }
136 if (options === null || options === void 0 ? void 0 : options.forceCloseConnections) {
137 this.trackOpenConnections();
138 }
139 }
140 registerParserMiddleware(prefix, rawBody) {
141 const bodyParserJsonOptions = (0, get_body_parser_options_util_1.getBodyParserOptions)(rawBody);
142 const bodyParserUrlencodedOptions = (0, get_body_parser_options_util_1.getBodyParserOptions)(rawBody, { extended: true });
143 const parserMiddleware = {
144 jsonParser: (0, body_parser_1.json)(bodyParserJsonOptions),
145 urlencodedParser: (0, body_parser_1.urlencoded)(bodyParserUrlencodedOptions),
146 };
147 Object.keys(parserMiddleware)
148 .filter(parser => !this.isMiddlewareApplied(parser))
149 .forEach(parserKey => this.use(parserMiddleware[parserKey]));
150 }
151 setLocal(key, value) {
152 this.instance.locals[key] = value;
153 return this;
154 }
155 getType() {
156 return 'express';
157 }
158 applyVersionFilter(handler, version, versioningOptions) {
159 const callNextHandler = (req, res, next) => {
160 if (!next) {
161 throw new common_1.InternalServerErrorException('HTTP adapter does not support filtering on version');
162 }
163 return next();
164 };
165 if (version === common_1.VERSION_NEUTRAL ||
166 // URL Versioning is done via the path, so the filter continues forward
167 versioningOptions.type === common_1.VersioningType.URI) {
168 const handlerForNoVersioning = (req, res, next) => handler(req, res, next);
169 return handlerForNoVersioning;
170 }
171 // Custom Extractor Versioning Handler
172 if (versioningOptions.type === common_1.VersioningType.CUSTOM) {
173 const handlerForCustomVersioning = (req, res, next) => {
174 const extractedVersion = versioningOptions.extractor(req);
175 if (Array.isArray(version)) {
176 if (Array.isArray(extractedVersion) &&
177 version.filter(v => extractedVersion.includes(v)).length) {
178 return handler(req, res, next);
179 }
180 if ((0, shared_utils_1.isString)(extractedVersion) &&
181 version.includes(extractedVersion)) {
182 return handler(req, res, next);
183 }
184 }
185 else if ((0, shared_utils_1.isString)(version)) {
186 // Known bug here - if there are multiple versions supported across separate
187 // handlers/controllers, we can't select the highest matching handler.
188 // Since this code is evaluated per-handler, then we can't see if the highest
189 // specified version exists in a different handler.
190 if (Array.isArray(extractedVersion) &&
191 extractedVersion.includes(version)) {
192 return handler(req, res, next);
193 }
194 if ((0, shared_utils_1.isString)(extractedVersion) && version === extractedVersion) {
195 return handler(req, res, next);
196 }
197 }
198 return callNextHandler(req, res, next);
199 };
200 return handlerForCustomVersioning;
201 }
202 // Media Type (Accept Header) Versioning Handler
203 if (versioningOptions.type === common_1.VersioningType.MEDIA_TYPE) {
204 const handlerForMediaTypeVersioning = (req, res, next) => {
205 var _a, _b;
206 const MEDIA_TYPE_HEADER = 'Accept';
207 const acceptHeaderValue = ((_a = req.headers) === null || _a === void 0 ? void 0 : _a[MEDIA_TYPE_HEADER]) ||
208 ((_b = req.headers) === null || _b === void 0 ? void 0 : _b[MEDIA_TYPE_HEADER.toLowerCase()]);
209 const acceptHeaderVersionParameter = acceptHeaderValue
210 ? acceptHeaderValue.split(';')[1]
211 : undefined;
212 // No version was supplied
213 if ((0, shared_utils_1.isUndefined)(acceptHeaderVersionParameter)) {
214 if (Array.isArray(version)) {
215 if (version.includes(common_1.VERSION_NEUTRAL)) {
216 return handler(req, res, next);
217 }
218 }
219 }
220 else {
221 const headerVersion = acceptHeaderVersionParameter.split(versioningOptions.key)[1];
222 if (Array.isArray(version)) {
223 if (version.includes(headerVersion)) {
224 return handler(req, res, next);
225 }
226 }
227 else if ((0, shared_utils_1.isString)(version)) {
228 if (version === headerVersion) {
229 return handler(req, res, next);
230 }
231 }
232 }
233 return callNextHandler(req, res, next);
234 };
235 return handlerForMediaTypeVersioning;
236 }
237 // Header Versioning Handler
238 if (versioningOptions.type === common_1.VersioningType.HEADER) {
239 const handlerForHeaderVersioning = (req, res, next) => {
240 var _a, _b;
241 const customHeaderVersionParameter = ((_a = req.headers) === null || _a === void 0 ? void 0 : _a[versioningOptions.header]) ||
242 ((_b = req.headers) === null || _b === void 0 ? void 0 : _b[versioningOptions.header.toLowerCase()]);
243 // No version was supplied
244 if ((0, shared_utils_1.isUndefined)(customHeaderVersionParameter)) {
245 if (Array.isArray(version)) {
246 if (version.includes(common_1.VERSION_NEUTRAL)) {
247 return handler(req, res, next);
248 }
249 }
250 }
251 else {
252 if (Array.isArray(version)) {
253 if (version.includes(customHeaderVersionParameter)) {
254 return handler(req, res, next);
255 }
256 }
257 else if ((0, shared_utils_1.isString)(version)) {
258 if (version === customHeaderVersionParameter) {
259 return handler(req, res, next);
260 }
261 }
262 }
263 return callNextHandler(req, res, next);
264 };
265 return handlerForHeaderVersioning;
266 }
267 }
268 trackOpenConnections() {
269 this.httpServer.on('connection', (socket) => {
270 this.openConnections.add(socket);
271 socket.on('close', () => this.openConnections.delete(socket));
272 });
273 }
274 closeOpenConnections() {
275 for (const socket of this.openConnections) {
276 socket.destroy();
277 this.openConnections.delete(socket);
278 }
279 }
280 isMiddlewareApplied(name) {
281 const app = this.getInstance();
282 return (!!app._router &&
283 !!app._router.stack &&
284 (0, shared_utils_1.isFunction)(app._router.stack.filter) &&
285 app._router.stack.some((layer) => layer && layer.handle && layer.handle.name === name));
286 }
287}
288exports.ExpressAdapter = ExpressAdapter;