Example usage for java.io FilterInputStream FilterInputStream

List of usage examples for java.io FilterInputStream FilterInputStream

Introduction

In this page you can find the example usage for java.io FilterInputStream FilterInputStream.

Prototype

protected FilterInputStream(InputStream in) 

Source Link

Document

Creates a FilterInputStream by assigning the argument in to the field this.in so as to remember it for later use.

Usage

From source file:com.android.sdklib.internal.repository.UrlOpener.java

private static InputStream openWithHttpClient(String url, ITaskMonitor monitor)
        throws IOException, ClientProtocolException, CanceledByUserException {
    UserCredentials result = null;//from w  w  w .  ja va  2s  .  c  om
    String realm = null;

    // use the simple one
    final DefaultHttpClient httpClient = new DefaultHttpClient();

    // create local execution context
    HttpContext localContext = new BasicHttpContext();
    HttpGet httpget = new HttpGet(url);

    // retrieve local java configured network in case there is the need to
    // authenticate a proxy
    ProxySelectorRoutePlanner routePlanner = new ProxySelectorRoutePlanner(
            httpClient.getConnectionManager().getSchemeRegistry(), ProxySelector.getDefault());
    httpClient.setRoutePlanner(routePlanner);

    // Set preference order for authentication options.
    // In particular, we don't add AuthPolicy.SPNEGO, which is given preference over NTLM in
    // servers that support both, as it is more secure. However, we don't seem to handle it
    // very well, so we leave it off the list.
    // See http://hc.apache.org/httpcomponents-client-ga/tutorial/html/authentication.html for
    // more info.
    List<String> authpref = new ArrayList<String>();
    authpref.add(AuthPolicy.BASIC);
    authpref.add(AuthPolicy.DIGEST);
    authpref.add(AuthPolicy.NTLM);
    httpClient.getParams().setParameter(AuthPNames.PROXY_AUTH_PREF, authpref);
    httpClient.getParams().setParameter(AuthPNames.TARGET_AUTH_PREF, authpref);

    boolean trying = true;
    // loop while the response is being fetched
    while (trying) {
        // connect and get status code
        HttpResponse response = httpClient.execute(httpget, localContext);
        int statusCode = response.getStatusLine().getStatusCode();

        // check whether any authentication is required
        AuthState authenticationState = null;
        if (statusCode == HttpStatus.SC_UNAUTHORIZED) {
            // Target host authentication required
            authenticationState = (AuthState) localContext.getAttribute(ClientContext.TARGET_AUTH_STATE);
        }
        if (statusCode == HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED) {
            // Proxy authentication required
            authenticationState = (AuthState) localContext.getAttribute(ClientContext.PROXY_AUTH_STATE);
        }
        if (statusCode == HttpStatus.SC_OK) {
            // in case the status is OK and there is a realm and result,
            // cache it
            if (realm != null && result != null) {
                sRealmCache.put(realm, result);
            }
        }

        // there is the need for authentication
        if (authenticationState != null) {

            // get scope and realm
            AuthScope authScope = authenticationState.getAuthScope();

            // If the current realm is different from the last one it means
            // a pass was performed successfully to the last URL, therefore
            // cache the last realm
            if (realm != null && !realm.equals(authScope.getRealm())) {
                sRealmCache.put(realm, result);
            }

            realm = authScope.getRealm();

            // in case there is cache for this Realm, use it to authenticate
            if (sRealmCache.containsKey(realm)) {
                result = sRealmCache.get(realm);
            } else {
                // since there is no cache, request for login and password
                result = monitor.displayLoginCredentialsPrompt("Site Authentication",
                        "Please login to the following domain: " + realm
                                + "\n\nServer requiring authentication:\n" + authScope.getHost());
                if (result == null) {
                    throw new CanceledByUserException("User canceled login dialog.");
                }
            }

            // retrieve authentication data
            String user = result.getUserName();
            String password = result.getPassword();
            String workstation = result.getWorkstation();
            String domain = result.getDomain();

            // proceed in case there is indeed a user
            if (user != null && user.length() > 0) {
                Credentials credentials = new NTCredentials(user, password, workstation, domain);
                httpClient.getCredentialsProvider().setCredentials(authScope, credentials);
                trying = true;
            } else {
                trying = false;
            }
        } else {
            trying = false;
        }

        HttpEntity entity = response.getEntity();

        if (entity != null) {
            if (trying) {
                // in case another pass to the Http Client will be performed, close the entity.
                entity.getContent().close();
            } else {
                // since no pass to the Http Client is needed, retrieve the
                // entity's content.

                // Note: don't use something like a BufferedHttpEntity since it would consume
                // all content and store it in memory, resulting in an OutOfMemory exception
                // on a large download.

                return new FilterInputStream(entity.getContent()) {
                    @Override
                    public void close() throws IOException {
                        super.close();

                        // since Http Client is no longer needed, close it
                        httpClient.getConnectionManager().shutdown();
                    }
                };
            }
        }
    }

    // We get here if we did not succeed. Callers do not expect a null result.
    httpClient.getConnectionManager().shutdown();
    throw new FileNotFoundException(url);
}

From source file:dk.netarkivet.common.distribute.ExtendedFTPRemoteFile.java

@Override
public InputStream getInputStream() {
    connectionManager.logOn();/*from  w w  w.  j av  a2 s .c om*/
    try {
        InputStream in = connectionManager.getFTPClient().retrieveFileStream(ftpFileName);
        return new FilterInputStream(in) {
            public void close() throws IOException {
                try {
                    super.close();
                } finally {
                    connectionManager.logOut();
                    cleanup();
                }
            }
        };
    } catch (IOException e) {
        String msg = "Creating inputstream from '" + ftpFileName + "' failed ";
        if (e instanceof CopyStreamException) {
            CopyStreamException realException = (CopyStreamException) e;
            msg += "(real cause = " + realException.getIOException() + ")";
        }
        log.warn(msg, e);
        throw new IOFailure(msg, e);
    }
}

From source file:net.solarnetwork.node.backup.DefaultBackupManager.java

@Override
public void importBackupArchive(InputStream archive) throws IOException {
    final ZipInputStream zin = new ZipInputStream(archive);
    while (true) {
        final ZipEntry entry = zin.getNextEntry();
        if (entry == null) {
            break;
        }//  w w w . ja  v  a 2  s .  c om
        final String path = entry.getName();
        log.debug("Restoring backup resource {}", path);
        final int providerIndex = path.indexOf('/');
        if (providerIndex != -1) {
            final String providerKey = path.substring(0, providerIndex);
            for (BackupResourceProvider provider : resourceProviders) {
                if (providerKey.equals(provider.getKey())) {
                    provider.restoreBackupResource(new BackupResource() {

                        @Override
                        public String getBackupPath() {
                            return path.substring(providerIndex + 1);
                        }

                        @Override
                        public InputStream getInputStream() throws IOException {
                            return new FilterInputStream(zin) {

                                @Override
                                public void close() throws IOException {
                                    // don't close me
                                }

                            };
                        }

                        @Override
                        public long getModificationDate() {
                            return entry.getTime();
                        }

                    });
                    break;
                }
            }
        }
    }
}

From source file:com.planet57.gshell.MainSupport.java

/**
 * Create the {@link StreamSet} used to register.
 *///from  w  ww .ja  v a  2  s  .com
@VisibleForTesting
protected StreamSet createStreamSet(final Terminal terminal) {
    InputStream in = new FilterInputStream(terminal.input()) {
        @Override
        public void close() throws IOException {
            // ignore
        }
    };
    PrintStream out = new PrintStream(terminal.output(), true) {
        @Override
        public void close() {
            // ignore
        }
    };
    return new StreamSet(in, out);
}

From source file:org.tizzit.util.spring.httpinvoker.StreamSupportingHttpInvokerRequestExecutor.java

/**
 * Execute a request to send the given serialized remote invocation.
 * <p>Implementations will usually call <code>readRemoteInvocationResult</code>
 * to deserialize a returned RemoteInvocationResult object.
 *
 * @param config the HTTP invoker configuration that specifies the target
 *               service/*from   w  w  w .  j a v a  2s.  c  o  m*/
 * @param baos   the ByteArrayOutputStream that contains the serialized
 *               RemoteInvocation object
 *
 * @return the RemoteInvocationResult object
 *
 * @throws IOException            if thrown by I/O operations
 * @throws ClassNotFoundException if thrown during deserialization
 * @see #readRemoteInvocationResult(java.io.InputStream, String)
 */
protected RemoteInvocationResult doExecuteRequest(final HttpInvokerClientConfiguration config,
        final ByteArrayOutputStream baos, final StreamSupportingRemoteInvocation invocation)
        throws IOException, ClassNotFoundException {
    final ByteArrayInputStream serializedInvocation = new ByteArrayInputStream(baos.toByteArray());

    final PostMethod postMethod;
    final InputStream body;

    if (invocation.getClientSideInputStream() != null) {
        // We don't want to close the client side input stream unless the remote
        // method closes the input stream, so we "shield" the close for now.
        body = new CompositeInputStream(new InputStream[] { serializedInvocation,
                new CloseShieldedInputStream(invocation.getClientSideInputStream()) });
        postMethod = createPostMethodForStreaming(config);
    } else {
        body = serializedInvocation;
        postMethod = createPostMethod(config);
    }

    boolean delayReleaseConnection = false;

    try {
        postMethod.setRequestBody(body);
        executePostMethod(config, getHttpClient(), postMethod);

        HttpState state = getHttpClient().getState();
        /*postMethod.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
        String host = targetURL.getHost();
        String path = targetURL.getPath();
        boolean secure = ("https".equalsIgnoreCase(targetURL.getProtocol())) ? true : false; //$NON-NLS-1$
        String ck1 = (String) postMethod.getParams().g msgContext.getProperty(HTTPConstants.HEADER_COOKIE);
                
        String ck2 = (String) msgContext.getProperty(HTTPConstants.HEADER_COOKIE2);
        if (ck1 != null) {
           int index = ck1.indexOf('=');
           state.addCookie(new Cookie(host, ck1.substring(0, index), ck1.substring(index + 1), path, null, secure));
        }
        if (ck2 != null) {
           int index = ck2.indexOf('=');
           state.addCookie(new Cookie(host, ck2.substring(0, index), ck2.substring(index + 1), path, null, secure));
        }
        httpClient.setState(state);
        */

        final RemoteInvocationResult ret = readRemoteInvocationResult(postMethod.getResponseBodyAsStream(),
                config.getCodebaseUrl());
        if (ret instanceof StreamSupportingRemoteInvocationResult) {
            final StreamSupportingRemoteInvocationResult ssrir = (StreamSupportingRemoteInvocationResult) ret;

            // Close the local InputStream parameter if the remote method
            // explicitly closed the InputStream parameter on the other side.
            if (invocation.getClientSideInputStream() != null) {
                if (ssrir.getMethodClosedParamInputStream() != null) {
                    if (Boolean.TRUE.equals(ssrir.getMethodClosedParamInputStream())) {
                        invocation.getClientSideInputStream().close();
                    }
                } else {
                    warnInputStreamParameterStateNotSpecified(invocation);
                }
            }

            // If there is a return stream, then we need to leave the PostMethod
            // connection open until the return stream is closed, so augment the
            // return stream for this.
            if (ssrir.getHasReturnStream()) {
                final InputStream sourceRetIs = ssrir.getClientSideInputStream();
                if (sourceRetIs != null) {
                    ssrir.setClientSideInputStream(new FilterInputStream(sourceRetIs) {
                        public void close() throws IOException {
                            super.close();
                            postMethod.releaseConnection();
                        }
                    });
                    delayReleaseConnection = true;
                }
            }
        } else if (invocation.getClientSideInputStream() != null) {
            warnInputStreamParameterStateNotSpecified(invocation);
        }
        return ret;
    } finally {
        // need to explicitly release because it might be pooled
        if (!delayReleaseConnection) {
            postMethod.releaseConnection();
        }
    }
}

From source file:io.druid.java.util.common.CompressionUtils.java

/**
 * Fixes java bug 7036144 http://bugs.java.com/bugdatabase/view_bug.do?bug_id=7036144 which affects concatenated GZip
 *
 * @param in The raw input stream//w  ww  .j  ava  2s . c o  m
 *
 * @return A GZIPInputStream that can handle concatenated gzip streams in the input
 *
 * @see #decompress(InputStream, String) which should be used instead for streams coming from files
 */
public static GZIPInputStream gzipInputStream(final InputStream in) throws IOException {
    return new GZIPInputStream(new FilterInputStream(in) {
        @Override
        public int available() throws IOException {
            final int otherAvailable = super.available();
            // Hack. Docs say available() should return an estimate,
            // so we estimate about 1KB to work around available == 0 bug in GZIPInputStream
            return otherAvailable == 0 ? 1 << 10 : otherAvailable;
        }
    });
}

From source file:dk.netarkivet.common.distribute.FTPRemoteFile.java

/**
 * An implementation of the getInputStream operation that works with FTP. Notice that most of the special work
 * (logging out and checking MD5) happens in the close() method of the returned InputStream, since that is the only
 * place where we can know we're done./* w w w. j  a v a 2 s  .  c  o m*/
 *
 * @return An InputStream that will deliver the data transferred by FTP. Holding on to this for long periods without
 * reading any data might cause a timeout.
 */
@Override
public InputStream getInputStream() {
    if (filesize == 0) {
        return new ByteArrayInputStream(new byte[] {});
    }
    try {
        cm.logOn();

        InputStream in = cm.getFTPClient().retrieveFileStream(ftpFileName);
        if (in == null) {
            throw new IOFailure("Unable to retrieve input stream:" + cm.getFtpErrorMessage());
        }
        if (useChecksums) {
            in = new DigestInputStream(in, ChecksumCalculator.getMessageDigest(ChecksumCalculator.MD5));
        }
        return new FilterInputStream(in) {
            public void close() throws IOException {
                try {
                    super.close();
                    if (useChecksums) {
                        String newChecksum = ChecksumCalculator
                                .toHex(((DigestInputStream) in).getMessageDigest().digest());
                        if (!newChecksum.equals(checksum)) {
                            final String msg = "Checksums of '" + ftpFileName + "' do not match! "
                                    + "Should be " + checksum + " but was " + newChecksum;
                            log.warn(msg);
                            throw new IOFailure(msg);
                        }
                    }
                } finally {
                    cm.logOut();
                    if (!multipleDownloads) {
                        cleanup();
                    }
                }
            }
        };
    } catch (IOException e) {
        String msg = "Creating inputstream from '" + ftpFileName + "' failed ";
        if (e instanceof CopyStreamException) {
            CopyStreamException realException = (CopyStreamException) e;
            msg += "(real cause = " + realException.getIOException() + ")";
        }
        log.warn(msg, e);
        throw new IOFailure(msg, e);
    }
}

From source file:fi.laverca.util.CommonsHTTPSender.java

private InputStream createConnectionReleasingInputStream(final HttpPost post, final HttpResponse response)
        throws IOException {
    return new FilterInputStream(response.getEntity().getContent()) {
        @Override/*from w w  w. jav  a 2  s.c  o m*/
        public void close() throws IOException {
            if (log.isDebugEnabled())
                log.debug("Close http response, and release post method connection");
            try {
                super.close();
            } finally {
                HttpClientUtils.closeQuietly(response);
                post.releaseConnection();
            }
        }
    };
}

From source file:com.github.mavenplugins.doctest.ReportMojo.java

/**
 * Gets the doctest results and transforms them into {@link DoctestsContainer} objects.
 *///  www .j ava  2 s. c  o m
protected void parseDoctestResults(File doctestResultDirectory, String doctestResultDirectoryName) {
    String tmp;
    String key;
    String className;
    String doctestName;
    String requestDataClass;
    String sourceName;
    String source;
    DoctestsContainer endpoint;
    DoctestData doctest;
    RequestResultWrapper requestResult;
    ResponseResultWrapper responseResult;
    Map<String, RequestResultWrapper> requestResults = new HashMap<String, RequestResultWrapper>();
    Map<String, ResponseResultWrapper> responseResults = new HashMap<String, ResponseResultWrapper>();
    ZipInputStream zipInputStream;
    ZipEntry zipEntry;

    for (File resultFile : FileUtils.listFiles(doctestResultDirectory, new String[] { "zip" }, false)) {
        zipInputStream = null;

        try {
            zipInputStream = new ZipInputStream(new BufferedInputStream(new FileInputStream(resultFile)));

            while ((zipEntry = zipInputStream.getNextEntry()) != null) {
                tmp = zipEntry.getName();

                className = getClassName(tmp);
                doctestName = getDoctestName(tmp);
                requestDataClass = getRequestDataClass(tmp);
                sourceName = getSourceName(className);
                key = getKey(tmp);

                if (isRequest(tmp)) {
                    requestResults.put(key, mapper.readValue(new FilterInputStream(zipInputStream) {

                        @Override
                        public void close() throws IOException {
                        }

                    }, RequestResultWrapper.class));
                } else if (isResponse(tmp)) {
                    responseResults.put(key, mapper.readValue(new FilterInputStream(zipInputStream) {

                        @Override
                        public void close() throws IOException {
                        }

                    }, ResponseResultWrapper.class));
                }

                if (requestResults.containsKey(key) && responseResults.containsKey(key)) {
                    try {
                        requestResult = requestResults.get(key);
                        responseResult = responseResults.get(key);

                        requestResults.remove(key);
                        responseResults.remove(key);

                        source = FileUtils.readFileToString(
                                new File(project.getBuild().getTestSourceDirectory(), sourceName));

                        tmp = className + '.' + doctestName;
                        endpoint = endpoints.get(requestResult.getPath());
                        if (endpoint == null) {
                            endpoint = new DoctestsContainer();
                            endpoint.setName(requestResult.getPath());
                            endpoints.put(requestResult.getPath(), endpoint);
                        }

                        requestResult.setEntity(escapeToHtml(requestResult.getEntity()));
                        requestResult.setPath(escapeToHtml(requestResult.getPath()));
                        requestResult.setRequestLine(escapeToHtml(requestResult.getRequestLine()));
                        requestResult.setHeader(escapeToHtml(requestResult.getHeader()));
                        requestResult.setParemeters(escapeToHtml(requestResult.getParemeters()));

                        responseResult.setEntity(escapeToHtml(responseResult.getEntity()));
                        responseResult.setStatusLine(escapeToHtml(responseResult.getStatusLine()));
                        responseResult.setHeader(escapeToHtml(responseResult.getHeader()));
                        responseResult.setParemeters(escapeToHtml(responseResult.getParemeters()));

                        doctest = new DoctestData();
                        doctest.setJavaDoc(getJavaDoc(source, doctestName));
                        doctest.setName(tmp);
                        doctest.setRequest(requestResult);
                        doctest.setResponse(responseResult);
                        endpoint.getDoctests().put(tmp, doctest);
                    } catch (IOException exception) {
                        getLog().error("error while reading doctest request", exception);
                    }
                }
            }
        } catch (IOException exception) {
            getLog().error("error while reading doctest request", exception);
        } finally {
            if (zipInputStream != null) {
                try {
                    zipInputStream.close();
                } catch (IOException exception) {
                    getLog().error("error while reading doctest request", exception);
                }
            }
        }
    }
}

From source file:com.android.tools.idea.sdk.remote.internal.UrlOpener.java

@NonNull
private static Pair<InputStream, HttpResponse> openWithHttpClient(@NonNull String url,
        @NonNull ITaskMonitor monitor, Header[] inHeaders) throws IOException, CanceledByUserException {
    UserCredentials result = null;//from  ww w  .  ja  v a2s  . c o  m
    String realm = null;

    HttpParams params = new BasicHttpParams();
    HttpConnectionParams.setConnectionTimeout(params, sConnectionTimeoutMs);
    HttpConnectionParams.setSoTimeout(params, sSocketTimeoutMs);

    // use the simple one
    final DefaultHttpClient httpClient = new DefaultHttpClient(params);

    // create local execution context
    HttpContext localContext = new BasicHttpContext();
    final HttpGet httpGet = new HttpGet(url);
    if (inHeaders != null) {
        for (Header header : inHeaders) {
            httpGet.addHeader(header);
        }
    }

    // retrieve local java configured network in case there is the need to
    // authenticate a proxy
    ProxySelectorRoutePlanner routePlanner = new ProxySelectorRoutePlanner(
            httpClient.getConnectionManager().getSchemeRegistry(), ProxySelector.getDefault());
    httpClient.setRoutePlanner(routePlanner);

    // Set preference order for authentication options.
    // In particular, we don't add AuthPolicy.SPNEGO, which is given preference over NTLM in
    // servers that support both, as it is more secure. However, we don't seem to handle it
    // very well, so we leave it off the list.
    // See http://hc.apache.org/httpcomponents-client-ga/tutorial/html/authentication.html for
    // more info.
    List<String> authpref = new ArrayList<String>();
    authpref.add(AuthPolicy.BASIC);
    authpref.add(AuthPolicy.DIGEST);
    authpref.add(AuthPolicy.NTLM);
    httpClient.getParams().setParameter(AuthPNames.PROXY_AUTH_PREF, authpref);
    httpClient.getParams().setParameter(AuthPNames.TARGET_AUTH_PREF, authpref);

    if (DEBUG) {
        try {
            URI uri = new URI(url);
            ProxySelector sel = routePlanner.getProxySelector();
            if (sel != null && uri.getScheme().startsWith("httP")) { //$NON-NLS-1$
                List<Proxy> list = sel.select(uri);
                System.out.printf("SdkLib.UrlOpener:\n  Connect to: %s\n  Proxy List: %s\n", //$NON-NLS-1$
                        url, list == null ? "(null)" : Arrays.toString(list.toArray()));//$NON-NLS-1$
            }
        } catch (Exception e) {
            System.out.printf("SdkLib.UrlOpener: Failed to get proxy info for %s: %s\n", //$NON-NLS-1$
                    url, e.toString());
        }
    }

    boolean trying = true;
    // loop while the response is being fetched
    while (trying) {
        // connect and get status code
        HttpResponse response = httpClient.execute(httpGet, localContext);
        int statusCode = response.getStatusLine().getStatusCode();

        if (DEBUG) {
            System.out.printf("  Status: %d\n", statusCode); //$NON-NLS-1$
        }

        // check whether any authentication is required
        AuthState authenticationState = null;
        if (statusCode == HttpStatus.SC_UNAUTHORIZED) {
            // Target host authentication required
            authenticationState = (AuthState) localContext.getAttribute(ClientContext.TARGET_AUTH_STATE);
        }
        if (statusCode == HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED) {
            // Proxy authentication required
            authenticationState = (AuthState) localContext.getAttribute(ClientContext.PROXY_AUTH_STATE);
        }
        if (statusCode == HttpStatus.SC_OK || statusCode == HttpStatus.SC_NOT_MODIFIED) {
            // in case the status is OK and there is a realm and result,
            // cache it
            if (realm != null && result != null) {
                sRealmCache.put(realm, result);
            }
        }

        // there is the need for authentication
        if (authenticationState != null) {

            // get scope and realm
            AuthScope authScope = authenticationState.getAuthScope();

            // If the current realm is different from the last one it means
            // a pass was performed successfully to the last URL, therefore
            // cache the last realm
            if (realm != null && !realm.equals(authScope.getRealm())) {
                sRealmCache.put(realm, result);
            }

            realm = authScope.getRealm();

            // in case there is cache for this Realm, use it to authenticate
            if (sRealmCache.containsKey(realm)) {
                result = sRealmCache.get(realm);
            } else {
                // since there is no cache, request for login and password
                result = monitor.displayLoginCredentialsPrompt("Site Authentication",
                        "Please login to the following domain: " + realm
                                + "\n\nServer requiring authentication:\n" + authScope.getHost());
                if (result == null) {
                    throw new CanceledByUserException("User canceled login dialog.");
                }
            }

            // retrieve authentication data
            String user = result.getUserName();
            String password = result.getPassword();
            String workstation = result.getWorkstation();
            String domain = result.getDomain();

            // proceed in case there is indeed a user
            if (user != null && user.length() > 0) {
                Credentials credentials = new NTCredentials(user, password, workstation, domain);
                httpClient.getCredentialsProvider().setCredentials(authScope, credentials);
                trying = true;
            } else {
                trying = false;
            }
        } else {
            trying = false;
        }

        HttpEntity entity = response.getEntity();

        if (entity != null) {
            if (trying) {
                // in case another pass to the Http Client will be performed, close the entity.
                entity.getContent().close();
            } else {
                // since no pass to the Http Client is needed, retrieve the
                // entity's content.

                // Note: don't use something like a BufferedHttpEntity since it would consume
                // all content and store it in memory, resulting in an OutOfMemory exception
                // on a large download.
                InputStream is = new FilterInputStream(entity.getContent()) {
                    @Override
                    public void close() throws IOException {
                        // Since Http Client is no longer needed, close it.

                        // Bug #21167: we need to tell http client to shutdown
                        // first, otherwise the super.close() would continue
                        // downloading and not return till complete.

                        httpClient.getConnectionManager().shutdown();
                        super.close();
                    }
                };

                HttpResponse outResponse = new BasicHttpResponse(response.getStatusLine());
                outResponse.setHeaders(response.getAllHeaders());
                outResponse.setLocale(response.getLocale());

                return Pair.of(is, outResponse);
            }
        } else if (statusCode == HttpStatus.SC_NOT_MODIFIED) {
            // It's ok to not have an entity (e.g. nothing to download) for a 304
            HttpResponse outResponse = new BasicHttpResponse(response.getStatusLine());
            outResponse.setHeaders(response.getAllHeaders());
            outResponse.setLocale(response.getLocale());

            return Pair.of(null, outResponse);
        }
    }

    // We get here if we did not succeed. Callers do not expect a null result.
    httpClient.getConnectionManager().shutdown();
    throw new FileNotFoundException(url);
}