1
1
import { Request , Router } from "express"
2
2
import { HttpCode , HttpError } from "../../common/http"
3
+ import { getHost } from "../http"
3
4
import { authenticated , ensureAuthenticated , ensureOrigin , redirect , self } from "../http"
4
5
import { proxy } from "../proxy"
5
6
import { Router as WsRouter } from "../wsRouter"
6
7
7
8
export const router = Router ( )
8
9
10
+ const proxyDomainToRegex = ( matchString : string ) : RegExp => {
11
+ let escapedMatchString = matchString . replace ( / [ . * + ? ^ $ ( ) | [ \] \\ ] / g, "\\$&" ) ;
12
+
13
+ // Replace {{port}} with a regex group to capture the port
14
+ // Replace {{host}} with .+ to allow any host match (so rely on DNS record here)
15
+ let regexString = escapedMatchString . replace ( "{{port}}" , "(\\d+)" ) ;
16
+ regexString = regexString . replace ( "{{host}}" , ".+" ) ;
17
+
18
+ regexString = regexString . replace ( / [ { } ] / g, "\\$&" ) ; //replace any '{}' that might be left
19
+
20
+ return new RegExp ( "^" + regexString + "$" ) ;
21
+ }
22
+
23
+ let proxyRegexes : RegExp [ ] = [ ] ;
24
+ const proxyDomainsToRegex = ( proxyDomains : string [ ] ) : RegExp [ ] => {
25
+ if ( proxyDomains . length != proxyRegexes . length ) {
26
+ proxyRegexes = proxyDomains . map ( proxyDomainToRegex ) ;
27
+ }
28
+ return proxyRegexes ;
29
+ }
9
30
10
31
/**
11
32
* Return the port if the request should be proxied. Anything that ends in a
@@ -16,56 +37,22 @@ export const router = Router()
16
37
* but `8080.test.coder.com` and `test.8080.coder.com` will not.
17
38
*/
18
39
const maybeProxy = ( req : Request ) : string | undefined => {
19
- // Split into parts.
20
- const host = req . headers . host || ""
21
- const idx = host . indexOf ( ":" )
22
- const domain = idx !== - 1 ? host . substring ( 0 , idx ) : host
23
- const parts = domain . split ( "." )
24
-
25
- // There must be an exact match for proxy-domain
26
- const port = parts . shift ( )
27
- const proxyDomain = parts . join ( "." )
28
- if ( port && req . args [ "proxy-domain" ] . includes ( proxyDomain ) ) {
29
- return port
30
- }
31
-
32
- // check based on VSCODE_PROXY_URI
33
- const proxyTemplate = process . env . VSCODE_PROXY_URI
34
- if ( proxyTemplate ) {
35
- return matchVsCodeProxyUriAndExtractPort ( proxyTemplate , domain )
40
+ let reqDomain = getHost ( req ) ;
41
+ if ( reqDomain === undefined ) {
42
+ return undefined ;
36
43
}
37
-
38
- return undefined
39
- }
40
-
41
-
42
- let regex : RegExp | undefined = undefined ;
43
- const matchVsCodeProxyUriAndExtractPort = ( matchString : string , domain : string ) : string | undefined => {
44
- // init regex on first use
45
- if ( ! regex ) {
46
- // Escape dot characters in the match string
47
- let escapedMatchString = matchString . replace ( / \. / g, "\\." ) ;
48
-
49
- // Replace {{port}} with a regex group to capture the port
50
- let regexString = escapedMatchString . replace ( "{{port}}" , "(\\d+)" ) ;
51
44
52
- // remove http:// and https:// from matchString as protocol cannot be determined based on the Host header
53
- regexString = regexString . replace ( "https://" , "" ) . replace ( "http://" , "" ) ;
45
+ let regexs = proxyDomainsToRegex ( req . args [ "proxy-domain" ] ) ;
54
46
55
- // Replace {{host}} with .* to allow any host match (so rely on DNS record here)
56
- regexString = regexString . replace ( "{{host}}" , ".*" ) ;
47
+ for ( let regex of regexs ) {
48
+ let match = reqDomain . match ( regex ) ;
57
49
58
- regex = new RegExp ( "^" + regexString + "$" ) ;
59
- }
60
-
61
- // Test the domain against the regex
62
- let match = domain . match ( regex ) ;
63
-
64
- if ( match ) {
65
- return match [ 1 ] ; // match[1] contains the port
50
+ if ( match ) {
51
+ return match [ 1 ] ; // match[1] contains the port
52
+ }
66
53
}
67
54
68
- return undefined ;
55
+ return undefined
69
56
}
70
57
71
58
router . all ( "*" , async ( req , res , next ) => {
0 commit comments