View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  package org.apache.hc.core5.http.io.support;
28  
29  import java.io.IOException;
30  
31  import org.apache.hc.core5.annotation.Contract;
32  import org.apache.hc.core5.annotation.ThreadingBehavior;
33  import org.apache.hc.core5.http.ClassicHttpRequest;
34  import org.apache.hc.core5.http.ClassicHttpResponse;
35  import org.apache.hc.core5.http.HttpEntity;
36  import org.apache.hc.core5.http.HttpException;
37  import org.apache.hc.core5.http.HttpResponse;
38  import org.apache.hc.core5.http.HttpStatus;
39  import org.apache.hc.core5.http.io.HttpFilterChain;
40  import org.apache.hc.core5.http.io.HttpFilterHandler;
41  import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
42  import org.apache.hc.core5.http.support.ExpectSupport;
43  import org.apache.hc.core5.http.support.Expectation;
44  import org.apache.hc.core5.http.protocol.HttpContext;
45  
46  /**
47   * HttpServerExpectationFilter add support for the Expect-Continue handshake
48   * to the request processing pipeline.
49   *
50   * @since 5.0
51   */
52  @Contract(threading = ThreadingBehavior.STATELESS)
53  public class HttpServerExpectationFilter implements HttpFilterHandler {
54  
55      /**
56       * Verifies the HTTP request and decides whether it meets server expectations and the request
57       * processing can continue.
58       *
59       * @param request the incoming HTTP request.
60       * @param context the actual execution context.
61       * @return {@code true} if the request meets expectations or {@code false} otherwise.
62       */
63      protected boolean verify(final ClassicHttpRequest request, final HttpContext context) throws HttpException {
64          return true;
65      }
66  
67      /**
68       * Generates response content entity for the final HTTP response with an error status
69       * representing the cause of expectation failure.
70       *
71       * @param expectationFailed the final HTTP response.
72       * @return the content entity for the final HTTP response with an error status
73       *  representing the cause of expectation failure.
74       */
75      protected HttpEntity generateResponseContent(final HttpResponse expectationFailed) throws HttpException {
76          return null;
77      }
78  
79      @Override
80      public final void handle(
81              final ClassicHttpRequest request,
82              final HttpFilterChain.ResponseTrigger responseTrigger,
83              final HttpContext context,
84              final HttpFilterChain chain) throws HttpException, IOException {
85          final Expectation expectation = ExpectSupport.parse(request, request.getEntity());
86          if (expectation == Expectation.CONTINUE) {
87              final boolean verified = verify(request, context);
88              if (verified) {
89                  responseTrigger.sendInformation(new BasicClassicHttpResponse(HttpStatus.SC_CONTINUE));
90              } else {
91                  final ClassicHttpResponse expectationFailed = new BasicClassicHttpResponse(HttpStatus.SC_EXPECTATION_FAILED);
92                  final HttpEntity responseContent = generateResponseContent(expectationFailed);
93                  expectationFailed.setEntity(responseContent);
94                  responseTrigger.submitResponse(expectationFailed);
95                  return;
96              }
97          } else if (expectation == Expectation.UNKNOWN) {
98              final ClassicHttpResponse expectationFailed = new BasicClassicHttpResponse(HttpStatus.SC_EXPECTATION_FAILED);
99              final HttpEntity responseContent = generateResponseContent(expectationFailed);
100             expectationFailed.setEntity(responseContent);
101             responseTrigger.submitResponse(expectationFailed);
102             return;
103         }
104         chain.proceed(request, responseTrigger, context);
105     }
106 }