1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 | import {Context} from '@loopback/core';
|
7 | import {
|
8 | HandlerContext,
|
9 | MiddlewareContext,
|
10 | Request,
|
11 | Response,
|
12 | } from '@loopback/express';
|
13 | import {RestBindings} from './keys';
|
14 | import {RestServerResolvedConfig} from './rest.server';
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 | export class RequestContext
|
21 | extends MiddlewareContext
|
22 | implements HandlerContext
|
23 | {
|
24 | |
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 | get requestedProtocol(): string {
|
31 | return (
|
32 | ((this.request.get('x-forwarded-proto') ?? '').split(',')[0] ||
|
33 | this.request.protocol ||
|
34 | this.serverConfig.protocol) ??
|
35 | 'http'
|
36 | );
|
37 | }
|
38 |
|
39 | |
40 |
|
41 |
|
42 |
|
43 |
|
44 | get basePath(): string {
|
45 | const request = this.request;
|
46 | let basePath = this.serverConfig.basePath ?? '';
|
47 | if (request.baseUrl && request.baseUrl !== '/') {
|
48 | if (!basePath || request.baseUrl.endsWith(basePath)) {
|
49 |
|
50 | basePath = request.baseUrl;
|
51 | } else {
|
52 | basePath = request.baseUrl + basePath;
|
53 | }
|
54 | }
|
55 | return basePath;
|
56 | }
|
57 |
|
58 | |
59 |
|
60 |
|
61 |
|
62 |
|
63 |
|
64 |
|
65 |
|
66 | get requestedBaseUrl(): string {
|
67 | const request = this.request;
|
68 | const config = this.serverConfig;
|
69 |
|
70 | const protocol = this.requestedProtocol;
|
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 | let {host, port} = parseHostAndPort(
|
77 | request.get('x-forwarded-host') ?? request.headers.host,
|
78 | );
|
79 |
|
80 | const forwardedPort = (request.get('x-forwarded-port') ?? '').split(',')[0];
|
81 | port = forwardedPort || port;
|
82 |
|
83 | if (!host) {
|
84 |
|
85 |
|
86 | host = config.host ?? request.socket.localAddress ?? '';
|
87 | port = ((config.port || request.socket.localPort) ?? '').toString();
|
88 | }
|
89 |
|
90 |
|
91 | port = protocol === 'https' && port === '443' ? '' : port;
|
92 | port = protocol === 'http' && port === '80' ? '' : port;
|
93 |
|
94 |
|
95 | host += port !== '' ? ':' + port : '';
|
96 |
|
97 | return protocol + '://' + host + this.basePath;
|
98 | }
|
99 |
|
100 | constructor(
|
101 | public readonly request: Request,
|
102 | public readonly response: Response,
|
103 | parent: Context,
|
104 | public readonly serverConfig: RestServerResolvedConfig,
|
105 | name?: string,
|
106 | ) {
|
107 | super(request, response, parent, name);
|
108 | }
|
109 |
|
110 | protected setupBindings() {
|
111 | super.setupBindings();
|
112 | this.bind(RestBindings.Http.REQUEST).to(this.request).lock();
|
113 | this.bind(RestBindings.Http.RESPONSE).to(this.response).lock();
|
114 | this.bind(RestBindings.Http.CONTEXT).to(this).lock();
|
115 | }
|
116 | }
|
117 |
|
118 | function parseHostAndPort(host: string | undefined) {
|
119 | host = host ?? '';
|
120 | host = host.split(',')[0];
|
121 | const portPattern = /:([0-9]+)$/;
|
122 | const port = (host.match(portPattern) ?? [])[1] || '';
|
123 | host = host.replace(portPattern, '');
|
124 | return {host, port};
|
125 | }
|