@Override public final OutputStream getOutputStream() throws IOException { connect(); OutputStream out = httpEngine.getRequestBody(); if (out == null) { throw new ProtocolException("method does not support a request body: " + method); } else if (httpEngine.hasResponse()) { throw new ProtocolException("cannot write request body after response has been read"); } if (faultRecoveringRequestBody == null) { faultRecoveringRequestBody = new FaultRecoveringOutputStream(MAX_REPLAY_BUFFER_LENGTH, out) { @Override protected OutputStream replacementStream(IOException e) throws IOException { if (httpEngine.getRequestBody() instanceof AbstractOutputStream && ((AbstractOutputStream) httpEngine.getRequestBody()).isClosed()) { return null; // Don't recover once the underlying stream has been closed. } if (handleFailure(e)) { return httpEngine.getRequestBody(); } return null; // This is a permanent failure. } }; } return faultRecoveringRequestBody; }
/** * Aggressively tries to get the final HTTP response, potentially making many HTTP requests in the * process in order to cope with redirects and authentication. */ private HttpEngine getResponse() throws IOException { initHttpEngine(); if (httpEngine.hasResponse()) { return httpEngine; } while (true) { if (!execute(true)) { continue; } Retry retry = processResponseHeaders(); if (retry == Retry.NONE) { httpEngine.automaticallyReleaseConnectionToPool(); return httpEngine; } // The first request was insufficient. Prepare for another... String retryMethod = method; OutputStream requestBody = httpEngine.getRequestBody(); // Although RFC 2616 10.3.2 specifies that a HTTP_MOVED_PERM // redirect should keep the same method, Chrome, Firefox and the // RI all issue GETs when following any redirect. int responseCode = getResponseCode(); if (responseCode == HTTP_MULT_CHOICE || responseCode == HTTP_MOVED_PERM || responseCode == HTTP_MOVED_TEMP || responseCode == HTTP_SEE_OTHER) { retryMethod = "GET"; requestBody = null; } if (requestBody != null && !(requestBody instanceof RetryableOutputStream)) { throw new HttpRetryException( "Cannot retry streamed HTTP body", httpEngine.getResponseCode()); } if (retry == Retry.DIFFERENT_CONNECTION) { httpEngine.automaticallyReleaseConnectionToPool(); } httpEngine.release(false); httpEngine = newHttpEngine( retryMethod, rawRequestHeaders, httpEngine.getConnection(), (RetryableOutputStream) requestBody); } }
@Override public final OutputStream getOutputStream() throws IOException { connect(); OutputStream out = httpEngine.getRequestBody(); if (out == null) { throw new ProtocolException("method does not support a request body: " + method); } else if (httpEngine.hasResponse()) { throw new ProtocolException("cannot write request body after response has been read"); } return out; }
@Override public final void disconnect() { // Calling disconnect() before a connection exists should have no effect. if (httpEngine != null) { // We close the response body here instead of in // HttpEngine.release because that is called when input // has been completely read from the underlying socket. // However the response body can be a GZIPInputStream that // still has unread data. if (httpEngine.hasResponse()) { Util.closeQuietly(httpEngine.getResponseBody()); } httpEngine.release(true); } }