@@ -27,6 +27,9 @@ Fixed bugs: | |||
central repository didn't contain any source files. | |||
Bugzilla Report 65110 | |||
* The <http> condition didn't follow redirects from http to https. | |||
Bugzilla Report 65105 | |||
Other changes: | |||
-------------- | |||
@@ -533,6 +533,18 @@ public class Get extends Task { | |||
extends org.apache.tools.ant.util.Base64Converter { | |||
} | |||
/** | |||
* Does the response code represent a redirection? | |||
* | |||
* @since 1.10.10 | |||
*/ | |||
public static boolean isMoved(final int responseCode) { | |||
return responseCode == HttpURLConnection.HTTP_MOVED_PERM | |||
|| responseCode == HttpURLConnection.HTTP_MOVED_TEMP | |||
|| responseCode == HttpURLConnection.HTTP_SEE_OTHER | |||
|| responseCode == HTTP_MOVED_TEMP; | |||
} | |||
/** | |||
* Interface implemented for reporting | |||
* progress of downloading. | |||
@@ -815,13 +827,6 @@ public class Get extends Task { | |||
return connection; | |||
} | |||
private boolean isMoved(final int responseCode) { | |||
return responseCode == HttpURLConnection.HTTP_MOVED_PERM | |||
|| responseCode == HttpURLConnection.HTTP_MOVED_TEMP | |||
|| responseCode == HttpURLConnection.HTTP_SEE_OTHER | |||
|| responseCode == HTTP_MOVED_TEMP; | |||
} | |||
private boolean downloadFile() throws IOException { | |||
for (int i = 0; i < numberRetries; i++) { | |||
// this three attempt trick is to get round quirks in different | |||
@@ -30,6 +30,7 @@ import java.util.Locale; | |||
import org.apache.tools.ant.BuildException; | |||
import org.apache.tools.ant.Project; | |||
import org.apache.tools.ant.ProjectComponent; | |||
import org.apache.tools.ant.taskdefs.Get; | |||
/** | |||
* Condition to wait for a HTTP request to succeed. Its attribute(s) are: | |||
@@ -42,6 +43,8 @@ import org.apache.tools.ant.ProjectComponent; | |||
public class Http extends ProjectComponent implements Condition { | |||
private static final int ERROR_BEGINS = 400; | |||
private static final String DEFAULT_REQUEST_METHOD = "GET"; | |||
private static final String HTTP = "http"; | |||
private static final String HTTPS = "https"; | |||
private String spec = null; | |||
private String requestMethod = DEFAULT_REQUEST_METHOD; | |||
@@ -124,11 +127,7 @@ public class Http extends ProjectComponent implements Condition { | |||
try { | |||
URLConnection conn = url.openConnection(); | |||
if (conn instanceof HttpURLConnection) { | |||
HttpURLConnection http = (HttpURLConnection) conn; | |||
http.setRequestMethod(requestMethod); | |||
http.setInstanceFollowRedirects(followRedirects); | |||
http.setReadTimeout(readTimeout); | |||
int code = http.getResponseCode(); | |||
int code = request((HttpURLConnection) conn, url); | |||
log("Result code for " + spec + " was " + code, | |||
Project.MSG_VERBOSE); | |||
return code > 0 && code < errorsBeginAt; | |||
@@ -144,4 +143,39 @@ public class Http extends ProjectComponent implements Condition { | |||
} | |||
return true; | |||
} | |||
private int request(final HttpURLConnection http, final URL url) throws IOException { | |||
http.setRequestMethod(requestMethod); | |||
http.setInstanceFollowRedirects(followRedirects); | |||
http.setReadTimeout(readTimeout); | |||
final int firstStatusCode = http.getResponseCode(); | |||
if (Get.isMoved(firstStatusCode)) { | |||
final String newLocation = http.getHeaderField("Location"); | |||
final URL newURL = new URL(newLocation); | |||
if (redirectionAllowed(url, newURL)) { | |||
final URLConnection newConn = newURL.openConnection(); | |||
if (newConn instanceof HttpURLConnection) { | |||
log("Following redirect from " + url + " to " + newURL); | |||
return request((HttpURLConnection) newConn, newURL); | |||
} | |||
} | |||
} | |||
return firstStatusCode; | |||
} | |||
private boolean redirectionAllowed(final URL from, final URL to) { | |||
if (from.equals(to)) { | |||
// most simple case of an infinite redirect loop | |||
return false; | |||
} | |||
if (!(from.getProtocol().equals(to.getProtocol()) | |||
|| (HTTP.equals(from.getProtocol()) | |||
&& HTTPS.equals(to.getProtocol())))) { | |||
log("Redirection detected from " | |||
+ from.getProtocol() + " to " + to.getProtocol() | |||
+ ". Protocol switch unsafe, not allowed."); | |||
return false; | |||
} | |||
return true; | |||
} | |||
} |
@@ -0,0 +1,71 @@ | |||
<?xml version="1.0"?> | |||
<!-- | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
https://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
--> | |||
<project name="http-test" default="antunit" xmlns:au="antlib:org.apache.ant.antunit"> | |||
<import file="../../antunit-base.xml" /> | |||
<property name="location" value="https://ant.apache.org/webtest/gettest" /> | |||
<property name="unsecurelocation" value="http://ant.apache.org/webtest/gettest/http-to-https.txt" /> | |||
<target name="testSeeOtherRedirect"> | |||
<sleep milliseconds="250"/> | |||
<au:assertTrue> | |||
<http url="${location}/other.txt"/> | |||
</au:assertTrue> | |||
<au:assertLogContains level="verbose" | |||
text="Result code for ${location}/other.txt was 200" /> | |||
</target> | |||
<target name="testPermanentRedirect"> | |||
<sleep milliseconds="250"/> | |||
<au:assertTrue> | |||
<http url="${location}/permanent.txt"/> | |||
</au:assertTrue> | |||
<au:assertLogContains level="verbose" | |||
text="Result code for ${location}/permanent.txt was 200" /> | |||
</target> | |||
<target name="testTemporaryRedirect"> | |||
<sleep milliseconds="250"/> | |||
<au:assertTrue> | |||
<http url="${location}/temp.txt"/> | |||
</au:assertTrue> | |||
<au:assertLogContains level="verbose" | |||
text="Result code for ${location}/temp.txt was 200" /> | |||
</target> | |||
<target name="testStatusCode307Redirect"> | |||
<sleep milliseconds="250"/> | |||
<au:assertTrue> | |||
<http url="${location}/307.txt"/> | |||
</au:assertTrue> | |||
<au:assertLogContains level="verbose" | |||
text="Result code for ${location}/307.txt was 200" /> | |||
</target> | |||
<target name="testHttpToHttpsRedirect" description="Tests that a resource that's redirected | |||
from HTTP to HTTPS works without an error. See bugzilla-65105 for details"> | |||
<sleep milliseconds="250"/> | |||
<au:assertTrue> | |||
<http url="${unsecurelocation}"/> | |||
</au:assertTrue> | |||
<au:assertLogContains level="verbose" | |||
text="Result code for ${unsecurelocation} was 200" /> | |||
</target> | |||
</project> |