1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/protocol/HttpService.java Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,375 @@ 1.4 +/* 1.5 + * ==================================================================== 1.6 + * Licensed to the Apache Software Foundation (ASF) under one 1.7 + * or more contributor license agreements. See the NOTICE file 1.8 + * distributed with this work for additional information 1.9 + * regarding copyright ownership. The ASF licenses this file 1.10 + * to you under the Apache License, Version 2.0 (the 1.11 + * "License"); you may not use this file except in compliance 1.12 + * with the License. You may obtain a copy of the License at 1.13 + * 1.14 + * http://www.apache.org/licenses/LICENSE-2.0 1.15 + * 1.16 + * Unless required by applicable law or agreed to in writing, 1.17 + * software distributed under the License is distributed on an 1.18 + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 1.19 + * KIND, either express or implied. See the License for the 1.20 + * specific language governing permissions and limitations 1.21 + * under the License. 1.22 + * ==================================================================== 1.23 + * 1.24 + * This software consists of voluntary contributions made by many 1.25 + * individuals on behalf of the Apache Software Foundation. For more 1.26 + * information on the Apache Software Foundation, please see 1.27 + * <http://www.apache.org/>. 1.28 + * 1.29 + */ 1.30 + 1.31 +package ch.boye.httpclientandroidlib.protocol; 1.32 + 1.33 +import java.io.IOException; 1.34 + 1.35 +import ch.boye.httpclientandroidlib.ConnectionReuseStrategy; 1.36 +import ch.boye.httpclientandroidlib.HttpEntity; 1.37 +import ch.boye.httpclientandroidlib.HttpEntityEnclosingRequest; 1.38 +import ch.boye.httpclientandroidlib.HttpException; 1.39 +import ch.boye.httpclientandroidlib.HttpRequest; 1.40 +import ch.boye.httpclientandroidlib.HttpResponse; 1.41 +import ch.boye.httpclientandroidlib.HttpResponseFactory; 1.42 +import ch.boye.httpclientandroidlib.HttpServerConnection; 1.43 +import ch.boye.httpclientandroidlib.HttpStatus; 1.44 +import ch.boye.httpclientandroidlib.HttpVersion; 1.45 +import ch.boye.httpclientandroidlib.MethodNotSupportedException; 1.46 +import ch.boye.httpclientandroidlib.ProtocolException; 1.47 +import ch.boye.httpclientandroidlib.ProtocolVersion; 1.48 +import ch.boye.httpclientandroidlib.UnsupportedHttpVersionException; 1.49 +import ch.boye.httpclientandroidlib.entity.ByteArrayEntity; 1.50 +import ch.boye.httpclientandroidlib.params.HttpParams; 1.51 +import ch.boye.httpclientandroidlib.params.DefaultedHttpParams; 1.52 +import ch.boye.httpclientandroidlib.util.EncodingUtils; 1.53 +import ch.boye.httpclientandroidlib.util.EntityUtils; 1.54 + 1.55 +/** 1.56 + * HttpService is a server side HTTP protocol handler based in the blocking 1.57 + * I/O model that implements the essential requirements of the HTTP protocol 1.58 + * for the server side message processing as described by RFC 2616. 1.59 + * <br> 1.60 + * HttpService relies on {@link HttpProcessor} to generate mandatory protocol 1.61 + * headers for all outgoing messages and apply common, cross-cutting message 1.62 + * transformations to all incoming and outgoing messages, whereas individual 1.63 + * {@link HttpRequestHandler}s are expected to take care of application specific 1.64 + * content generation and processing. 1.65 + * <br> 1.66 + * HttpService relies on {@link HttpRequestHandler} to resolve matching request 1.67 + * handler for a particular request URI of an incoming HTTP request. 1.68 + * <br> 1.69 + * HttpService can use optional {@link HttpExpectationVerifier} to ensure that 1.70 + * incoming requests meet server's expectations. 1.71 + * 1.72 + * @since 4.0 1.73 + */ 1.74 +public class HttpService { 1.75 + 1.76 + /** 1.77 + * TODO: make all variables final in the next major version 1.78 + */ 1.79 + private volatile HttpParams params = null; 1.80 + private volatile HttpProcessor processor = null; 1.81 + private volatile HttpRequestHandlerResolver handlerResolver = null; 1.82 + private volatile ConnectionReuseStrategy connStrategy = null; 1.83 + private volatile HttpResponseFactory responseFactory = null; 1.84 + private volatile HttpExpectationVerifier expectationVerifier = null; 1.85 + 1.86 + /** 1.87 + * Create a new HTTP service. 1.88 + * 1.89 + * @param processor the processor to use on requests and responses 1.90 + * @param connStrategy the connection reuse strategy 1.91 + * @param responseFactory the response factory 1.92 + * @param handlerResolver the handler resolver. May be null. 1.93 + * @param expectationVerifier the expectation verifier. May be null. 1.94 + * @param params the HTTP parameters 1.95 + * 1.96 + * @since 4.1 1.97 + */ 1.98 + public HttpService( 1.99 + final HttpProcessor processor, 1.100 + final ConnectionReuseStrategy connStrategy, 1.101 + final HttpResponseFactory responseFactory, 1.102 + final HttpRequestHandlerResolver handlerResolver, 1.103 + final HttpExpectationVerifier expectationVerifier, 1.104 + final HttpParams params) { 1.105 + super(); 1.106 + if (processor == null) { 1.107 + throw new IllegalArgumentException("HTTP processor may not be null"); 1.108 + } 1.109 + if (connStrategy == null) { 1.110 + throw new IllegalArgumentException("Connection reuse strategy may not be null"); 1.111 + } 1.112 + if (responseFactory == null) { 1.113 + throw new IllegalArgumentException("Response factory may not be null"); 1.114 + } 1.115 + if (params == null) { 1.116 + throw new IllegalArgumentException("HTTP parameters may not be null"); 1.117 + } 1.118 + this.processor = processor; 1.119 + this.connStrategy = connStrategy; 1.120 + this.responseFactory = responseFactory; 1.121 + this.handlerResolver = handlerResolver; 1.122 + this.expectationVerifier = expectationVerifier; 1.123 + this.params = params; 1.124 + } 1.125 + 1.126 + /** 1.127 + * Create a new HTTP service. 1.128 + * 1.129 + * @param processor the processor to use on requests and responses 1.130 + * @param connStrategy the connection reuse strategy 1.131 + * @param responseFactory the response factory 1.132 + * @param handlerResolver the handler resolver. May be null. 1.133 + * @param params the HTTP parameters 1.134 + * 1.135 + * @since 4.1 1.136 + */ 1.137 + public HttpService( 1.138 + final HttpProcessor processor, 1.139 + final ConnectionReuseStrategy connStrategy, 1.140 + final HttpResponseFactory responseFactory, 1.141 + final HttpRequestHandlerResolver handlerResolver, 1.142 + final HttpParams params) { 1.143 + this(processor, connStrategy, responseFactory, handlerResolver, null, params); 1.144 + } 1.145 + 1.146 + /** 1.147 + * Create a new HTTP service. 1.148 + * 1.149 + * @param proc the processor to use on requests and responses 1.150 + * @param connStrategy the connection reuse strategy 1.151 + * @param responseFactory the response factory 1.152 + * 1.153 + * @deprecated use {@link HttpService#HttpService(HttpProcessor, 1.154 + * ConnectionReuseStrategy, HttpResponseFactory, HttpRequestHandlerResolver, HttpParams)} 1.155 + */ 1.156 + public HttpService( 1.157 + final HttpProcessor proc, 1.158 + final ConnectionReuseStrategy connStrategy, 1.159 + final HttpResponseFactory responseFactory) { 1.160 + super(); 1.161 + setHttpProcessor(proc); 1.162 + setConnReuseStrategy(connStrategy); 1.163 + setResponseFactory(responseFactory); 1.164 + } 1.165 + 1.166 + /** 1.167 + * @deprecated set {@link HttpProcessor} using constructor 1.168 + */ 1.169 + public void setHttpProcessor(final HttpProcessor processor) { 1.170 + if (processor == null) { 1.171 + throw new IllegalArgumentException("HTTP processor may not be null"); 1.172 + } 1.173 + this.processor = processor; 1.174 + } 1.175 + 1.176 + /** 1.177 + * @deprecated set {@link ConnectionReuseStrategy} using constructor 1.178 + */ 1.179 + public void setConnReuseStrategy(final ConnectionReuseStrategy connStrategy) { 1.180 + if (connStrategy == null) { 1.181 + throw new IllegalArgumentException("Connection reuse strategy may not be null"); 1.182 + } 1.183 + this.connStrategy = connStrategy; 1.184 + } 1.185 + 1.186 + /** 1.187 + * @deprecated set {@link HttpResponseFactory} using constructor 1.188 + */ 1.189 + public void setResponseFactory(final HttpResponseFactory responseFactory) { 1.190 + if (responseFactory == null) { 1.191 + throw new IllegalArgumentException("Response factory may not be null"); 1.192 + } 1.193 + this.responseFactory = responseFactory; 1.194 + } 1.195 + 1.196 + /** 1.197 + * @deprecated set {@link HttpResponseFactory} using constructor 1.198 + */ 1.199 + public void setParams(final HttpParams params) { 1.200 + this.params = params; 1.201 + } 1.202 + 1.203 + /** 1.204 + * @deprecated set {@link HttpRequestHandlerResolver} using constructor 1.205 + */ 1.206 + public void setHandlerResolver(final HttpRequestHandlerResolver handlerResolver) { 1.207 + this.handlerResolver = handlerResolver; 1.208 + } 1.209 + 1.210 + /** 1.211 + * @deprecated set {@link HttpExpectationVerifier} using constructor 1.212 + */ 1.213 + public void setExpectationVerifier(final HttpExpectationVerifier expectationVerifier) { 1.214 + this.expectationVerifier = expectationVerifier; 1.215 + } 1.216 + 1.217 + public HttpParams getParams() { 1.218 + return this.params; 1.219 + } 1.220 + 1.221 + /** 1.222 + * Handles receives one HTTP request over the given connection within the 1.223 + * given execution context and sends a response back to the client. 1.224 + * 1.225 + * @param conn the active connection to the client 1.226 + * @param context the actual execution context. 1.227 + * @throws IOException in case of an I/O error. 1.228 + * @throws HttpException in case of HTTP protocol violation or a processing 1.229 + * problem. 1.230 + */ 1.231 + public void handleRequest( 1.232 + final HttpServerConnection conn, 1.233 + final HttpContext context) throws IOException, HttpException { 1.234 + 1.235 + context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn); 1.236 + 1.237 + HttpResponse response = null; 1.238 + 1.239 + try { 1.240 + 1.241 + HttpRequest request = conn.receiveRequestHeader(); 1.242 + request.setParams( 1.243 + new DefaultedHttpParams(request.getParams(), this.params)); 1.244 + 1.245 + ProtocolVersion ver = 1.246 + request.getRequestLine().getProtocolVersion(); 1.247 + if (!ver.lessEquals(HttpVersion.HTTP_1_1)) { 1.248 + // Downgrade protocol version if greater than HTTP/1.1 1.249 + ver = HttpVersion.HTTP_1_1; 1.250 + } 1.251 + 1.252 + if (request instanceof HttpEntityEnclosingRequest) { 1.253 + 1.254 + if (((HttpEntityEnclosingRequest) request).expectContinue()) { 1.255 + response = this.responseFactory.newHttpResponse(ver, 1.256 + HttpStatus.SC_CONTINUE, context); 1.257 + response.setParams( 1.258 + new DefaultedHttpParams(response.getParams(), this.params)); 1.259 + 1.260 + if (this.expectationVerifier != null) { 1.261 + try { 1.262 + this.expectationVerifier.verify(request, response, context); 1.263 + } catch (HttpException ex) { 1.264 + response = this.responseFactory.newHttpResponse(HttpVersion.HTTP_1_0, 1.265 + HttpStatus.SC_INTERNAL_SERVER_ERROR, context); 1.266 + response.setParams( 1.267 + new DefaultedHttpParams(response.getParams(), this.params)); 1.268 + handleException(ex, response); 1.269 + } 1.270 + } 1.271 + if (response.getStatusLine().getStatusCode() < 200) { 1.272 + // Send 1xx response indicating the server expections 1.273 + // have been met 1.274 + conn.sendResponseHeader(response); 1.275 + conn.flush(); 1.276 + response = null; 1.277 + conn.receiveRequestEntity((HttpEntityEnclosingRequest) request); 1.278 + } 1.279 + } else { 1.280 + conn.receiveRequestEntity((HttpEntityEnclosingRequest) request); 1.281 + } 1.282 + } 1.283 + 1.284 + if (response == null) { 1.285 + response = this.responseFactory.newHttpResponse(ver, HttpStatus.SC_OK, context); 1.286 + response.setParams( 1.287 + new DefaultedHttpParams(response.getParams(), this.params)); 1.288 + 1.289 + context.setAttribute(ExecutionContext.HTTP_REQUEST, request); 1.290 + context.setAttribute(ExecutionContext.HTTP_RESPONSE, response); 1.291 + 1.292 + this.processor.process(request, context); 1.293 + doService(request, response, context); 1.294 + } 1.295 + 1.296 + // Make sure the request content is fully consumed 1.297 + if (request instanceof HttpEntityEnclosingRequest) { 1.298 + HttpEntity entity = ((HttpEntityEnclosingRequest)request).getEntity(); 1.299 + EntityUtils.consume(entity); 1.300 + } 1.301 + 1.302 + } catch (HttpException ex) { 1.303 + response = this.responseFactory.newHttpResponse 1.304 + (HttpVersion.HTTP_1_0, HttpStatus.SC_INTERNAL_SERVER_ERROR, 1.305 + context); 1.306 + response.setParams( 1.307 + new DefaultedHttpParams(response.getParams(), this.params)); 1.308 + handleException(ex, response); 1.309 + } 1.310 + 1.311 + this.processor.process(response, context); 1.312 + conn.sendResponseHeader(response); 1.313 + conn.sendResponseEntity(response); 1.314 + conn.flush(); 1.315 + 1.316 + if (!this.connStrategy.keepAlive(response, context)) { 1.317 + conn.close(); 1.318 + } 1.319 + } 1.320 + 1.321 + /** 1.322 + * Handles the given exception and generates an HTTP response to be sent 1.323 + * back to the client to inform about the exceptional condition encountered 1.324 + * in the course of the request processing. 1.325 + * 1.326 + * @param ex the exception. 1.327 + * @param response the HTTP response. 1.328 + */ 1.329 + protected void handleException(final HttpException ex, final HttpResponse response) { 1.330 + if (ex instanceof MethodNotSupportedException) { 1.331 + response.setStatusCode(HttpStatus.SC_NOT_IMPLEMENTED); 1.332 + } else if (ex instanceof UnsupportedHttpVersionException) { 1.333 + response.setStatusCode(HttpStatus.SC_HTTP_VERSION_NOT_SUPPORTED); 1.334 + } else if (ex instanceof ProtocolException) { 1.335 + response.setStatusCode(HttpStatus.SC_BAD_REQUEST); 1.336 + } else { 1.337 + response.setStatusCode(HttpStatus.SC_INTERNAL_SERVER_ERROR); 1.338 + } 1.339 + byte[] msg = EncodingUtils.getAsciiBytes(ex.getMessage()); 1.340 + ByteArrayEntity entity = new ByteArrayEntity(msg); 1.341 + entity.setContentType("text/plain; charset=US-ASCII"); 1.342 + response.setEntity(entity); 1.343 + } 1.344 + 1.345 + /** 1.346 + * The default implementation of this method attempts to resolve an 1.347 + * {@link HttpRequestHandler} for the request URI of the given request 1.348 + * and, if found, executes its 1.349 + * {@link HttpRequestHandler#handle(HttpRequest, HttpResponse, HttpContext)} 1.350 + * method. 1.351 + * <p> 1.352 + * Super-classes can override this method in order to provide a custom 1.353 + * implementation of the request processing logic. 1.354 + * 1.355 + * @param request the HTTP request. 1.356 + * @param response the HTTP response. 1.357 + * @param context the execution context. 1.358 + * @throws IOException in case of an I/O error. 1.359 + * @throws HttpException in case of HTTP protocol violation or a processing 1.360 + * problem. 1.361 + */ 1.362 + protected void doService( 1.363 + final HttpRequest request, 1.364 + final HttpResponse response, 1.365 + final HttpContext context) throws HttpException, IOException { 1.366 + HttpRequestHandler handler = null; 1.367 + if (this.handlerResolver != null) { 1.368 + String requestURI = request.getRequestLine().getUri(); 1.369 + handler = this.handlerResolver.lookup(requestURI); 1.370 + } 1.371 + if (handler != null) { 1.372 + handler.handle(request, response, context); 1.373 + } else { 1.374 + response.setStatusCode(HttpStatus.SC_NOT_IMPLEMENTED); 1.375 + } 1.376 + } 1.377 + 1.378 +}