Skip to content

Commit e377812

Browse files
committed
Redirection http redirection across different hosts
Signed-off-by: Paolo Di Tommaso <[email protected]>
1 parent dd32f80 commit e377812

File tree

3 files changed

+28
-23
lines changed

3 files changed

+28
-23
lines changed

modules/nf-httpfs/src/main/nextflow/file/http/XFileSystemProvider.groovy

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ abstract class XFileSystemProvider extends FileSystemProvider {
6464

6565
private Map<URI, FileSystem> fileSystemMap = new LinkedHashMap<>(20)
6666

67+
private static final int[] REDIRECT_CODES = [301, 302, 307, 308]
6768

6869
protected static String config(String name, def defValue) {
6970
return SysEnv.containsKey(name) ? SysEnv.get(name) : defValue.toString()
@@ -185,18 +186,25 @@ abstract class XFileSystemProvider extends FileSystemProvider {
185186
protected URLConnection toConnection0(URL url, int attempt) {
186187
final conn = url.openConnection()
187188
conn.setRequestProperty("User-Agent", 'Nextflow/httpfs')
189+
if( conn instanceof HttpURLConnection ) {
190+
// by default HttpURLConnection does redirect only within the same host
191+
// disable the built-in to implement custom redirection logic (see below)
192+
conn.setInstanceFollowRedirects(false)
193+
}
188194
if( url.userInfo ) {
189195
conn.setRequestProperty("Authorization", auth(url.userInfo));
190196
}
191197
else {
192198
XAuthRegistry.instance.authorize(conn)
193199
}
194-
if ( conn instanceof HttpURLConnection && conn.getResponseCode() in [307, 308] && attempt < MAX_REDIRECT_HOPS ) {
200+
if ( conn instanceof HttpURLConnection && conn.getResponseCode() in REDIRECT_CODES && attempt < MAX_REDIRECT_HOPS ) {
195201
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)
202+
final location = header.get("Location")?.get(0)
203+
final newUrl = new URI(location).toURL()
204+
if( url.protocol=='https' && newUrl.protocol=='http' )
205+
throw new IOException("Refuse to follow redirection from HTTPS to HTTP (unsafe) URL - origin: $url - target: $newUrl")
206+
log.debug "Remote redirect URL: $newUrl"
207+
return toConnection0(newUrl, attempt+1)
200208
}
201209
else if( conn instanceof HttpURLConnection && conn.getResponseCode() in config().retryCodes() && attempt < config().maxAttempts() ) {
202210
final delay = (Math.pow(config().backOffBase(), attempt) as long) * config().backOffDelay()

modules/nf-httpfs/src/test/nextflow/file/http/HttpFilesTests.groovy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ class HttpFilesTests extends Specification {
112112
def lines = Files.readAllLines(path, Charset.forName('UTF-8'))
113113
then:
114114
lines.size()>0
115-
lines[0] == '<html>'
115+
lines[0] == '<!DOCTYPE html>'
116116

117117
}
118118

modules/nf-httpfs/src/test/nextflow/file/http/XFileSystemProviderTest.groovy

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import java.nio.file.Path
2121

2222
import com.github.tomakehurst.wiremock.junit.WireMockRule
2323
import com.github.tomjankes.wiremock.WireMockGroovy
24-
import nextflow.SysEnv
2524
import org.junit.Rule
2625
import spock.lang.Specification
2726
import spock.lang.Unroll
@@ -106,7 +105,7 @@ class XFileSystemProviderTest extends Specification {
106105
when:
107106
def attrs = fsp.readHttpAttributes(path)
108107
then:
109-
attrs.lastModifiedTime() == null
108+
attrs.lastModifiedTime()
110109
attrs.size() > 0
111110
}
112111

@@ -157,6 +156,7 @@ class XFileSystemProviderTest extends Specification {
157156
@Rule
158157
WireMockRule wireMockRule = new WireMockRule(18080)
159158

159+
@Unroll
160160
def 'should follow a redirect when read a http file '() {
161161
given:
162162
def wireMock = new WireMockGroovy(18080)
@@ -180,14 +180,14 @@ class XFileSystemProviderTest extends Specification {
180180
response {
181181
status HTTP_CODE
182182
headers {
183-
"Location" "http://localhost:18080/redirected.html"
183+
"Location" "http://localhost:18080/target.html"
184184
}
185185
}
186186
}
187187
wireMock.stub {
188188
request {
189189
method "GET"
190-
url "/redirected.html"
190+
url "/target.html"
191191
}
192192
response {
193193
status 200
@@ -212,22 +212,19 @@ class XFileSystemProviderTest extends Specification {
212212
Files.size(path) == EXPECTED
213213

214214
where:
215-
HTTP_CODE | REDIRECT_TO | EXPECTED
216-
300 | "/redirected.html" | 10
217-
300 | "/index2.html" | 10
218-
219-
301 | "/redirected.html" | 10
220-
301 | "/index2.html" | 10
215+
HTTP_CODE | REDIRECT_TO | EXPECTED
216+
301 | "/target.html" | 10
217+
301 | "/index2.html" | 10
221218

222-
302 | "/redirected.html" | 10
223-
302 | "/index2.html" | 10
219+
302 | "/target.html" | 10
220+
302 | "/index2.html" | 10
224221

225-
307 | "/redirected.html" | 10
226-
307 | "/index2.html" | 10
222+
307 | "/target.html" | 10
223+
307 | "/index2.html" | 10
227224

228-
308 | "/redirected.html" | 10
229-
308 | "/index2.html" | 10
225+
308 | "/target.html" | 10
226+
308 | "/index2.html" | 10
230227
//infinite redirect to himself
231-
308 | "/index.html" | -1
228+
308 | "/index.html" | -1
232229
}
233230
}

0 commit comments

Comments
 (0)