/// <summary> /// Returns the response body as a String if the response was successful (a /// 2xx status code). /// </summary> /// <remarks> /// Returns the response body as a String if the response was successful (a /// 2xx status code). If no response body exists, this returns null. If the /// response was unsuccessful (>= 300 status code), throws an /// <see cref="Apache.Http.Client.HttpResponseException">Apache.Http.Client.HttpResponseException /// </see> /// . /// </remarks> /// <exception cref="Apache.Http.Client.HttpResponseException"></exception> /// <exception cref="System.IO.IOException"></exception> public virtual string HandleResponse(HttpResponse response) { StatusLine statusLine = response.GetStatusLine(); HttpEntity entity = response.GetEntity(); if (statusLine.GetStatusCode() >= 300) { EntityUtils.Consume(entity); throw new HttpResponseException(statusLine.GetStatusCode(), statusLine.GetReasonPhrase ()); } return(entity == null ? null : EntityUtils.ToString(entity)); }
/// <summary>Unconditionally close a response.</summary> /// <remarks> /// Unconditionally close a response. /// <p> /// Example Code: /// <pre> /// HttpResponse httpResponse = null; /// try { /// httpResponse = httpClient.execute(httpGet); /// } catch (Exception e) { /// // error handling /// } finally { /// HttpClientUtils.closeQuietly(httpResponse); /// } /// </pre> /// </remarks> /// <param name="response"> /// the HttpResponse to release resources, may be null or already /// closed. /// </param> /// <since>4.2</since> public static void CloseQuietly(HttpResponse response) { if (response != null) { HttpEntity entity = response.GetEntity(); if (entity != null) { try { EntityUtils.Consume(entity); } catch (IOException) { } } } }
/// <summary>Unconditionally close a response.</summary> /// <remarks> /// Unconditionally close a response. /// <p> /// Example Code: /// <pre> /// HttpResponse httpResponse = null; /// try { /// httpResponse = httpClient.execute(httpGet); /// } catch (Exception e) { /// // error handling /// } finally { /// HttpClientUtils.closeQuietly(httpResponse); /// } /// </pre> /// </remarks> /// <param name="response"> /// the HttpResponse to release resources, may be null or already /// closed. /// </param> /// <since>4.3</since> public static void CloseQuietly(CloseableHttpResponse response) { if (response != null) { try { try { EntityUtils.Consume(response.GetEntity()); } finally { response.Close(); } } catch (IOException) { } } }
/// <summary> /// Executes a request using the default context and processes the /// response using the given response handler. /// </summary> /// <remarks> /// Executes a request using the default context and processes the /// response using the given response handler. The content entity associated /// with the response is fully consumed and the underlying connection is /// released back to the connection manager automatically in all cases /// relieving individual /// <see cref="Apache.Http.Client.ResponseHandler{T}">Apache.Http.Client.ResponseHandler<T> /// </see> /// s from having to manage /// resource deallocation internally. /// </remarks> /// <param name="target"> /// the target host for the request. /// Implementations may accept <code>null</code> /// if they can still determine a route, for example /// to a default target or by inspecting the request. /// </param> /// <param name="request">the request to execute</param> /// <param name="responseHandler">the response handler</param> /// <param name="context"> /// the context to use for the execution, or /// <code>null</code> to use the default context /// </param> /// <returns>the response object as generated by the response handler.</returns> /// <exception cref="System.IO.IOException">in case of a problem or the connection was aborted /// </exception> /// <exception cref="Apache.Http.Client.ClientProtocolException">in case of an http protocol error /// </exception> public virtual T Execute <T, _T1>(HttpHost target, IHttpRequest request, ResponseHandler <_T1> responseHandler, HttpContext context) where _T1 : T { Args.NotNull(responseHandler, "Response handler"); HttpResponse response = Execute(target, request, context); T result; try { result = responseHandler.HandleResponse(response); } catch (Exception t) { HttpEntity entity = response.GetEntity(); try { EntityUtils.Consume(entity); } catch (Exception t2) { // Log this exception. The original exception is more // important and will be thrown to the caller. this.log.Warn("Error consuming content after an exception.", t2); } if (t is RuntimeException) { throw (RuntimeException)t; } if (t is IOException) { throw (IOException)t; } throw new UndeclaredThrowableException(t); } // Handling the response was successful. Ensure that the content has // been fully consumed. HttpEntity entity_1 = response.GetEntity(); EntityUtils.Consume(entity_1); return(result); }
/// <summary> /// Handles receives one HTTP request over the given connection within the /// given execution context and sends a response back to the client. /// </summary> /// <remarks> /// Handles receives one HTTP request over the given connection within the /// given execution context and sends a response back to the client. /// </remarks> /// <param name="conn">the active connection to the client</param> /// <param name="context">the actual execution context.</param> /// <exception cref="System.IO.IOException">in case of an I/O error.</exception> /// <exception cref="Org.Apache.Http.HttpException"> /// in case of HTTP protocol violation or a processing /// problem. /// </exception> public virtual void HandleRequest(HttpServerConnection conn, HttpContext context) { context.SetAttribute(HttpCoreContext.HttpConnection, conn); HttpResponse response = null; try { IHttpRequest request = conn.ReceiveRequestHeader(); if (request is HttpEntityEnclosingRequest) { if (((HttpEntityEnclosingRequest)request).ExpectContinue()) { response = this.responseFactory.NewHttpResponse(HttpVersion.Http11, HttpStatus.ScContinue , context); if (this.expectationVerifier != null) { try { this.expectationVerifier.Verify(request, response, context); } catch (HttpException ex) { response = this.responseFactory.NewHttpResponse(HttpVersion.Http10, HttpStatus.ScInternalServerError , context); HandleException(ex, response); } } if (response.GetStatusLine().GetStatusCode() < 200) { // Send 1xx response indicating the server expections // have been met conn.SendResponseHeader(response); conn.Flush(); response = null; conn.ReceiveRequestEntity((HttpEntityEnclosingRequest)request); } } else { conn.ReceiveRequestEntity((HttpEntityEnclosingRequest)request); } } context.SetAttribute(HttpCoreContext.HttpRequest, request); if (response == null) { response = this.responseFactory.NewHttpResponse(HttpVersion.Http11, HttpStatus.ScOk , context); this.processor.Process(request, context); DoService(request, response, context); } // Make sure the request content is fully consumed if (request is HttpEntityEnclosingRequest) { HttpEntity entity = ((HttpEntityEnclosingRequest)request).GetEntity(); EntityUtils.Consume(entity); } } catch (HttpException ex) { response = this.responseFactory.NewHttpResponse(HttpVersion.Http10, HttpStatus.ScInternalServerError , context); HandleException(ex, response); } context.SetAttribute(HttpCoreContext.HttpResponse, response); this.processor.Process(response, context); conn.SendResponseHeader(response); conn.SendResponseEntity(response); conn.Flush(); if (!this.connStrategy.KeepAlive(response, context)) { conn.Close(); } }
/// <exception cref="System.IO.IOException"></exception> public virtual void Close() { HttpEntity entity = this.original.GetEntity(); EntityUtils.Consume(entity); }
/// <exception cref="System.IO.IOException"></exception> /// <exception cref="Apache.Http.HttpException"></exception> public virtual CloseableHttpResponse Execute(HttpRoute route, HttpRequestWrapper request, HttpClientContext context, HttpExecutionAware execAware) { Args.NotNull(route, "HTTP route"); Args.NotNull(request, "HTTP request"); Args.NotNull(context, "HTTP context"); IList <URI> redirectLocations = context.GetRedirectLocations(); if (redirectLocations != null) { redirectLocations.Clear(); } RequestConfig config = context.GetRequestConfig(); int maxRedirects = config.GetMaxRedirects() > 0 ? config.GetMaxRedirects() : 50; HttpRoute currentRoute = route; HttpRequestWrapper currentRequest = request; for (int redirectCount = 0; ;) { CloseableHttpResponse response = requestExecutor.Execute(currentRoute, currentRequest , context, execAware); try { if (config.IsRedirectsEnabled() && this.redirectStrategy.IsRedirected(currentRequest , response, context)) { if (redirectCount >= maxRedirects) { throw new RedirectException("Maximum redirects (" + maxRedirects + ") exceeded"); } redirectCount++; IHttpRequest redirect = this.redirectStrategy.GetRedirect(currentRequest, response , context); if (!redirect.HeaderIterator().HasNext()) { IHttpRequest original = request.GetOriginal(); redirect.SetHeaders(original.GetAllHeaders()); } currentRequest = HttpRequestWrapper.Wrap(redirect); if (currentRequest is HttpEntityEnclosingRequest) { Proxies.EnhanceEntity((HttpEntityEnclosingRequest)currentRequest); } URI uri = currentRequest.GetURI(); HttpHost newTarget = URIUtils.ExtractHost(uri); if (newTarget == null) { throw new ProtocolException("Redirect URI does not specify a valid host name: " + uri); } // Reset virtual host and auth states if redirecting to another host if (!currentRoute.GetTargetHost().Equals(newTarget)) { AuthState targetAuthState = context.GetTargetAuthState(); if (targetAuthState != null) { this.log.Debug("Resetting target auth state"); targetAuthState.Reset(); } AuthState proxyAuthState = context.GetProxyAuthState(); if (proxyAuthState != null) { AuthScheme authScheme = proxyAuthState.GetAuthScheme(); if (authScheme != null && authScheme.IsConnectionBased()) { this.log.Debug("Resetting proxy auth state"); proxyAuthState.Reset(); } } } currentRoute = this.routePlanner.DetermineRoute(newTarget, currentRequest, context ); if (this.log.IsDebugEnabled()) { this.log.Debug("Redirecting to '" + uri + "' via " + currentRoute); } EntityUtils.Consume(response.GetEntity()); response.Close(); } else { return(response); } } catch (RuntimeException ex) { response.Close(); throw; } catch (IOException ex) { response.Close(); throw; } catch (HttpException ex) { // Protocol exception related to a direct. // The underlying connection may still be salvaged. try { EntityUtils.Consume(response.GetEntity()); } catch (IOException ioex) { this.log.Debug("I/O error while releasing connection", ioex); } finally { response.Close(); } throw; } } }
/// <exception cref="System.IO.IOException"></exception> /// <exception cref="Apache.Http.HttpException"></exception> public virtual Socket Tunnel(HttpHost proxy, HttpHost target, Credentials credentials ) { Args.NotNull(proxy, "Proxy host"); Args.NotNull(target, "Target host"); Args.NotNull(credentials, "Credentials"); HttpHost host = target; if (host.GetPort() <= 0) { host = new HttpHost(host.GetHostName(), 80, host.GetSchemeName()); } HttpRoute route = new HttpRoute(host, this.requestConfig.GetLocalAddress(), proxy , false, RouteInfo.TunnelType.Tunnelled, RouteInfo.LayerType.Plain); ManagedHttpClientConnection conn = this.connFactory.Create(route, this.connectionConfig ); HttpContext context = new BasicHttpContext(); HttpResponse response; IHttpRequest connect = new BasicHttpRequest("CONNECT", host.ToHostString(), HttpVersion .Http11); BasicCredentialsProvider credsProvider = new BasicCredentialsProvider(); credsProvider.SetCredentials(new AuthScope(proxy), credentials); // Populate the execution context context.SetAttribute(HttpCoreContext.HttpTargetHost, target); context.SetAttribute(HttpCoreContext.HttpConnection, conn); context.SetAttribute(HttpCoreContext.HttpRequest, connect); context.SetAttribute(HttpClientContext.HttpRoute, route); context.SetAttribute(HttpClientContext.ProxyAuthState, this.proxyAuthState); context.SetAttribute(HttpClientContext.CredsProvider, credsProvider); context.SetAttribute(HttpClientContext.AuthschemeRegistry, this.authSchemeRegistry ); context.SetAttribute(HttpClientContext.RequestConfig, this.requestConfig); this.requestExec.PreProcess(connect, this.httpProcessor, context); for (; ;) { if (!conn.IsOpen()) { Socket socket = Sharpen.Extensions.CreateSocket(proxy.GetHostName(), proxy.GetPort ()); conn.Bind(socket); } this.authenticator.GenerateAuthResponse(connect, this.proxyAuthState, context); response = this.requestExec.Execute(connect, conn, context); int status = response.GetStatusLine().GetStatusCode(); if (status < 200) { throw new HttpException("Unexpected response to CONNECT request: " + response.GetStatusLine ()); } if (this.authenticator.IsAuthenticationRequested(proxy, response, this.proxyAuthStrategy , this.proxyAuthState, context)) { if (this.authenticator.HandleAuthChallenge(proxy, response, this.proxyAuthStrategy , this.proxyAuthState, context)) { // Retry request if (this.reuseStrategy.KeepAlive(response, context)) { // Consume response content HttpEntity entity = response.GetEntity(); EntityUtils.Consume(entity); } else { conn.Close(); } // discard previous auth header connect.RemoveHeaders(AUTH.ProxyAuthResp); } else { break; } } else { break; } } int status_1 = response.GetStatusLine().GetStatusCode(); if (status_1 > 299) { // Buffer response content HttpEntity entity = response.GetEntity(); if (entity != null) { response.SetEntity(new BufferedHttpEntity(entity)); } conn.Close(); throw new TunnelRefusedException("CONNECT refused by proxy: " + response.GetStatusLine (), response); } return(conn.GetSocket()); }
/// <summary>Creates a tunnel to the target server.</summary> /// <remarks> /// Creates a tunnel to the target server. /// The connection must be established to the (last) proxy. /// A CONNECT request for tunnelling through the proxy will /// be created and sent, the response received and checked. /// This method does <i>not</i> update the connection with /// information about the tunnel, that is left to the caller. /// </remarks> /// <exception cref="Apache.Http.HttpException"></exception> /// <exception cref="System.IO.IOException"></exception> private bool CreateTunnelToTarget(AuthState proxyAuthState, HttpClientConnection managedConn, HttpRoute route, IHttpRequest request, HttpClientContext context) { RequestConfig config = context.GetRequestConfig(); int timeout = config.GetConnectTimeout(); HttpHost target = route.GetTargetHost(); HttpHost proxy = route.GetProxyHost(); HttpResponse response; string authority = target.ToHostString(); IHttpRequest connect = new BasicHttpRequest("CONNECT", authority, request.GetProtocolVersion ()); this.requestExecutor.PreProcess(connect, this.proxyHttpProcessor, context); for (; ;) { if (!managedConn.IsOpen()) { this.connManager.Connect(managedConn, route, timeout > 0 ? timeout : 0, context); } connect.RemoveHeaders(AUTH.ProxyAuthResp); this.authenticator.GenerateAuthResponse(connect, proxyAuthState, context); response = this.requestExecutor.Execute(connect, managedConn, context); int status = response.GetStatusLine().GetStatusCode(); if (status < 200) { throw new HttpException("Unexpected response to CONNECT request: " + response.GetStatusLine ()); } if (config.IsAuthenticationEnabled()) { if (this.authenticator.IsAuthenticationRequested(proxy, response, this.proxyAuthStrategy , proxyAuthState, context)) { if (this.authenticator.HandleAuthChallenge(proxy, response, this.proxyAuthStrategy , proxyAuthState, context)) { // Retry request if (this.reuseStrategy.KeepAlive(response, context)) { this.log.Debug("Connection kept alive"); // Consume response content HttpEntity entity = response.GetEntity(); EntityUtils.Consume(entity); } else { managedConn.Close(); } } else { break; } } else { break; } } } int status_1 = response.GetStatusLine().GetStatusCode(); if (status_1 > 299) { // Buffer response content HttpEntity entity = response.GetEntity(); if (entity != null) { response.SetEntity(new BufferedHttpEntity(entity)); } managedConn.Close(); throw new TunnelRefusedException("CONNECT refused by proxy: " + response.GetStatusLine (), response); } // How to decide on security of the tunnelled connection? // The socket factory knows only about the segment to the proxy. // Even if that is secure, the hop to the target may be insecure. // Leave it to derived classes, consider insecure by default here. return(false); }
/// <exception cref="System.IO.IOException"></exception> /// <exception cref="Apache.Http.HttpException"></exception> public virtual CloseableHttpResponse Execute(HttpRoute route, HttpRequestWrapper request, HttpClientContext context, HttpExecutionAware execAware) { Args.NotNull(route, "HTTP route"); Args.NotNull(request, "HTTP request"); Args.NotNull(context, "HTTP context"); AuthState targetAuthState = context.GetTargetAuthState(); if (targetAuthState == null) { targetAuthState = new AuthState(); context.SetAttribute(HttpClientContext.TargetAuthState, targetAuthState); } AuthState proxyAuthState = context.GetProxyAuthState(); if (proxyAuthState == null) { proxyAuthState = new AuthState(); context.SetAttribute(HttpClientContext.ProxyAuthState, proxyAuthState); } if (request is HttpEntityEnclosingRequest) { Proxies.EnhanceEntity((HttpEntityEnclosingRequest)request); } object userToken = context.GetUserToken(); ConnectionRequest connRequest = connManager.RequestConnection(route, userToken); if (execAware != null) { if (execAware.IsAborted()) { connRequest.Cancel(); throw new RequestAbortedException("Request aborted"); } else { execAware.SetCancellable(connRequest); } } RequestConfig config = context.GetRequestConfig(); HttpClientConnection managedConn; try { int timeout = config.GetConnectionRequestTimeout(); managedConn = connRequest.Get(timeout > 0 ? timeout : 0, TimeUnit.Milliseconds); } catch (Exception interrupted) { Sharpen.Thread.CurrentThread().Interrupt(); throw new RequestAbortedException("Request aborted", interrupted); } catch (ExecutionException ex) { Exception cause = ex.InnerException; if (cause == null) { cause = ex; } throw new RequestAbortedException("Request execution failed", cause); } context.SetAttribute(HttpClientContext.HttpConnection, managedConn); if (config.IsStaleConnectionCheckEnabled()) { // validate connection if (managedConn.IsOpen()) { this.log.Debug("Stale connection check"); if (managedConn.IsStale()) { this.log.Debug("Stale connection detected"); managedConn.Close(); } } } ConnectionHolder connHolder = new ConnectionHolder(this.log, this.connManager, managedConn ); try { if (execAware != null) { execAware.SetCancellable(connHolder); } HttpResponse response; for (int execCount = 1; ; execCount++) { if (execCount > 1 && !Proxies.IsRepeatable(request)) { throw new NonRepeatableRequestException("Cannot retry request " + "with a non-repeatable request entity." ); } if (execAware != null && execAware.IsAborted()) { throw new RequestAbortedException("Request aborted"); } if (!managedConn.IsOpen()) { this.log.Debug("Opening connection " + route); try { EstablishRoute(proxyAuthState, managedConn, route, request, context); } catch (TunnelRefusedException ex) { if (this.log.IsDebugEnabled()) { this.log.Debug(ex.Message); } response = ex.GetResponse(); break; } } int timeout = config.GetSocketTimeout(); if (timeout >= 0) { managedConn.SetSocketTimeout(timeout); } if (execAware != null && execAware.IsAborted()) { throw new RequestAbortedException("Request aborted"); } if (this.log.IsDebugEnabled()) { this.log.Debug("Executing request " + request.GetRequestLine()); } if (!request.ContainsHeader(AUTH.WwwAuthResp)) { if (this.log.IsDebugEnabled()) { this.log.Debug("Target auth state: " + targetAuthState.GetState()); } this.authenticator.GenerateAuthResponse(request, targetAuthState, context); } if (!request.ContainsHeader(AUTH.ProxyAuthResp) && !route.IsTunnelled()) { if (this.log.IsDebugEnabled()) { this.log.Debug("Proxy auth state: " + proxyAuthState.GetState()); } this.authenticator.GenerateAuthResponse(request, proxyAuthState, context); } response = requestExecutor.Execute(request, managedConn, context); // The connection is in or can be brought to a re-usable state. if (reuseStrategy.KeepAlive(response, context)) { // Set the idle duration of this connection long duration = keepAliveStrategy.GetKeepAliveDuration(response, context); if (this.log.IsDebugEnabled()) { string s; if (duration > 0) { s = "for " + duration + " " + TimeUnit.Milliseconds; } else { s = "indefinitely"; } this.log.Debug("Connection can be kept alive " + s); } connHolder.SetValidFor(duration, TimeUnit.Milliseconds); connHolder.MarkReusable(); } else { connHolder.MarkNonReusable(); } if (NeedAuthentication(targetAuthState, proxyAuthState, route, response, context)) { // Make sure the response body is fully consumed, if present HttpEntity entity = response.GetEntity(); if (connHolder.IsReusable()) { EntityUtils.Consume(entity); } else { managedConn.Close(); if (proxyAuthState.GetState() == AuthProtocolState.Success && proxyAuthState.GetAuthScheme () != null && proxyAuthState.GetAuthScheme().IsConnectionBased()) { this.log.Debug("Resetting proxy auth state"); proxyAuthState.Reset(); } if (targetAuthState.GetState() == AuthProtocolState.Success && targetAuthState.GetAuthScheme () != null && targetAuthState.GetAuthScheme().IsConnectionBased()) { this.log.Debug("Resetting target auth state"); targetAuthState.Reset(); } } // discard previous auth headers IHttpRequest original = request.GetOriginal(); if (!original.ContainsHeader(AUTH.WwwAuthResp)) { request.RemoveHeaders(AUTH.WwwAuthResp); } if (!original.ContainsHeader(AUTH.ProxyAuthResp)) { request.RemoveHeaders(AUTH.ProxyAuthResp); } } else { break; } } if (userToken == null) { userToken = userTokenHandler.GetUserToken(context); context.SetAttribute(HttpClientContext.UserToken, userToken); } if (userToken != null) { connHolder.SetState(userToken); } // check for entity, release connection if possible HttpEntity entity_1 = response.GetEntity(); if (entity_1 == null || !entity_1.IsStreaming()) { // connection not needed and (assumed to be) in re-usable state connHolder.ReleaseConnection(); return(Proxies.EnhanceResponse(response, null)); } else { return(Proxies.EnhanceResponse(response, connHolder)); } } catch (ConnectionShutdownException ex) { ThreadInterruptedException ioex = new ThreadInterruptedException("Connection has been shut down" ); Sharpen.Extensions.InitCause(ioex, ex); throw ioex; } catch (HttpException ex) { connHolder.AbortConnection(); throw; } catch (IOException ex) { connHolder.AbortConnection(); throw; } catch (RuntimeException ex) { connHolder.AbortConnection(); throw; } }