@@ -13,16 +13,29 @@ import https from 'https';
13
13
import zlib from 'zlib' ;
14
14
import Stream from 'stream' ;
15
15
16
- import Body , { writeToStream , getTotalBytes } from './body' ;
17
- import Response from './response' ;
18
- import Headers , { createHeadersLenient } from './headers' ;
19
- import Request , { getNodeRequestOptions } from './request' ;
20
- import FetchError from './fetch-error' ;
21
- import AbortError from './abort-error' ;
16
+ import Body , { writeToStream , getTotalBytes } from './body.js' ;
17
+ import Response from './response.js' ;
18
+ import Headers , { createHeadersLenient } from './headers.js' ;
19
+ import Request , { getNodeRequestOptions } from './request.js' ;
20
+ import FetchError from './fetch-error.js' ;
21
+ import AbortError from './abort-error.js' ;
22
+
23
+ import whatwgUrl from 'whatwg-url' ;
24
+
25
+ const URL = Url . URL || whatwgUrl . URL ;
22
26
23
27
// fix an issue where "PassThrough", "resolve" aren't a named export for node <10
24
28
const PassThrough = Stream . PassThrough ;
25
- const resolve_url = Url . resolve ;
29
+
30
+ const isDomainOrSubdomain = ( destination , original ) => {
31
+ const orig = new URL ( original ) . hostname ;
32
+ const dest = new URL ( destination ) . hostname ;
33
+
34
+ return orig === dest || (
35
+ orig [ orig . length - dest . length - 1 ] === '.' && orig . endsWith ( dest )
36
+ ) ;
37
+ } ;
38
+
26
39
27
40
/**
28
41
* Fetch function
@@ -109,7 +122,19 @@ export default function fetch(url, opts) {
109
122
const location = headers . get ( 'Location' ) ;
110
123
111
124
// HTTP fetch step 5.3
112
- const locationURL = location === null ? null : resolve_url ( request . url , location ) ;
125
+ let locationURL = null ;
126
+ try {
127
+ locationURL = location === null ? null : new URL ( location , request . url ) . toString ( ) ;
128
+ } catch ( err ) {
129
+ // error here can only be invalid URL in Location: header
130
+ // do not throw when options.redirect == manual
131
+ // let the user extract the errorneous redirect URL
132
+ if ( request . redirect !== 'manual' ) {
133
+ reject ( new FetchError ( `uri requested responds with an invalid redirect URL: ${ location } ` , 'invalid-redirect' ) ) ;
134
+ finalize ( ) ;
135
+ return ;
136
+ }
137
+ }
113
138
114
139
// HTTP fetch step 5.5
115
140
switch ( request . redirect ) {
@@ -154,9 +179,15 @@ export default function fetch(url, opts) {
154
179
body : request . body ,
155
180
signal : request . signal ,
156
181
timeout : request . timeout ,
157
- size : request . size
182
+ size : request . size
158
183
} ;
159
184
185
+ if ( ! isDomainOrSubdomain ( request . url , locationURL ) ) {
186
+ for ( const name of [ 'authorization' , 'www-authenticate' , 'cookie' , 'cookie2' ] ) {
187
+ requestOpts . headers . delete ( name ) ;
188
+ }
189
+ }
190
+
160
191
// HTTP-redirect fetch step 9
161
192
if ( res . statusCode !== 303 && request . body && getTotalBytes ( request ) === null ) {
162
193
reject ( new FetchError ( 'Cannot follow redirect with body being a readable stream' , 'unsupported-redirect' ) ) ;
0 commit comments