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 }