@@ -226,13 +226,39 @@ private function createUri(ResponseInterface $redirectResponse, RequestInterface
226226 $ location = $ redirectResponse ->getHeaderLine ('Location ' );
227227 $ parsedLocation = parse_url ($ location );
228228
229- if (false === $ parsedLocation ) {
230- throw new HttpException (sprintf ('Location %s could not be parsed ' , $ location ), $ originalRequest , $ redirectResponse );
229+ if (false === $ parsedLocation || '' === $ location ) {
230+ throw new HttpException (sprintf ('Location "%s" could not be parsed ' , $ location ), $ originalRequest , $ redirectResponse );
231231 }
232232
233233 $ uri = $ originalRequest ->getUri ();
234+
235+ // Redirections can either use an absolute uri or a relative reference https://www.rfc-editor.org/rfc/rfc3986#section-4.2
236+ // If relative, we need to check if we have an absolute path or not
237+
238+ $ path = array_key_exists ('path ' , $ parsedLocation ) ? $ parsedLocation ['path ' ] : '' ;
239+ if (!array_key_exists ('host ' , $ parsedLocation ) && '/ ' !== $ location [0 ]) {
240+ // the target is a relative-path reference, we need to merge it with the base path
241+ $ originalPath = $ uri ->getPath ();
242+ if ('' === $ path ) {
243+ $ path = $ originalPath ;
244+ } elseif (($ pos = strrpos ($ originalPath , '/ ' )) !== false ) {
245+ $ path = substr ($ originalPath , 0 , $ pos +1 ).$ path ;
246+ } else {
247+ $ path = '/ ' .$ path ;
248+ }
249+ /* replace '/./' or '/foo/../' with '/' */
250+ $ re = ['#(/\./)# ' , '#/(?!\.\.)[^/]+/\.\./# ' ];
251+ for ($ n = 1 ; $ n > 0 ; $ path = preg_replace ($ re , '/ ' , $ path , -1 , $ n )) {
252+ if (null === $ path ) {
253+ throw new HttpException (sprintf ('Failed to resolve Location %s ' , $ location ), $ originalRequest , $ redirectResponse );
254+ }
255+ }
256+ }
257+ if (null === $ path ) {
258+ throw new HttpException (sprintf ('Failed to resolve Location %s ' , $ location ), $ originalRequest , $ redirectResponse );
259+ }
234260 $ uri = $ uri
235- ->withPath (array_key_exists ( ' path ' , $ parsedLocation ) ? $ parsedLocation [ ' path ' ] : '' )
261+ ->withPath ($ path )
236262 ->withQuery (array_key_exists ('query ' , $ parsedLocation ) ? $ parsedLocation ['query ' ] : '' )
237263 ->withFragment (array_key_exists ('fragment ' , $ parsedLocation ) ? $ parsedLocation ['fragment ' ] : '' )
238264 ;
@@ -247,6 +273,8 @@ private function createUri(ResponseInterface $redirectResponse, RequestInterface
247273
248274 if (array_key_exists ('port ' , $ parsedLocation )) {
249275 $ uri = $ uri ->withPort ($ parsedLocation ['port ' ]);
276+ } elseif (array_key_exists ('host ' , $ parsedLocation )) {
277+ $ uri = $ uri ->withPort (null );
250278 }
251279
252280 return $ uri ;
0 commit comments