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  
28  package org.apache.hc.client5.http.protocol;
29  
30  import java.io.IOException;
31  
32  import org.apache.hc.core5.annotation.Contract;
33  import org.apache.hc.core5.annotation.ThreadingBehavior;
34  import org.apache.hc.core5.http.EntityDetails;
35  import org.apache.hc.core5.http.Header;
36  import org.apache.hc.core5.http.HttpException;
37  import org.apache.hc.core5.http.HttpHeaders;
38  import org.apache.hc.core5.http.HttpRequest;
39  import org.apache.hc.core5.http.HttpRequestInterceptor;
40  import org.apache.hc.core5.http.Method;
41  import org.apache.hc.core5.http.ProtocolException;
42  import org.apache.hc.core5.http.protocol.HttpContext;
43  import org.apache.hc.core5.util.Args;
44  import org.slf4j.Logger;
45  import org.slf4j.LoggerFactory;
46  
47  /**
48   * <h1>RequestTraceInterceptor</h1>
49   *
50   * <p>This class serves as an interceptor for HTTP TRACE requests, ensuring they adhere to specific security and protocol guidelines.</p>
51   *
52   * <p><strong>Responsibilities:</strong></p>
53   * <ul>
54   *   <li>Validates TRACE requests by checking for sensitive headers such as {@code Authorization} and {@code Cookie}.</li>
55   *   <li>Ensures that TRACE requests do not contain a request body, throwing a {@link ProtocolException} if a body is present.</li>
56   * </ul>
57   *
58   * <p><strong>Thread Safety:</strong> This class is stateless and therefore thread-safe, as indicated by its {@code ThreadingBehavior.STATELESS} annotation.</p>
59   *
60   * <p><strong>Interceptor Behavior:</strong></p>
61   * <ul>
62   *   <li>If the HTTP method is TRACE, the interceptor throws a {@link ProtocolException} if any {@code Authorization} or {@code Cookie} headers are present to prevent sensitive data leakage.</li>
63   *   <li>If a TRACE request contains a body, a {@link ProtocolException} is thrown.</li>
64   * </ul>
65   *
66   * @version 5.4
67   * @see HttpRequestInterceptor
68   * @see HttpException
69   * @see IOException
70   * @see ProtocolException
71   * @see Method#TRACE
72   * @see HttpHeaders#AUTHORIZATION
73   * @see HttpHeaders#COOKIE
74   *//**
75   * <h1>RequestTraceInterceptor</h1>
76   *
77   * <p>This class serves as an interceptor for HTTP TRACE requests, ensuring they adhere to specific security and protocol guidelines.</p>
78   *
79   * <p><strong>Responsibilities:</strong></p>
80   * <ul>
81   *   <li>Validates TRACE requests by checking for sensitive headers such as {@code Authorization} and {@code Cookie}.</li>
82   *   <li>Ensures that TRACE requests do not contain a request body, throwing a {@link ProtocolException} if a body is present.</li>
83   * </ul>
84   *
85   * <p><strong>Thread Safety:</strong> This class is stateless and therefore thread-safe, as indicated by its {@code ThreadingBehavior.STATELESS} annotation.</p>
86   *
87   * <p><strong>Interceptor Behavior:</strong></p>
88   * <ul>
89   *   <li>If the HTTP method is TRACE, the interceptor throws a {@link ProtocolException} if any {@code Authorization} or {@code Cookie} headers are present to prevent sensitive data leakage.</li>
90   *   <li>If a TRACE request contains a body, a {@link ProtocolException} is thrown.</li>
91   * </ul>
92   *
93   * @version 5.4
94   * @see HttpRequestInterceptor
95   * @see HttpException
96   * @see IOException
97   * @see ProtocolException
98   * @see Method#TRACE
99   * @see HttpHeaders#AUTHORIZATION
100  * @see HttpHeaders#COOKIE
101  */
102 @Contract(threading = ThreadingBehavior.STATELESS)
103 public class RequestTraceInterceptor implements HttpRequestInterceptor {
104 
105     private static final Logger LOG = LoggerFactory.getLogger(RequestTraceInterceptor.class);
106 
107     /**
108      * Singleton instance of {@link RequestTraceInterceptor}.
109      */
110     public static final HttpRequestInterceptor INSTANCE = new RequestTraceInterceptor();
111 
112     /**
113      * Default constructor.
114      */
115     public RequestTraceInterceptor() {
116         super();
117     }
118 
119     /**
120      * Processes an incoming HTTP request. If the request is of type TRACE, it performs the following actions:
121      * <ul>
122      *   <li>Throws a {@link ProtocolException} if the request contains an {@code Authorization} header to prevent sensitive data leakage.</li>
123      *   <li>Throws a {@link ProtocolException} if the request contains a {@code Cookie} header to prevent sensitive data leakage.</li>
124      *   <li>Throws a {@link ProtocolException} if the request contains a body.</li>
125      * </ul>
126      *
127      * @param request The incoming HTTP request. Cannot be {@code null}.
128      * @param entity  Details of the request entity. Can be {@code null}.
129      * @param context The HTTP context.
130      * @throws HttpException If a protocol error occurs.
131      * @throws IOException   If an I/O error occurs.
132      */
133     @Override
134     public void process(final HttpRequest request, final EntityDetails entity, final HttpContext context)
135             throws HttpException, IOException {
136 
137         Args.notNull(request, "HTTP request");
138         Args.notNull(context, "HTTP context");
139 
140         // Check if the request method is TRACE
141         if (Method.TRACE.isSame(request.getMethod())) {
142 
143             // A client MUST NOT send content in a TRACE request.
144             if (entity != null) {
145                 throw new ProtocolException("TRACE request MUST NOT contain a request body.");
146             }
147 
148             // Check for sensitive headers
149             final Header authHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
150             if (authHeader != null) {
151                 throw new ProtocolException("TRACE request MUST NOT contain an Authorization header.");
152             }
153 
154             // Check for cookies
155             final Header cookieHeader = request.getHeader(HttpHeaders.COOKIE);
156             if (cookieHeader != null) {
157                 throw new ProtocolException("TRACE request MUST NOT contain a Cookie header.");
158             }
159         }
160     }
161 }