1616
1717package nextflow.file.http
1818
19+ import static nextflow.file.http.XFileSystemConfig.*
20+
1921import java.nio.ByteBuffer
2022import java.nio.channels.SeekableByteChannel
2123import java.nio.file.AccessDeniedException
@@ -44,13 +46,9 @@ import groovy.transform.PackageScope
4446import groovy.util.logging.Slf4j
4547import nextflow.SysEnv
4648import nextflow.extension.FilesEx
49+ import nextflow.file.FileHelper
4750import nextflow.util.InsensitiveMap
4851import sun.net.www.protocol.ftp.FtpURLConnection
49-
50- import static XFileSystemConfig.*
51-
52- import static nextflow.file.http.XFileSystemConfig.config
53-
5452/**
5553 * Implements a read-only JSR-203 compliant file system provider for http/ftp protocols
5654 *
@@ -64,6 +62,7 @@ abstract class XFileSystemProvider extends FileSystemProvider {
6462
6563 private Map<URI , FileSystem > fileSystemMap = new LinkedHashMap<> (20 )
6664
65+ private static final int [] REDIRECT_CODES = [301 , 302 , 307 , 308 ]
6766
6867 protected static String config (String name , def defValue ) {
6968 return SysEnv . containsKey(name) ? SysEnv . get(name) : defValue. toString()
@@ -185,18 +184,25 @@ abstract class XFileSystemProvider extends FileSystemProvider {
185184 protected URLConnection toConnection0 (URL url , int attempt ) {
186185 final conn = url. openConnection()
187186 conn. setRequestProperty(" User-Agent" , ' Nextflow/httpfs' )
187+ if ( conn instanceof HttpURLConnection ) {
188+ // by default HttpURLConnection does redirect only within the same host
189+ // disable the built-in to implement custom redirection logic (see below)
190+ conn. setInstanceFollowRedirects(false )
191+ }
188192 if ( url. userInfo ) {
189193 conn. setRequestProperty(" Authorization" , auth(url. userInfo));
190194 }
191195 else {
192196 XAuthRegistry . instance. authorize(conn)
193197 }
194- if ( conn instanceof HttpURLConnection && conn. getResponseCode() in [ 307 , 308 ] && attempt < MAX_REDIRECT_HOPS ) {
198+ if ( conn instanceof HttpURLConnection && conn. getResponseCode() in REDIRECT_CODES && attempt < MAX_REDIRECT_HOPS ) {
195199 final header = InsensitiveMap . of(conn. getHeaderFields())
196- String location = header. get(" Location" )?. get(0 )
197- URL newPath = new URI (location). toURL()
198- log. debug " Remote redirect URL: $newPath "
199- return toConnection0(newPath, attempt+1 )
200+ final location = header. get(" Location" )?. get(0 )
201+ log. debug " Remote redirect location: $location "
202+ final newUrl = new URI (absLocation(location,url)). toURL()
203+ if ( url. protocol== ' https' && newUrl. protocol== ' http' )
204+ throw new IOException (" Refuse to follow redirection from HTTPS to HTTP (unsafe) URL - origin: $url - target: $newUrl " )
205+ return toConnection0(newUrl, attempt+1 )
200206 }
201207 else if ( conn instanceof HttpURLConnection && conn. getResponseCode() in config(). retryCodes() && attempt < config(). maxAttempts() ) {
202208 final delay = (Math . pow(config(). backOffBase(), attempt) as long ) * config(). backOffDelay()
@@ -212,6 +218,18 @@ abstract class XFileSystemProvider extends FileSystemProvider {
212218 return conn
213219 }
214220
221+ protected String absLocation (String location , URL target ) {
222+ assert location, " Missing location argument"
223+ assert target, " Missing target URL argument"
224+
225+ final base = FileHelper . baseUrl(location)
226+ if ( base )
227+ return location
228+ if ( ! location. startsWith(' /' ) )
229+ location = ' /' + location
230+ return " ${ target.protocol} ://${ target.authority} $location "
231+ }
232+
215233 @Override
216234 SeekableByteChannel newByteChannel (Path path , Set<? extends OpenOption > options , FileAttribute<?> ... attrs ) throws IOException {
217235
0 commit comments