@@ -20,13 +20,8 @@ import urlToOptions from './utils/url-to-options';
2020import { RequestFunction , NormalizedOptions , Response , ResponseObject , AgentByProtocol } from './utils/types' ;
2121import dynamicRequire from './utils/dynamic-require' ;
2222
23- export type GetMethodRedirectCodes = 300 | 301 | 302 | 303 | 304 | 305 | 307 | 308 ;
24- export type AllMethodRedirectCodes = 300 | 303 | 307 | 308 ;
25- export type WithoutBody = 'GET' | 'HEAD' ;
26-
27- const getMethodRedirectCodes : ReadonlySet < GetMethodRedirectCodes > = new Set ( [ 300 , 301 , 302 , 303 , 304 , 305 , 307 , 308 ] ) ;
28- const allMethodRedirectCodes : ReadonlySet < AllMethodRedirectCodes > = new Set ( [ 300 , 303 , 307 , 308 ] ) ;
29- const withoutBody : ReadonlySet < WithoutBody > = new Set ( [ 'GET' , 'HEAD' ] ) ;
23+ const redirectCodes : ReadonlySet < number > = new Set ( [ 300 , 301 , 302 , 303 , 304 , 307 , 308 ] ) ;
24+ const withoutBody : ReadonlySet < string > = new Set ( [ 'GET' , 'HEAD' ] ) ;
3025
3126export interface RequestAsEventEmitter extends EventEmitter {
3227 retry : < T extends Error > ( error : T ) => boolean ;
@@ -143,46 +138,50 @@ export default (options: NormalizedOptions, input?: TransformStream) => {
143138 await Promise . all ( promises ) ;
144139 }
145140
146- if ( options . followRedirect && 'location' in typedResponse . headers ) {
147- if ( allMethodRedirectCodes . has ( statusCode as AllMethodRedirectCodes ) || ( getMethodRedirectCodes . has ( statusCode as GetMethodRedirectCodes ) && ( options . method === 'GET' || options . method === 'HEAD' ) ) ) {
148- typedResponse . resume ( ) ; // We're being redirected, we don't care about the response.
149-
150- if ( statusCode === 303 ) {
151- // Server responded with "see other", indicating that the resource exists at another location,
152- // and the client should request it from that location via GET or HEAD.
153- options . method = 'GET' ;
154- }
141+ if ( options . followRedirect && Reflect . has ( typedResponse . headers , 'location' ) && redirectCodes . has ( statusCode ) ) {
142+ typedResponse . resume ( ) ; // We're being redirected, we don't care about the response.
155143
156- if ( redirects . length >= options . maxRedirects ) {
157- throw new MaxRedirectsError ( typedResponse , options . maxRedirects , options ) ;
158- }
144+ if ( statusCode === 303 && options . method !== 'GET' && options . method !== 'HEAD' ) {
145+ // Server responded with "see other", indicating that the resource exists at another location,
146+ // and the client should request it from that location via GET or HEAD.
147+ options . method = 'GET' ;
159148
160- // Handles invalid URLs. See https://github.com/sindresorhus/got/issues/604
161- const redirectBuffer = Buffer . from ( typedResponse . headers . location , 'binary' ) . toString ( ) ;
162- const redirectURL = new URL ( redirectBuffer , currentUrl ) ;
163- redirectString = redirectURL . toString ( ) ;
149+ delete options . json ;
150+ delete options . form ;
151+ delete options . body ;
152+ }
164153
165- redirects . push ( redirectString ) ;
154+ if ( redirects . length >= options . maxRedirects ) {
155+ throw new MaxRedirectsError ( typedResponse , options . maxRedirects , options ) ;
156+ }
166157
167- const redirectOptions = {
168- ...options ,
169- port : undefined ,
170- auth : undefined ,
171- ...urlToOptions ( redirectURL )
172- } ;
158+ // Handles invalid URLs. See https://github.com/sindresorhus/got/issues/604
159+ const redirectBuffer = Buffer . from ( typedResponse . headers . location , 'binary' ) . toString ( ) ;
160+ const redirectURL = new URL ( redirectBuffer , currentUrl ) ;
161+ redirectString = redirectURL . toString ( ) ;
173162
174- for ( const hook of options . hooks . beforeRedirect ) {
175- // eslint-disable-next-line no-await-in-loop
176- await hook ( redirectOptions , typedResponse ) ;
177- }
163+ redirects . push ( redirectString ) ;
178164
179- emitter . emit ( 'redirect' , response , redirectOptions ) ;
165+ const redirectOptions = {
166+ ...options ,
167+ port : undefined ,
168+ auth : undefined ,
169+ ...urlToOptions ( redirectURL )
170+ } ;
180171
181- await get ( redirectOptions ) ;
182- return ;
172+ for ( const hook of options . hooks . beforeRedirect ) {
173+ // eslint-disable-next-line no-await-in-loop
174+ await hook ( redirectOptions , typedResponse ) ;
183175 }
176+
177+ emitter . emit ( 'redirect' , response , redirectOptions ) ;
178+
179+ await get ( redirectOptions ) ;
180+ return ;
184181 }
185182
183+ delete options . body ;
184+
186185 getResponse ( typedResponse , options , emitter ) ;
187186 } catch ( error ) {
188187 emitError ( error ) ;
@@ -362,7 +361,7 @@ export default (options: NormalizedOptions, input?: TransformStream) => {
362361 const isForm = ! is . nullOrUndefined ( options . form ) ;
363362 const isJSON = ! is . nullOrUndefined ( options . json ) ;
364363 const isBody = ! is . nullOrUndefined ( body ) ;
365- if ( ( isBody || isForm || isJSON ) && withoutBody . has ( options . method as WithoutBody ) ) {
364+ if ( ( isBody || isForm || isJSON ) && withoutBody . has ( options . method ) ) {
366365 throw new TypeError ( `The \`${ options . method } \` method cannot be used with a body` ) ;
367366 }
368367
0 commit comments