// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.io; import static org.openstreetmap.josm.tools.I18n.tr; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Enumeration; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.tools.Pair; import org.openstreetmap.josm.tools.Utils; /** * Mirrors a file to a local file. *
* The file mirrored is only downloaded if it has been more than 7 days since last download */ public class MirroredInputStream extends InputStream { InputStream fs = null; File file = null; public static final long DEFAULT_MAXTIME = -1L; /** * Constructs an input stream from a given filename, URL or internal resource. * * @param name can be:
extension
. If more than one files have this
* extension, the last file whose name includes namepart
* is opened.
*
* @param extension the extension of the file we're looking for
* @param namepart the name part
* @return The zip entry path of the matching file. Null if this mirrored
* input stream doesn't represent a zip file or if there was no matching
* file in the ZIP file.
*/
public String findZipEntryPath(String extension, String namepart) {
Pair* Manually follows redirects because * {@link HttpURLConnection#setFollowRedirects(boolean)} fails if the redirect * is going from a http to a https URL, see bug report. *
* This can causes problems when downloading from certain GitHub URLs. * * @param downloadUrl The resource URL to download * @param httpAccept The accepted MIME types sent in the HTTP Accept header. Can be {@code null} * @return The HTTP connection effectively linked to the resource, after all potential redirections * @throws MalformedURLException If a redirected URL is wrong * @throws IOException If any I/O operation goes wrong * @since 6867 */ public static HttpURLConnection connectFollowingRedirect(URL downloadUrl, String httpAccept) throws MalformedURLException, IOException { HttpURLConnection con = null; int numRedirects = 0; while(true) { con = Utils.openHttpConnection(downloadUrl); con.setInstanceFollowRedirects(false); con.setConnectTimeout(Main.pref.getInteger("socket.timeout.connect",15)*1000); con.setReadTimeout(Main.pref.getInteger("socket.timeout.read",30)*1000); Main.debug("GET "+downloadUrl); if (httpAccept != null) { Main.debug("Accept: "+httpAccept); con.setRequestProperty("Accept", httpAccept); } try { con.connect(); } catch (IOException e) { Main.addNetworkError(downloadUrl, Utils.getRootCause(e)); throw e; } switch(con.getResponseCode()) { case HttpURLConnection.HTTP_OK: return con; case HttpURLConnection.HTTP_MOVED_PERM: case HttpURLConnection.HTTP_MOVED_TEMP: case HttpURLConnection.HTTP_SEE_OTHER: String redirectLocation = con.getHeaderField("Location"); if (downloadUrl == null) { /* I18n: argument is HTTP response code */ String msg = tr("Unexpected response from HTTP server. Got {0} response without ''Location'' header. Can''t redirect. Aborting.", con.getResponseCode()); throw new IOException(msg); } downloadUrl = new URL(redirectLocation); // keep track of redirect attempts to break a redirect loops if it happens // to occur for whatever reason numRedirects++; if (numRedirects >= Main.pref.getInteger("socket.maxredirects", 5)) { String msg = tr("Too many redirects to the download URL detected. Aborting."); throw new IOException(msg); } Main.info(tr("Download redirected to ''{0}''", downloadUrl)); break; default: String msg = tr("Failed to read from ''{0}''. Server responded with status code {1}.", downloadUrl, con.getResponseCode()); throw new IOException(msg); } } } @Override public int available() throws IOException { return fs.available(); } @Override public void close() throws IOException { Utils.close(fs); } @Override public int read() throws IOException { return fs.read(); } @Override public int read(byte[] b) throws IOException { return fs.read(b); } @Override public int read(byte[] b, int off, int len) throws IOException { return fs.read(b,off, len); } @Override public long skip(long n) throws IOException { return fs.skip(n); } }