~ubuntu-branches/ubuntu/trusty/httpcomponents-core/trusty

« back to all changes in this revision

Viewing changes to httpcore/src/main/java/org/apache/http/protocol/HttpService.java

  • Committer: Bazaar Package Importer
  • Author(s): David Paleino
  • Date: 2010-06-12 08:37:34 UTC
  • Revision ID: james.westby@ubuntu.com-20100612083734-1y8kp6qm4sjk60az
Tags: upstream-4.0.1
ImportĀ upstreamĀ versionĀ 4.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $HeadURL: https://svn.apache.org/repos/asf/httpcomponents/httpcore/tags/4.0.1/httpcore/src/main/java/org/apache/http/protocol/HttpService.java $
 
3
 * $Revision: 744532 $
 
4
 * $Date: 2009-02-14 18:12:18 +0100 (Sat, 14 Feb 2009) $
 
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
 
 
32
package org.apache.http.protocol;
 
33
 
 
34
import java.io.IOException;
 
35
 
 
36
import org.apache.http.ConnectionReuseStrategy;
 
37
import org.apache.http.HttpEntity;
 
38
import org.apache.http.HttpEntityEnclosingRequest;
 
39
import org.apache.http.HttpException;
 
40
import org.apache.http.HttpRequest;
 
41
import org.apache.http.HttpResponse;
 
42
import org.apache.http.HttpResponseFactory;
 
43
import org.apache.http.HttpServerConnection;
 
44
import org.apache.http.HttpStatus;
 
45
import org.apache.http.HttpVersion;
 
46
import org.apache.http.MethodNotSupportedException;
 
47
import org.apache.http.ProtocolException;
 
48
import org.apache.http.ProtocolVersion;
 
49
import org.apache.http.UnsupportedHttpVersionException;
 
50
import org.apache.http.entity.ByteArrayEntity;
 
51
import org.apache.http.params.HttpParams;
 
52
import org.apache.http.params.DefaultedHttpParams;
 
53
import org.apache.http.util.EncodingUtils;
 
54
 
 
55
/**
 
56
 * HttpService is a server side HTTP protocol handler based in the blocking 
 
57
 * I/O model that implements the essential requirements of the HTTP protocol 
 
58
 * for the server side message processing as described by RFC 2616. 
 
59
 * <br>
 
60
 * HttpService relies on {@link HttpProcessor} to generate mandatory protocol 
 
61
 * headers for all outgoing messages and apply common, cross-cutting message 
 
62
 * transformations to all incoming and outgoing messages, whereas individual 
 
63
 * {@link HttpRequestHandler}s are expected to take care of application specific 
 
64
 * content generation and processing.
 
65
 * <br>
 
66
 * HttpService relies on {@link HttpRequestHandler} to resolve matching request 
 
67
 * handler for a particular request URI of an incoming HTTP request.
 
68
 * <br>
 
69
 * HttpService can use optional {@link HttpExpectationVerifier} to ensure that 
 
70
 * incoming requests meet server's expectations.
 
71
 *
 
72
 *
 
73
 * @version $Revision: 744532 $
 
74
 *
 
75
 * @since 4.0
 
76
 */
 
77
public class HttpService {
 
78
 
 
79
    private HttpParams params = null;
 
80
    private HttpProcessor processor = null;
 
81
    private HttpRequestHandlerResolver handlerResolver = null;
 
82
    private ConnectionReuseStrategy connStrategy = null;
 
83
    private HttpResponseFactory responseFactory = null;
 
84
    private HttpExpectationVerifier expectationVerifier = null;
 
85
    
 
86
    /**
 
87
     * Create a new HTTP service.
 
88
     *
 
89
     * @param proc             the processor to use on requests and responses
 
90
     * @param connStrategy     the connection reuse strategy
 
91
     * @param responseFactory  the response factory
 
92
     */
 
93
    public HttpService(
 
94
            final HttpProcessor proc,
 
95
            final ConnectionReuseStrategy connStrategy,
 
96
            final HttpResponseFactory responseFactory) {
 
97
        super();
 
98
        setHttpProcessor(proc);
 
99
        setConnReuseStrategy(connStrategy);
 
100
        setResponseFactory(responseFactory);
 
101
    }
 
102
    
 
103
    public void setHttpProcessor(final HttpProcessor processor) {
 
104
        if (processor == null) {
 
105
            throw new IllegalArgumentException("HTTP processor may not be null");
 
106
        }
 
107
        this.processor = processor;
 
108
    }
 
109
 
 
110
    public void setConnReuseStrategy(final ConnectionReuseStrategy connStrategy) {
 
111
        if (connStrategy == null) {
 
112
            throw new IllegalArgumentException("Connection reuse strategy may not be null");
 
113
        }
 
114
        this.connStrategy = connStrategy;
 
115
    }
 
116
 
 
117
    public void setResponseFactory(final HttpResponseFactory responseFactory) {
 
118
        if (responseFactory == null) {
 
119
            throw new IllegalArgumentException("Response factory may not be null");
 
120
        }
 
121
        this.responseFactory = responseFactory;
 
122
    }
 
123
    
 
124
    public void setHandlerResolver(final HttpRequestHandlerResolver handlerResolver) {
 
125
        this.handlerResolver = handlerResolver;
 
126
    }
 
127
 
 
128
    public void setExpectationVerifier(final HttpExpectationVerifier expectationVerifier) {
 
129
        this.expectationVerifier = expectationVerifier;
 
130
    }
 
131
 
 
132
    public HttpParams getParams() {
 
133
        return this.params;
 
134
    }
 
135
    
 
136
    public void setParams(final HttpParams params) {
 
137
        this.params = params;
 
138
    }
 
139
    
 
140
    /**
 
141
     * Handles receives one HTTP request over the given connection within the 
 
142
     * given execution context and sends a response back to the client.
 
143
     * 
 
144
     * @param conn the active connection to the client
 
145
     * @param context the actual execution context.
 
146
     * @throws IOException in case of an I/O error.
 
147
     * @throws HttpException in case of HTTP protocol violation or a processing 
 
148
     *   problem.
 
149
     */
 
150
    public void handleRequest(
 
151
            final HttpServerConnection conn, 
 
152
            final HttpContext context) throws IOException, HttpException { 
 
153
        
 
154
        context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
 
155
 
 
156
        HttpResponse response = null;
 
157
        
 
158
        try {
 
159
 
 
160
            HttpRequest request = conn.receiveRequestHeader();
 
161
            request.setParams(
 
162
                    new DefaultedHttpParams(request.getParams(), this.params));
 
163
            
 
164
            ProtocolVersion ver =
 
165
                request.getRequestLine().getProtocolVersion();
 
166
            if (!ver.lessEquals(HttpVersion.HTTP_1_1)) {
 
167
                // Downgrade protocol version if greater than HTTP/1.1 
 
168
                ver = HttpVersion.HTTP_1_1;
 
169
            }
 
170
 
 
171
            if (request instanceof HttpEntityEnclosingRequest) {
 
172
 
 
173
                if (((HttpEntityEnclosingRequest) request).expectContinue()) {
 
174
                    response = this.responseFactory.newHttpResponse(ver, 
 
175
                            HttpStatus.SC_CONTINUE, context);
 
176
                    response.setParams(
 
177
                            new DefaultedHttpParams(response.getParams(), this.params));
 
178
                    
 
179
                    if (this.expectationVerifier != null) {
 
180
                        try {
 
181
                            this.expectationVerifier.verify(request, response, context);
 
182
                        } catch (HttpException ex) {
 
183
                            response = this.responseFactory.newHttpResponse(HttpVersion.HTTP_1_0, 
 
184
                                    HttpStatus.SC_INTERNAL_SERVER_ERROR, context);
 
185
                            response.setParams(
 
186
                                    new DefaultedHttpParams(response.getParams(), this.params));
 
187
                            handleException(ex, response);
 
188
                        }
 
189
                    }
 
190
                    if (response.getStatusLine().getStatusCode() < 200) {
 
191
                        // Send 1xx response indicating the server expections
 
192
                        // have been met
 
193
                        conn.sendResponseHeader(response);
 
194
                        conn.flush();
 
195
                        response = null;
 
196
                        conn.receiveRequestEntity((HttpEntityEnclosingRequest) request);
 
197
                    }
 
198
                } else {
 
199
                    conn.receiveRequestEntity((HttpEntityEnclosingRequest) request);
 
200
                }
 
201
            }
 
202
 
 
203
            if (response == null) {
 
204
                response = this.responseFactory.newHttpResponse(ver, HttpStatus.SC_OK, context);
 
205
                response.setParams(
 
206
                        new DefaultedHttpParams(response.getParams(), this.params));
 
207
 
 
208
                context.setAttribute(ExecutionContext.HTTP_REQUEST, request);
 
209
                context.setAttribute(ExecutionContext.HTTP_RESPONSE, response);
 
210
 
 
211
                this.processor.process(request, context);
 
212
                doService(request, response, context);
 
213
            }
 
214
            
 
215
            // Make sure the request content is fully consumed
 
216
            if (request instanceof HttpEntityEnclosingRequest) {
 
217
                HttpEntity entity = ((HttpEntityEnclosingRequest)request).getEntity();
 
218
                if (entity != null) {
 
219
                    entity.consumeContent();
 
220
                }
 
221
            }
 
222
            
 
223
        } catch (HttpException ex) {
 
224
            response = this.responseFactory.newHttpResponse
 
225
                (HttpVersion.HTTP_1_0, HttpStatus.SC_INTERNAL_SERVER_ERROR,
 
226
                 context);
 
227
            response.setParams(
 
228
                    new DefaultedHttpParams(response.getParams(), this.params));
 
229
            handleException(ex, response);
 
230
        }
 
231
        
 
232
        this.processor.process(response, context);
 
233
        conn.sendResponseHeader(response);
 
234
        conn.sendResponseEntity(response);
 
235
        conn.flush();
 
236
        
 
237
        if (!this.connStrategy.keepAlive(response, context)) {
 
238
            conn.close();
 
239
        }
 
240
    }
 
241
 
 
242
    /**
 
243
     * Handles the given exception and generates an HTTP response to be sent 
 
244
     * back to the client to inform about the exceptional condition encountered
 
245
     * in the course of the request processing.
 
246
     * 
 
247
     * @param ex the exception.
 
248
     * @param response the HTTP response.
 
249
     */
 
250
    protected void handleException(final HttpException ex, final HttpResponse response) {
 
251
        if (ex instanceof MethodNotSupportedException) {
 
252
            response.setStatusCode(HttpStatus.SC_NOT_IMPLEMENTED);
 
253
        } else if (ex instanceof UnsupportedHttpVersionException) {
 
254
            response.setStatusCode(HttpStatus.SC_HTTP_VERSION_NOT_SUPPORTED);
 
255
        } else if (ex instanceof ProtocolException) {
 
256
            response.setStatusCode(HttpStatus.SC_BAD_REQUEST);
 
257
        } else {
 
258
            response.setStatusCode(HttpStatus.SC_INTERNAL_SERVER_ERROR);
 
259
        }
 
260
        byte[] msg = EncodingUtils.getAsciiBytes(ex.getMessage());
 
261
        ByteArrayEntity entity = new ByteArrayEntity(msg);
 
262
        entity.setContentType("text/plain; charset=US-ASCII");
 
263
        response.setEntity(entity);
 
264
    }
 
265
    
 
266
    /**
 
267
     * The default implementation of this method attempts to resolve an 
 
268
     * {@link HttpRequestHandler} for the request URI of the given request
 
269
     * and, if found, executes its
 
270
     * {@link HttpRequestHandler#handle(HttpRequest, HttpResponse, HttpContext)}
 
271
     * method.
 
272
     * <p>
 
273
     * Super-classes can override this method in order to provide a custom
 
274
     * implementation of the request processing logic.
 
275
     * 
 
276
     * @param request the HTTP request.
 
277
     * @param response the HTTP response.
 
278
     * @param context the execution context.
 
279
     * @throws IOException in case of an I/O error.
 
280
     * @throws HttpException in case of HTTP protocol violation or a processing 
 
281
     *   problem.
 
282
     */
 
283
    protected void doService(
 
284
            final HttpRequest request, 
 
285
            final HttpResponse response,
 
286
            final HttpContext context) throws HttpException, IOException {
 
287
        HttpRequestHandler handler = null;
 
288
        if (this.handlerResolver != null) {
 
289
            String requestURI = request.getRequestLine().getUri();
 
290
            handler = this.handlerResolver.lookup(requestURI);
 
291
        }
 
292
        if (handler != null) {
 
293
            handler.handle(request, response, context);
 
294
        } else {
 
295
            response.setStatusCode(HttpStatus.SC_NOT_IMPLEMENTED);
 
296
        }
 
297
    }
 
298
    
 
299
}