HttpService.java revision 417f3b92ba4549b2f22340e3107d869d2b9c5bb8
1/*
2 * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/HttpService.java $
3 * $Revision: 610763 $
4 * $Date: 2008-01-10 04:01:13 -0800 (Thu, 10 Jan 2008) $
5 *
6 * ====================================================================
7 * Licensed to the Apache Software Foundation (ASF) under one
8 * or more contributor license agreements.  See the NOTICE file
9 * distributed with this work for additional information
10 * regarding copyright ownership.  The ASF licenses this file
11 * to you under the Apache License, Version 2.0 (the
12 * "License"); you may not use this file except in compliance
13 * with the License.  You may obtain a copy of the License at
14 *
15 *   http://www.apache.org/licenses/LICENSE-2.0
16 *
17 * Unless required by applicable law or agreed to in writing,
18 * software distributed under the License is distributed on an
19 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20 * KIND, either express or implied.  See the License for the
21 * specific language governing permissions and limitations
22 * under the License.
23 * ====================================================================
24 *
25 * This software consists of voluntary contributions made by many
26 * individuals on behalf of the Apache Software Foundation.  For more
27 * information on the Apache Software Foundation, please see
28 * <http://www.apache.org/>.
29 *
30 */
31
32package org.apache.http.protocol;
33
34import java.io.IOException;
35
36import org.apache.http.ConnectionReuseStrategy;
37import org.apache.http.HttpEntity;
38import org.apache.http.HttpEntityEnclosingRequest;
39import org.apache.http.HttpException;
40import org.apache.http.HttpRequest;
41import org.apache.http.HttpResponse;
42import org.apache.http.HttpResponseFactory;
43import org.apache.http.HttpServerConnection;
44import org.apache.http.HttpStatus;
45import org.apache.http.HttpVersion;
46import org.apache.http.MethodNotSupportedException;
47import org.apache.http.ProtocolException;
48import org.apache.http.ProtocolVersion;
49import org.apache.http.UnsupportedHttpVersionException;
50import org.apache.http.entity.ByteArrayEntity;
51import org.apache.http.params.HttpParams;
52import org.apache.http.params.DefaultedHttpParams;
53import org.apache.http.util.EncodingUtils;
54
55/**
56 * Minimalistic server-side implementation of an HTTP processor.
57 *
58 * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
59 *
60 * @version $Revision: 610763 $
61 */
62public class HttpService {
63
64    private HttpParams params = null;
65    private HttpProcessor processor = null;
66    private HttpRequestHandlerResolver handlerResolver = null;
67    private ConnectionReuseStrategy connStrategy = null;
68    private HttpResponseFactory responseFactory = null;
69    private HttpExpectationVerifier expectationVerifier = null;
70
71    /**
72     * Create a new HTTP service.
73     *
74     * @param proc             the processor to use on requests and responses
75     * @param connStrategy     the connection reuse strategy
76     * @param responseFactory  the response factory
77     */
78    public HttpService(
79            final HttpProcessor proc,
80            final ConnectionReuseStrategy connStrategy,
81            final HttpResponseFactory responseFactory) {
82        super();
83        setHttpProcessor(proc);
84        setConnReuseStrategy(connStrategy);
85        setResponseFactory(responseFactory);
86    }
87
88    public void setHttpProcessor(final HttpProcessor processor) {
89        if (processor == null) {
90            throw new IllegalArgumentException("HTTP processor may not be null.");
91        }
92        this.processor = processor;
93    }
94
95    public void setConnReuseStrategy(final ConnectionReuseStrategy connStrategy) {
96        if (connStrategy == null) {
97            throw new IllegalArgumentException("Connection reuse strategy may not be null");
98        }
99        this.connStrategy = connStrategy;
100    }
101
102    public void setResponseFactory(final HttpResponseFactory responseFactory) {
103        if (responseFactory == null) {
104            throw new IllegalArgumentException("Response factory may not be null");
105        }
106        this.responseFactory = responseFactory;
107    }
108
109    public void setHandlerResolver(final HttpRequestHandlerResolver handlerResolver) {
110        this.handlerResolver = handlerResolver;
111    }
112
113    public void setExpectationVerifier(final HttpExpectationVerifier expectationVerifier) {
114        this.expectationVerifier = expectationVerifier;
115    }
116
117    public HttpParams getParams() {
118        return this.params;
119    }
120
121    public void setParams(final HttpParams params) {
122        this.params = params;
123    }
124
125    public void handleRequest(
126            final HttpServerConnection conn,
127            final HttpContext context) throws IOException, HttpException {
128
129        context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
130
131        HttpResponse response = null;
132
133        try {
134
135            HttpRequest request = conn.receiveRequestHeader();
136            request.setParams(
137                    new DefaultedHttpParams(request.getParams(), this.params));
138
139            ProtocolVersion ver =
140                request.getRequestLine().getProtocolVersion();
141            if (!ver.lessEquals(HttpVersion.HTTP_1_1)) {
142                // Downgrade protocol version if greater than HTTP/1.1
143                ver = HttpVersion.HTTP_1_1;
144            }
145
146            if (request instanceof HttpEntityEnclosingRequest) {
147
148                if (((HttpEntityEnclosingRequest) request).expectContinue()) {
149                    response = this.responseFactory.newHttpResponse(ver,
150                            HttpStatus.SC_CONTINUE, context);
151                    response.setParams(
152                            new DefaultedHttpParams(response.getParams(), this.params));
153
154                    if (this.expectationVerifier != null) {
155                        try {
156                            this.expectationVerifier.verify(request, response, context);
157                        } catch (HttpException ex) {
158                            response = this.responseFactory.newHttpResponse(HttpVersion.HTTP_1_0,
159                                    HttpStatus.SC_INTERNAL_SERVER_ERROR, context);
160                            response.setParams(
161                                    new DefaultedHttpParams(response.getParams(), this.params));
162                            handleException(ex, response);
163                        }
164                    }
165                    if (response.getStatusLine().getStatusCode() < 200) {
166                        // Send 1xx response indicating the server expections
167                        // have been met
168                        conn.sendResponseHeader(response);
169                        conn.flush();
170                        response = null;
171                        conn.receiveRequestEntity((HttpEntityEnclosingRequest) request);
172                    }
173                } else {
174                    conn.receiveRequestEntity((HttpEntityEnclosingRequest) request);
175                }
176            }
177
178            if (response == null) {
179                response = this.responseFactory.newHttpResponse(ver, HttpStatus.SC_OK, context);
180                response.setParams(
181                        new DefaultedHttpParams(response.getParams(), this.params));
182
183                context.setAttribute(ExecutionContext.HTTP_REQUEST, request);
184                context.setAttribute(ExecutionContext.HTTP_RESPONSE, response);
185
186                this.processor.process(request, context);
187                doService(request, response, context);
188            }
189
190            // Make sure the request content is fully consumed
191            if (request instanceof HttpEntityEnclosingRequest) {
192                HttpEntity entity = ((HttpEntityEnclosingRequest)request).getEntity();
193                if (entity != null) {
194                    entity.consumeContent();
195                }
196            }
197
198        } catch (HttpException ex) {
199            response = this.responseFactory.newHttpResponse
200                (HttpVersion.HTTP_1_0, HttpStatus.SC_INTERNAL_SERVER_ERROR,
201                 context);
202            response.setParams(
203                    new DefaultedHttpParams(response.getParams(), this.params));
204            handleException(ex, response);
205        }
206
207        this.processor.process(response, context);
208        conn.sendResponseHeader(response);
209        conn.sendResponseEntity(response);
210        conn.flush();
211
212        if (!this.connStrategy.keepAlive(response, context)) {
213            conn.close();
214        }
215    }
216
217    protected void handleException(final HttpException ex, final HttpResponse response) {
218        if (ex instanceof MethodNotSupportedException) {
219            response.setStatusCode(HttpStatus.SC_NOT_IMPLEMENTED);
220        } else if (ex instanceof UnsupportedHttpVersionException) {
221            response.setStatusCode(HttpStatus.SC_HTTP_VERSION_NOT_SUPPORTED);
222        } else if (ex instanceof ProtocolException) {
223            response.setStatusCode(HttpStatus.SC_BAD_REQUEST);
224        } else {
225            response.setStatusCode(HttpStatus.SC_INTERNAL_SERVER_ERROR);
226        }
227        byte[] msg = EncodingUtils.getAsciiBytes(ex.getMessage());
228        ByteArrayEntity entity = new ByteArrayEntity(msg);
229        entity.setContentType("text/plain; charset=US-ASCII");
230        response.setEntity(entity);
231    }
232
233    protected void doService(
234            final HttpRequest request,
235            final HttpResponse response,
236            final HttpContext context) throws HttpException, IOException {
237        HttpRequestHandler handler = null;
238        if (this.handlerResolver != null) {
239            String requestURI = request.getRequestLine().getUri();
240            handler = this.handlerResolver.lookup(requestURI);
241        }
242        if (handler != null) {
243            handler.handle(request, response, context);
244        } else {
245            response.setStatusCode(HttpStatus.SC_NOT_IMPLEMENTED);
246        }
247    }
248
249}
250