All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.unkrig.commons.net.UrlConnections Maven / Gradle / Ivy

Go to download

A versatile Java(TM) library that implements many useful container and utility classes.

There is a newer version: 1.1.12
Show newest version

/*
 * de.unkrig.commons - A general-purpose Java class library
 *
 * Copyright (c) 2015, Arno Unkrig
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 * following conditions are met:
 *
 *    1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
 *       following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 *       following disclaimer in the documentation and/or other materials provided with the distribution.
 *    3. The name of the author may not be used to endorse or promote products derived from this software without
 *       specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

package de.unkrig.commons.net;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import de.unkrig.commons.io.IoUtil;
import de.unkrig.commons.lang.AssertionUtil;
import de.unkrig.commons.nullanalysis.Nullable;

/**
 * Utility methods related to {@link URLConnection}.
 */
public final
class UrlConnections {

    static { AssertionUtil.enableAssertionsForThisClass(); }

    private static final Logger LOGGER = Logger.getLogger(UrlConnections.class.getName());

    /**
     * The charset that applies if the HTTP "Content-Type:" header is missing or has no "charset" parameter.
     * 

* See RFC 2616, sections "3.4.1 Missing Charset" and "3.7.1 * Canonicalization and Text Defaults". *

*/ public static final Charset HTTP_DEFAULT_CHARSET = Charset.forName("ISO-8859-1"); private UrlConnections() {} /** * The "follow redirects" feature of {@link HttpURLConnection} doesn't support "cross-protocol" redirects, e.g. * from "{@code http://foo}" to "{@code https://foo}". This methods implements them. * * @return httpConn, or a new {@link URLConnection} iff the connection was cross-protocol-redirected */ public static URLConnection followRedirects2(HttpURLConnection httpConn) throws IOException { LOGGER.log(Level.FINE, "followRedirects2({0})", httpConn); for (int attempt = 0;; attempt++) { if (attempt == 10) { throw new IOException( "Giving up after " + attempt + " REDIRECTs (last location was '" + httpConn.getURL() + "')" ); } try { final Set>> requestProperties = httpConn.getRequestProperties().entrySet(); int responseCode = httpConn.getResponseCode(); // 2xx? if (responseCode < 300) return httpConn; // >= 400? if (responseCode >= 400) { throw toException(httpConn, null); } String location = httpConn.getHeaderField("Location"); if (location == null) { throw new IOException("Response with code " + responseCode + " lacks the 'Location:' header field"); } URL url; try { url = new URL(httpConn.getURL(), location); } catch (MalformedURLException mue) { throw new IOException("Invalid redirection location '" + location + "'", mue); } URLConnection conn2 = url.openConnection(); // Special handling for response "303 See other". if (responseCode == 303) return conn2; // Copy all connection properties to the new connection. conn2.setAllowUserInteraction(httpConn.getAllowUserInteraction()); conn2.setConnectTimeout(httpConn.getConnectTimeout()); conn2.setDefaultUseCaches(httpConn.getDefaultUseCaches()); conn2.setDoInput(httpConn.getDoInput()); conn2.setDoOutput(httpConn.getDoOutput()); conn2.setIfModifiedSince(httpConn.getIfModifiedSince()); conn2.setReadTimeout(httpConn.getReadTimeout()); conn2.setUseCaches(httpConn.getUseCaches()); for (Entry> e : requestProperties) { for (String v : e.getValue()) { conn2.addRequestProperty(e.getKey(), v); } } if (!(conn2 instanceof HttpURLConnection)) return conn2; HttpURLConnection httpConn2 = (HttpURLConnection) conn2; // Copy all HTTP connection properties to the new connection. { int chunkLength = getChunkLength(httpConn); if (chunkLength != -1) { httpConn2.setChunkedStreamingMode(chunkLength); } } { int fixedContentLength = getFixedContentLength(httpConn); if (fixedContentLength != -1) { httpConn2.setFixedLengthStreamingMode(fixedContentLength); } } httpConn2.setInstanceFollowRedirects(httpConn.getInstanceFollowRedirects()); httpConn2.setRequestMethod(httpConn.getRequestMethod()); httpConn = httpConn2; } catch (Exception e) { LOGGER.log(Level.FINE, null, e); throw toException(httpConn, e); } } } /** * @return An {@link IOException} that contains detailed information about the request, the response, * and the response's "error stream" */ public static IOException toException(HttpURLConnection httpConn, @Nullable Throwable cause) throws IOException { int responseCode = httpConn.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_NOT_FOUND && cause == null) { return new FileNotFoundException(httpConn.getURL().toString()); } StringBuilder sb = new StringBuilder(); sb.append(httpConn.getRequestMethod()).append(" ").append(httpConn.getURL()).append('\n'); sb.append(responseCode).append(" ").append(httpConn.getResponseMessage()).append('\n'); InputStream errorStream = httpConn.getErrorStream(); if (errorStream != null) { sb.append(IoUtil.readAll(new InputStreamReader(errorStream, Charset.forName("ISO-8859-1")))); } return new IOException(sb.toString(), cause); } /** * The missing counterpart for {@link HttpURLConnection#setFixedLengthStreamingMode(int)}. * * @return The fixed content-length when using fixed-length streaming mode; {@code -1} means fixed-length streaming * mode is disabled for output */ private static int getFixedContentLength(HttpURLConnection httpConn) { try { return (Integer) HttpURLConnection.class.getDeclaredField("fixedContentLength").get(httpConn); } catch (Exception e) { return -1; } } /** * The missing counterpart for {@link HttpURLConnection#setChunkedStreamingMode(int)}. * * @return The chunk-length when using chunked encoding streaming mode for output; {@code -1} means chunked * encoding is disabled for output */ private static int getChunkLength(HttpURLConnection httpConn) { try { return (Integer) HttpURLConnection.class.getDeclaredField("chunkLength").get(httpConn); } catch (Exception e) { return -1; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy