You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@hc.apache.org by "ok2c (via GitHub)" <gi...@apache.org> on 2023/02/13 12:32:44 UTC

[GitHub] [httpcomponents-core] ok2c commented on a diff in pull request #390: Add a "Forwarded" HttpRequestInterceptor to add the "Forwarded" HTTP header.

ok2c commented on code in PR #390:
URL: https://github.com/apache/httpcomponents-core/pull/390#discussion_r1104408830


##########
httpcore5/src/main/java/org/apache/hc/core5/http/protocol/ForwardedRequest.java:
##########
@@ -0,0 +1,159 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.core5.http.protocol;
+
+import java.io.IOException;
+
+import org.apache.hc.core5.annotation.Contract;
+import org.apache.hc.core5.annotation.ThreadingBehavior;
+import org.apache.hc.core5.http.EndpointDetails;
+import org.apache.hc.core5.http.EntityDetails;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.HttpRequest;
+import org.apache.hc.core5.http.HttpRequestInterceptor;
+import org.apache.hc.core5.http.HttpVersion;
+import org.apache.hc.core5.http.ProtocolException;
+import org.apache.hc.core5.http.ProtocolVersion;
+import org.apache.hc.core5.http.message.BasicHeader;
+import org.apache.hc.core5.net.URIAuthority;
+import org.apache.hc.core5.util.Args;
+
+/**
+ * The ForwardedHeaderInterceptor class is a `HttpRequestInterceptor` that can be used to add the
+ * Forwarded header to an HTTP request. The Forwarded header is used to capture information about
+ * the intermediate nodes that a request has passed through. This information can be useful for
+ * security purposes or for debugging purposes.
+ * <p>
+ * The Forwarded header consists of a list of key-value pairs separated by semicolons. The keys that
+ * can be used in the Forwarded header include "host", "port", "proto", "for", and "by". The host
+ * key is used to specify the host name or IP address of the request authority. The port key is used
+ * to specify the port number of the request authority. The proto key is used to specify the
+ * protocol version of the request. The for key is used to specify the IP address of the client
+ * making the request. The by key is used to specify the IP address of the node adding the Forwarded
+ * header.
+ * <p>
+ * When multiple proxy servers are involved in forwarding a request, each proxy can add its own
+ * Forwarded header to the request. This allows for the capture of information about each
+ * intermediate node that the request passes through.
+ * <p>
+ * In this implementation, the Forwarded header is added to the request by the `process` method. The
+ * method first retrieves the ProtocolVersion and URIAuthority from the HttpContext. The
+ * ProtocolVersion is used to determine the proto key value and the URIAuthority is used to
+ * determine the host and port key values. The method also retrieves the EndpointDetails and
+ * "X-Forwarded-For" header from the HttpContext, if they exist. The EndpointDetails is used to
+ * determine the for key value and the "X-Forwarded-For" header is used to determine the by key
+ * value. If the "X-Forwarded-For" header does not exist, the by key value is set to "unknown".
+ * <p>
+ * The Forwarded header is added to the request by calling the `HttpRequest.addHeader` method. If a
+ * Forwarded header already exists in the request, the new key-value pairs are appended to the
+ * existing header.
+ *
+ * @since 5.3
+ */
+@Contract(threading = ThreadingBehavior.IMMUTABLE)
+public class ForwardedRequest implements HttpRequestInterceptor {
+
+    /**
+     * The name of the header to set in the HTTP request.
+     */
+    private static final String X_FORWARDED_HEADER_NAME = "X-Forwarded-For";
+
+    /**
+     * The name of the header to set in the HTTP request.
+     */
+    private static final String FORWARDED_HEADER_NAME = "Forwarded";
+
+
+    /**
+     * Singleton instance.
+     */
+    public static final HttpRequestInterceptor INSTANCE = new ForwardedRequest();
+
+
+    /**
+     * Adds a Forwarded header to the specified HTTP request.
+     *
+     * @param request the HTTP request to add the Forwarded header to
+     * @param entity  the entity details associated with the request, or null if the request does
+     *                not contain an entity
+     * @param context the HTTP context for the request
+     * @throws HttpException if an error occurs while adding the header
+     * @throws IOException   if an I/O error occurs while adding the header
+     */
+    @Override
+    public void process(final HttpRequest request, final EntityDetails entity, final HttpContext context) throws HttpException, IOException {
+
+        Args.notNull(request, "HTTP request");
+        Args.notNull(context, "HTTP context");
+
+        final ProtocolVersion ver = context.getProtocolVersion() != null ? context.getProtocolVersion() : HttpVersion.HTTP_1_1;
+
+        final URIAuthority authority = request.getAuthority();
+        if (authority == null) {
+            throw new ProtocolException("Request authority not specified");
+        }
+
+        final int port = authority.getPort();
+
+        final StringBuilder valueBuilder = new StringBuilder();
+        valueBuilder.append("host=").append(authority.getHostName());
+
+        if (port != -1) {
+            valueBuilder.append(";port=").append(port);
+        }
+
+        final String protoValue = ver.getProtocol();
+        if (protoValue != null) {
+            valueBuilder.append("proto=").append(protoValue);
+        }
+
+
+        final EndpointDetails endpointDetails = (EndpointDetails) context.getAttribute(HttpCoreContext.CONNECTION_ENDPOINT);
+
+        // Add the "for" property
+        if (endpointDetails != null) {
+            valueBuilder.append(";for=").append(endpointDetails.getRemoteAddress().toString());
+        }
+
+        final String byValue = (String) context.getAttribute(X_FORWARDED_HEADER_NAME);
+        if (byValue != null) {
+            valueBuilder.append(";by=").append(byValue);
+        } else {
+            valueBuilder.append(";by=unknown");
+        }
+
+        final Header header = request.getFirstHeader(X_FORWARDED_HEADER_NAME);

Review Comment:
   @arturobernalg If all you want is to override a header value if it has already been set, use `Header#setHeader`. It is massively more efficient then `Header#getFirstHeader`, `Header#removeHeader`, `Header#addHeader` sequence.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@hc.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@hc.apache.org
For additional commands, e-mail: dev-help@hc.apache.org