11import * as url from 'url' ;
22import * as domain from 'domain' ;
33import * as domainContext from 'domain-context' ;
4+ import * as isAbsoluteUrl from 'is-absolute-url' ;
45import { baseUrl } from './main' ;
56const isomorphicFetch = require ( 'isomorphic-fetch' ) ;
67const isNode = typeof process === 'object' && process . versions && ! ! process . versions . node ;
8+ const nodeHttps = isNode && require ( 'https' ) ;
79
810function issueRequest ( baseUrl : string , req : string | Request , init ?: RequestInit ) : Promise < any > {
11+ const reqUrl = ( req instanceof Request ) ? req . url : req ;
12+ const isRelativeUrl = reqUrl && ! isAbsoluteUrl ( reqUrl ) ;
13+
914 // Resolve relative URLs
1015 if ( baseUrl ) {
1116 if ( req instanceof Request ) {
@@ -25,9 +30,42 @@ function issueRequest(baseUrl: string, req: string | Request, init?: RequestInit
2530 ` ) ;
2631 }
2732
33+ init = applyHttpsAgentPolicy ( init , isRelativeUrl ) ;
2834 return isomorphicFetch ( req , init ) ;
2935}
3036
37+ function applyHttpsAgentPolicy ( init : RequestInit , isRelativeUrl : boolean ) : RequestInit {
38+ // HTTPS is awkward in Node because it uses a built-in list of CAs, rather than recognizing
39+ // the OS's system-level CA list. There are dozens of issues filed against Node about this,
40+ // but still (as of v8.0.0) no resolution besides manually duplicating your CA config.
41+ //
42+ // The biggest problem for typical isomorphic-SPA development this causes is that if you're
43+ // using a self-signed localhost cert in development, Node won't be able to make API calls
44+ // to it (e.g., https://github.com/aspnet/JavaScriptServices/issues/1089). Developers could
45+ // fix this by either manually configuring the cert in Node (which is extremely inconvenient,
46+ // especially if multiple devs on a team have different self-signed localhost certs), or by
47+ // disabling cert verification on their API requests.
48+ //
49+ // Fortunately, 'domain-task/fetch' knows when you're making a relative-URL request to your
50+ // own web server (as opposed to an arbitrary request to anywhere else). In this specific case,
51+ // there's no real point in cert verification, since the request never even leaves the machine
52+ // so a MitM attack isn't meaningful. So by default, when your code is running in Node and
53+ // is making a relative-URL request, *and* if you haven't explicitly configured any option
54+ // for 'agent' (which would let you set up other HTTPS-handling policies), then we automatically
55+ // disable cert verification for that request.
56+ if ( isNode && isRelativeUrl ) {
57+ const hasAgentConfig = init && ( 'agent' in init ) ;
58+ if ( ! hasAgentConfig ) {
59+ const agentForRequest = new ( nodeHttps . Agent ) ( { rejectUnauthorized : false } ) ;
60+
61+ init = init || { } ;
62+ ( init as any ) . agent = agentForRequest ;
63+ }
64+ }
65+
66+ return init ;
67+ }
68+
3169export function fetch ( url : string | Request , init ?: RequestInit ) : Promise < any > {
3270 // As of domain-task 2.0.0, we no longer auto-add the 'fetch' promise to the current domain task list.
3371 // This is because it's misleading to do so, and can result in race-condition bugs, e.g.,
0 commit comments