1168 lines
41 KiB
Diff
1168 lines
41 KiB
Diff
|
|
From cec50b3d2cea7bdf6b2f00d45c8554139aebbf87 Mon Sep 17 00:00:00 2001
|
||
|
|
From: Greg Wilkins <gregw@webtide.com>
|
||
|
|
Date: Wed, 8 May 2019 21:07:22 +0200
|
||
|
|
Subject: [PATCH] Issue #3630 Optimized ForwardedRequestCustomizer
|
||
|
|
|
||
|
|
Signed-off-by: Greg Wilkins <gregw@webtide.com>
|
||
|
|
---
|
||
|
|
.../eclipse/jetty/http/HostPortHttpField.java | 17 +-
|
||
|
|
.../org/eclipse/jetty/http/QuotedCSV.java | 264 +---------------
|
||
|
|
.../eclipse/jetty/http/QuotedCSVParser.java | 288 ++++++++++++++++++
|
||
|
|
.../server/ForwardedRequestCustomizer.java | 249 +++++++--------
|
||
|
|
.../ForwardedRequestCustomizerTest.java | 99 +++++-
|
||
|
|
5 files changed, 507 insertions(+), 410 deletions(-)
|
||
|
|
create mode 100644 jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSVParser.java
|
||
|
|
|
||
|
|
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java
|
||
|
|
index dc386665339..6c9f3b921e8 100644
|
||
|
|
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java
|
||
|
|
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java
|
||
|
|
@@ -22,9 +22,9 @@
|
||
|
|
import org.eclipse.jetty.util.HostPort;
|
||
|
|
|
||
|
|
|
||
|
|
-
|
||
|
|
-/* ------------------------------------------------------------ */
|
||
|
|
/**
|
||
|
|
+ * A HttpField holding a preparsed Host and port number
|
||
|
|
+ * @see HostPort
|
||
|
|
*/
|
||
|
|
public class HostPortHttpField extends HttpField
|
||
|
|
{
|
||
|
|
@@ -35,7 +35,6 @@ public HostPortHttpField(String authority)
|
||
|
|
this(HttpHeader.HOST,HttpHeader.HOST.asString(),authority);
|
||
|
|
}
|
||
|
|
|
||
|
|
- /* ------------------------------------------------------------ */
|
||
|
|
protected HostPortHttpField(HttpHeader header, String name, String authority)
|
||
|
|
{
|
||
|
|
super(header,name,authority);
|
||
|
|
@@ -49,20 +48,17 @@ protected HostPortHttpField(HttpHeader header, String name, String authority)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
- /* ------------------------------------------------------------ */
|
||
|
|
public HostPortHttpField(String host, int port)
|
||
|
|
{
|
||
|
|
this(new HostPort(host, port));
|
||
|
|
}
|
||
|
|
|
||
|
|
- /* ------------------------------------------------------------ */
|
||
|
|
- protected HostPortHttpField(HostPort hostport)
|
||
|
|
+ public HostPortHttpField(HostPort hostport)
|
||
|
|
{
|
||
|
|
super(HttpHeader.HOST,HttpHeader.HOST.asString(),hostport.toString());
|
||
|
|
_hostPort = hostport;
|
||
|
|
}
|
||
|
|
|
||
|
|
- /* ------------------------------------------------------------ */
|
||
|
|
/** Get the host.
|
||
|
|
* @return the host
|
||
|
|
*/
|
||
|
|
@@ -71,7 +67,6 @@ public String getHost()
|
||
|
|
return _hostPort.getHost();
|
||
|
|
}
|
||
|
|
|
||
|
|
- /* ------------------------------------------------------------ */
|
||
|
|
/** Get the port.
|
||
|
|
* @return the port
|
||
|
|
*/
|
||
|
|
@@ -80,7 +75,6 @@ public int getPort()
|
||
|
|
return _hostPort.getPort();
|
||
|
|
}
|
||
|
|
|
||
|
|
- /* ------------------------------------------------------------ */
|
||
|
|
/** Get the port.
|
||
|
|
* @param defaultPort The default port to return if no port set
|
||
|
|
* @return the port
|
||
|
|
@@ -89,4 +83,9 @@ public int getPort(int defaultPort)
|
||
|
|
{
|
||
|
|
return _hostPort.getPort(defaultPort);
|
||
|
|
}
|
||
|
|
+
|
||
|
|
+ public HostPort getHostPort()
|
||
|
|
+ {
|
||
|
|
+ return _hostPort;
|
||
|
|
+ }
|
||
|
|
}
|
||
|
|
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSV.java b/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSV.java
|
||
|
|
index 9ca7dbeec2c..8ebc2c36307 100644
|
||
|
|
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSV.java
|
||
|
|
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSV.java
|
||
|
|
@@ -22,8 +22,6 @@
|
||
|
|
import java.util.Iterator;
|
||
|
|
import java.util.List;
|
||
|
|
|
||
|
|
-import org.eclipse.jetty.util.QuotedStringTokenizer;
|
||
|
|
-
|
||
|
|
/* ------------------------------------------------------------ */
|
||
|
|
/**
|
||
|
|
* Implements a quoted comma separated list of values
|
||
|
|
@@ -32,226 +30,26 @@
|
||
|
|
* @see "https://tools.ietf.org/html/rfc7230#section-3.2.6"
|
||
|
|
* @see "https://tools.ietf.org/html/rfc7230#section-7"
|
||
|
|
*/
|
||
|
|
-public class QuotedCSV implements Iterable<String>
|
||
|
|
-{
|
||
|
|
- private enum State { VALUE, PARAM_NAME, PARAM_VALUE};
|
||
|
|
-
|
||
|
|
+public class QuotedCSV extends QuotedCSVParser implements Iterable<String>
|
||
|
|
+{
|
||
|
|
protected final List<String> _values = new ArrayList<>();
|
||
|
|
- protected final boolean _keepQuotes;
|
||
|
|
-
|
||
|
|
- /* ------------------------------------------------------------ */
|
||
|
|
+
|
||
|
|
public QuotedCSV(String... values)
|
||
|
|
{
|
||
|
|
this(true,values);
|
||
|
|
}
|
||
|
|
|
||
|
|
- /* ------------------------------------------------------------ */
|
||
|
|
public QuotedCSV(boolean keepQuotes,String... values)
|
||
|
|
{
|
||
|
|
- _keepQuotes=keepQuotes;
|
||
|
|
+ super(keepQuotes);
|
||
|
|
for (String v:values)
|
||
|
|
addValue(v);
|
||
|
|
}
|
||
|
|
-
|
||
|
|
- /* ------------------------------------------------------------ */
|
||
|
|
- /** Add and parse a value string(s)
|
||
|
|
- * @param value A value that may contain one or more Quoted CSV items.
|
||
|
|
- */
|
||
|
|
- public void addValue(String value)
|
||
|
|
- {
|
||
|
|
- if (value == null)
|
||
|
|
- return;
|
||
|
|
-
|
||
|
|
- StringBuffer buffer = new StringBuffer();
|
||
|
|
-
|
||
|
|
- int l=value.length();
|
||
|
|
- State state=State.VALUE;
|
||
|
|
- boolean quoted=false;
|
||
|
|
- boolean sloshed=false;
|
||
|
|
- int nws_length=0;
|
||
|
|
- int last_length=0;
|
||
|
|
- int value_length=-1;
|
||
|
|
- int param_name=-1;
|
||
|
|
- int param_value=-1;
|
||
|
|
-
|
||
|
|
- for (int i=0;i<=l;i++)
|
||
|
|
- {
|
||
|
|
- char c=i==l?0:value.charAt(i);
|
||
|
|
-
|
||
|
|
- // Handle quoting https://tools.ietf.org/html/rfc7230#section-3.2.6
|
||
|
|
- if (quoted && c!=0)
|
||
|
|
- {
|
||
|
|
- if (sloshed)
|
||
|
|
- sloshed=false;
|
||
|
|
- else
|
||
|
|
- {
|
||
|
|
- switch(c)
|
||
|
|
- {
|
||
|
|
- case '\\':
|
||
|
|
- sloshed=true;
|
||
|
|
- if (!_keepQuotes)
|
||
|
|
- continue;
|
||
|
|
- break;
|
||
|
|
- case '"':
|
||
|
|
- quoted=false;
|
||
|
|
- if (!_keepQuotes)
|
||
|
|
- continue;
|
||
|
|
- break;
|
||
|
|
- }
|
||
|
|
- }
|
||
|
|
-
|
||
|
|
- buffer.append(c);
|
||
|
|
- nws_length=buffer.length();
|
||
|
|
- continue;
|
||
|
|
- }
|
||
|
|
-
|
||
|
|
- // Handle common cases
|
||
|
|
- switch(c)
|
||
|
|
- {
|
||
|
|
- case ' ':
|
||
|
|
- case '\t':
|
||
|
|
- if (buffer.length()>last_length) // not leading OWS
|
||
|
|
- buffer.append(c);
|
||
|
|
- continue;
|
||
|
|
-
|
||
|
|
- case '"':
|
||
|
|
- quoted=true;
|
||
|
|
- if (_keepQuotes)
|
||
|
|
- {
|
||
|
|
- if (state==State.PARAM_VALUE && param_value<0)
|
||
|
|
- param_value=nws_length;
|
||
|
|
- buffer.append(c);
|
||
|
|
- }
|
||
|
|
- else if (state==State.PARAM_VALUE && param_value<0)
|
||
|
|
- param_value=nws_length;
|
||
|
|
- nws_length=buffer.length();
|
||
|
|
- continue;
|
||
|
|
-
|
||
|
|
- case ';':
|
||
|
|
- buffer.setLength(nws_length); // trim following OWS
|
||
|
|
- if (state==State.VALUE)
|
||
|
|
- {
|
||
|
|
- parsedValue(buffer);
|
||
|
|
- value_length=buffer.length();
|
||
|
|
- }
|
||
|
|
- else
|
||
|
|
- parsedParam(buffer,value_length,param_name,param_value);
|
||
|
|
- nws_length=buffer.length();
|
||
|
|
- param_name=param_value=-1;
|
||
|
|
- buffer.append(c);
|
||
|
|
- last_length=++nws_length;
|
||
|
|
- state=State.PARAM_NAME;
|
||
|
|
- continue;
|
||
|
|
-
|
||
|
|
- case ',':
|
||
|
|
- case 0:
|
||
|
|
- if (nws_length>0)
|
||
|
|
- {
|
||
|
|
- buffer.setLength(nws_length); // trim following OWS
|
||
|
|
- switch(state)
|
||
|
|
- {
|
||
|
|
- case VALUE:
|
||
|
|
- parsedValue(buffer);
|
||
|
|
- value_length=buffer.length();
|
||
|
|
- break;
|
||
|
|
- case PARAM_NAME:
|
||
|
|
- case PARAM_VALUE:
|
||
|
|
- parsedParam(buffer,value_length,param_name,param_value);
|
||
|
|
- break;
|
||
|
|
- }
|
||
|
|
- _values.add(buffer.toString());
|
||
|
|
- }
|
||
|
|
- buffer.setLength(0);
|
||
|
|
- last_length=0;
|
||
|
|
- nws_length=0;
|
||
|
|
- value_length=param_name=param_value=-1;
|
||
|
|
- state=State.VALUE;
|
||
|
|
- continue;
|
||
|
|
-
|
||
|
|
- case '=':
|
||
|
|
- switch (state)
|
||
|
|
- {
|
||
|
|
- case VALUE:
|
||
|
|
- // It wasn't really a value, it was a param name
|
||
|
|
- value_length=param_name=0;
|
||
|
|
- buffer.setLength(nws_length); // trim following OWS
|
||
|
|
- String param = buffer.toString();
|
||
|
|
- buffer.setLength(0);
|
||
|
|
- parsedValue(buffer);
|
||
|
|
- value_length=buffer.length();
|
||
|
|
- buffer.append(param);
|
||
|
|
- buffer.append(c);
|
||
|
|
- last_length=++nws_length;
|
||
|
|
- state=State.PARAM_VALUE;
|
||
|
|
- continue;
|
||
|
|
-
|
||
|
|
- case PARAM_NAME:
|
||
|
|
- buffer.setLength(nws_length); // trim following OWS
|
||
|
|
- buffer.append(c);
|
||
|
|
- last_length=++nws_length;
|
||
|
|
- state=State.PARAM_VALUE;
|
||
|
|
- continue;
|
||
|
|
-
|
||
|
|
- case PARAM_VALUE:
|
||
|
|
- if (param_value<0)
|
||
|
|
- param_value=nws_length;
|
||
|
|
- buffer.append(c);
|
||
|
|
- nws_length=buffer.length();
|
||
|
|
- continue;
|
||
|
|
- }
|
||
|
|
- continue;
|
||
|
|
-
|
||
|
|
- default:
|
||
|
|
- {
|
||
|
|
- switch (state)
|
||
|
|
- {
|
||
|
|
- case VALUE:
|
||
|
|
- {
|
||
|
|
- buffer.append(c);
|
||
|
|
- nws_length=buffer.length();
|
||
|
|
- continue;
|
||
|
|
- }
|
||
|
|
-
|
||
|
|
- case PARAM_NAME:
|
||
|
|
- {
|
||
|
|
- if (param_name<0)
|
||
|
|
- param_name=nws_length;
|
||
|
|
- buffer.append(c);
|
||
|
|
- nws_length=buffer.length();
|
||
|
|
- continue;
|
||
|
|
- }
|
||
|
|
-
|
||
|
|
- case PARAM_VALUE:
|
||
|
|
- {
|
||
|
|
- if (param_value<0)
|
||
|
|
- param_value=nws_length;
|
||
|
|
- buffer.append(c);
|
||
|
|
- nws_length=buffer.length();
|
||
|
|
- continue;
|
||
|
|
- }
|
||
|
|
- }
|
||
|
|
- }
|
||
|
|
- }
|
||
|
|
- }
|
||
|
|
- }
|
||
|
|
-
|
||
|
|
- /**
|
||
|
|
- * Called when a value has been parsed
|
||
|
|
- * @param buffer Containing the trimmed value, which may be mutated
|
||
|
|
- */
|
||
|
|
- protected void parsedValue(StringBuffer buffer)
|
||
|
|
- {
|
||
|
|
- }
|
||
|
|
|
||
|
|
- /**
|
||
|
|
- * Called when a parameter has been parsed
|
||
|
|
- * @param buffer Containing the trimmed value and all parameters, which may be mutated
|
||
|
|
- * @param valueLength The length of the value
|
||
|
|
- * @param paramName The index of the start of the parameter just parsed
|
||
|
|
- * @param paramValue The index of the start of the parameter value just parsed, or -1
|
||
|
|
- */
|
||
|
|
- protected void parsedParam(StringBuffer buffer, int valueLength, int paramName, int paramValue)
|
||
|
|
+ @Override
|
||
|
|
+ protected void parsedValueAndParams(StringBuffer buffer)
|
||
|
|
{
|
||
|
|
+ _values.add(buffer.toString());
|
||
|
|
}
|
||
|
|
|
||
|
|
public int size()
|
||
|
|
@@ -274,55 +72,7 @@ public boolean isEmpty()
|
||
|
|
{
|
||
|
|
return _values.iterator();
|
||
|
|
}
|
||
|
|
-
|
||
|
|
- public static String unquote(String s)
|
||
|
|
- {
|
||
|
|
- // handle trivial cases
|
||
|
|
- int l=s.length();
|
||
|
|
- if (s==null || l==0)
|
||
|
|
- return s;
|
||
|
|
-
|
||
|
|
- // Look for any quotes
|
||
|
|
- int i=0;
|
||
|
|
- for (;i<l;i++)
|
||
|
|
- {
|
||
|
|
- char c=s.charAt(i);
|
||
|
|
- if (c=='"')
|
||
|
|
- break;
|
||
|
|
- }
|
||
|
|
- if (i==l)
|
||
|
|
- return s;
|
||
|
|
|
||
|
|
- boolean quoted=true;
|
||
|
|
- boolean sloshed=false;
|
||
|
|
- StringBuffer buffer = new StringBuffer();
|
||
|
|
- buffer.append(s,0,i);
|
||
|
|
- i++;
|
||
|
|
- for (;i<l;i++)
|
||
|
|
- {
|
||
|
|
- char c=s.charAt(i);
|
||
|
|
- if (quoted)
|
||
|
|
- {
|
||
|
|
- if (sloshed)
|
||
|
|
- {
|
||
|
|
- buffer.append(c);
|
||
|
|
- sloshed=false;
|
||
|
|
- }
|
||
|
|
- else if (c=='"')
|
||
|
|
- quoted=false;
|
||
|
|
- else if (c=='\\')
|
||
|
|
- sloshed=true;
|
||
|
|
- else
|
||
|
|
- buffer.append(c);
|
||
|
|
- }
|
||
|
|
- else if (c=='"')
|
||
|
|
- quoted=true;
|
||
|
|
- else
|
||
|
|
- buffer.append(c);
|
||
|
|
- }
|
||
|
|
- return buffer.toString();
|
||
|
|
- }
|
||
|
|
-
|
||
|
|
@Override
|
||
|
|
public String toString()
|
||
|
|
{
|
||
|
|
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSVParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSVParser.java
|
||
|
|
new file mode 100644
|
||
|
|
index 00000000000..8f521db7ffb
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSVParser.java
|
||
|
|
@@ -0,0 +1,288 @@
|
||
|
|
+//
|
||
|
|
+// ========================================================================
|
||
|
|
+// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||
|
|
+// ------------------------------------------------------------------------
|
||
|
|
+// All rights reserved. This program and the accompanying materials
|
||
|
|
+// are made available under the terms of the Eclipse Public License v1.0
|
||
|
|
+// and Apache License v2.0 which accompanies this distribution.
|
||
|
|
+//
|
||
|
|
+// The Eclipse Public License is available at
|
||
|
|
+// http://www.eclipse.org/legal/epl-v10.html
|
||
|
|
+//
|
||
|
|
+// The Apache License v2.0 is available at
|
||
|
|
+// http://www.opensource.org/licenses/apache2.0.php
|
||
|
|
+//
|
||
|
|
+// You may elect to redistribute this code under either of these licenses.
|
||
|
|
+// ========================================================================
|
||
|
|
+//
|
||
|
|
+
|
||
|
|
+package org.eclipse.jetty.http;
|
||
|
|
+
|
||
|
|
+public abstract class QuotedCSVParser
|
||
|
|
+{
|
||
|
|
+ private enum State { VALUE, PARAM_NAME, PARAM_VALUE}
|
||
|
|
+
|
||
|
|
+ protected final boolean _keepQuotes;
|
||
|
|
+
|
||
|
|
+ public QuotedCSVParser(boolean keepQuotes)
|
||
|
|
+ {
|
||
|
|
+ _keepQuotes=keepQuotes;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ public static String unquote(String s)
|
||
|
|
+ {
|
||
|
|
+ // handle trivial cases
|
||
|
|
+ int l=s.length();
|
||
|
|
+ if (s==null || l==0)
|
||
|
|
+ return s;
|
||
|
|
+
|
||
|
|
+ // Look for any quotes
|
||
|
|
+ int i=0;
|
||
|
|
+ for (;i<l;i++)
|
||
|
|
+ {
|
||
|
|
+ char c=s.charAt(i);
|
||
|
|
+ if (c=='"')
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+ if (i==l)
|
||
|
|
+ return s;
|
||
|
|
+
|
||
|
|
+ boolean quoted=true;
|
||
|
|
+ boolean sloshed=false;
|
||
|
|
+ StringBuffer buffer = new StringBuffer();
|
||
|
|
+ buffer.append(s,0,i);
|
||
|
|
+ i++;
|
||
|
|
+ for (;i<l;i++)
|
||
|
|
+ {
|
||
|
|
+ char c=s.charAt(i);
|
||
|
|
+ if (quoted)
|
||
|
|
+ {
|
||
|
|
+ if (sloshed)
|
||
|
|
+ {
|
||
|
|
+ buffer.append(c);
|
||
|
|
+ sloshed=false;
|
||
|
|
+ }
|
||
|
|
+ else if (c=='"')
|
||
|
|
+ quoted=false;
|
||
|
|
+ else if (c=='\\')
|
||
|
|
+ sloshed=true;
|
||
|
|
+ else
|
||
|
|
+ buffer.append(c);
|
||
|
|
+ }
|
||
|
|
+ else if (c=='"')
|
||
|
|
+ quoted=true;
|
||
|
|
+ else
|
||
|
|
+ buffer.append(c);
|
||
|
|
+ }
|
||
|
|
+ return buffer.toString();
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /** Add and parse a value string(s)
|
||
|
|
+ * @param value A value that may contain one or more Quoted CSV items.
|
||
|
|
+ */
|
||
|
|
+ public void addValue(String value)
|
||
|
|
+ {
|
||
|
|
+ if (value == null)
|
||
|
|
+ return;
|
||
|
|
+
|
||
|
|
+ StringBuffer buffer = new StringBuffer();
|
||
|
|
+
|
||
|
|
+ int l=value.length();
|
||
|
|
+ State state=State.VALUE;
|
||
|
|
+ boolean quoted=false;
|
||
|
|
+ boolean sloshed=false;
|
||
|
|
+ int nws_length=0;
|
||
|
|
+ int last_length=0;
|
||
|
|
+ int value_length=-1;
|
||
|
|
+ int param_name=-1;
|
||
|
|
+ int param_value=-1;
|
||
|
|
+
|
||
|
|
+ for (int i=0;i<=l;i++)
|
||
|
|
+ {
|
||
|
|
+ char c=i==l?0:value.charAt(i);
|
||
|
|
+
|
||
|
|
+ // Handle quoting https://tools.ietf.org/html/rfc7230#section-3.2.6
|
||
|
|
+ if (quoted && c!=0)
|
||
|
|
+ {
|
||
|
|
+ if (sloshed)
|
||
|
|
+ sloshed=false;
|
||
|
|
+ else
|
||
|
|
+ {
|
||
|
|
+ switch(c)
|
||
|
|
+ {
|
||
|
|
+ case '\\':
|
||
|
|
+ sloshed=true;
|
||
|
|
+ if (!_keepQuotes)
|
||
|
|
+ continue;
|
||
|
|
+ break;
|
||
|
|
+ case '"':
|
||
|
|
+ quoted=false;
|
||
|
|
+ if (!_keepQuotes)
|
||
|
|
+ continue;
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ buffer.append(c);
|
||
|
|
+ nws_length=buffer.length();
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ // Handle common cases
|
||
|
|
+ switch(c)
|
||
|
|
+ {
|
||
|
|
+ case ' ':
|
||
|
|
+ case '\t':
|
||
|
|
+ if (buffer.length()>last_length) // not leading OWS
|
||
|
|
+ buffer.append(c);
|
||
|
|
+ continue;
|
||
|
|
+
|
||
|
|
+ case '"':
|
||
|
|
+ quoted=true;
|
||
|
|
+ if (_keepQuotes)
|
||
|
|
+ {
|
||
|
|
+ if (state==State.PARAM_VALUE && param_value<0)
|
||
|
|
+ param_value=nws_length;
|
||
|
|
+ buffer.append(c);
|
||
|
|
+ }
|
||
|
|
+ else if (state==State.PARAM_VALUE && param_value<0)
|
||
|
|
+ param_value=nws_length;
|
||
|
|
+ nws_length=buffer.length();
|
||
|
|
+ continue;
|
||
|
|
+
|
||
|
|
+ case ';':
|
||
|
|
+ buffer.setLength(nws_length); // trim following OWS
|
||
|
|
+ if (state==State.VALUE)
|
||
|
|
+ {
|
||
|
|
+ parsedValue(buffer);
|
||
|
|
+ value_length=buffer.length();
|
||
|
|
+ }
|
||
|
|
+ else
|
||
|
|
+ parsedParam(buffer,value_length,param_name,param_value);
|
||
|
|
+ nws_length=buffer.length();
|
||
|
|
+ param_name=param_value=-1;
|
||
|
|
+ buffer.append(c);
|
||
|
|
+ last_length=++nws_length;
|
||
|
|
+ state=State.PARAM_NAME;
|
||
|
|
+ continue;
|
||
|
|
+
|
||
|
|
+ case ',':
|
||
|
|
+ case 0:
|
||
|
|
+ if (nws_length>0)
|
||
|
|
+ {
|
||
|
|
+ buffer.setLength(nws_length); // trim following OWS
|
||
|
|
+ switch(state)
|
||
|
|
+ {
|
||
|
|
+ case VALUE:
|
||
|
|
+ parsedValue(buffer);
|
||
|
|
+ value_length=buffer.length();
|
||
|
|
+ break;
|
||
|
|
+ case PARAM_NAME:
|
||
|
|
+ case PARAM_VALUE:
|
||
|
|
+ parsedParam(buffer,value_length,param_name,param_value);
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+ parsedValueAndParams(buffer);
|
||
|
|
+ }
|
||
|
|
+ buffer.setLength(0);
|
||
|
|
+ last_length=0;
|
||
|
|
+ nws_length=0;
|
||
|
|
+ value_length=param_name=param_value=-1;
|
||
|
|
+ state=State.VALUE;
|
||
|
|
+ continue;
|
||
|
|
+
|
||
|
|
+ case '=':
|
||
|
|
+ switch (state)
|
||
|
|
+ {
|
||
|
|
+ case VALUE:
|
||
|
|
+ // It wasn't really a value, it was a param name
|
||
|
|
+ value_length=param_name=0;
|
||
|
|
+ buffer.setLength(nws_length); // trim following OWS
|
||
|
|
+ String param = buffer.toString();
|
||
|
|
+ buffer.setLength(0);
|
||
|
|
+ parsedValue(buffer);
|
||
|
|
+ value_length=buffer.length();
|
||
|
|
+ buffer.append(param);
|
||
|
|
+ buffer.append(c);
|
||
|
|
+ last_length=++nws_length;
|
||
|
|
+ state=State.PARAM_VALUE;
|
||
|
|
+ continue;
|
||
|
|
+
|
||
|
|
+ case PARAM_NAME:
|
||
|
|
+ buffer.setLength(nws_length); // trim following OWS
|
||
|
|
+ buffer.append(c);
|
||
|
|
+ last_length=++nws_length;
|
||
|
|
+ state=State.PARAM_VALUE;
|
||
|
|
+ continue;
|
||
|
|
+
|
||
|
|
+ case PARAM_VALUE:
|
||
|
|
+ if (param_value<0)
|
||
|
|
+ param_value=nws_length;
|
||
|
|
+ buffer.append(c);
|
||
|
|
+ nws_length=buffer.length();
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+ continue;
|
||
|
|
+
|
||
|
|
+ default:
|
||
|
|
+ {
|
||
|
|
+ switch (state)
|
||
|
|
+ {
|
||
|
|
+ case VALUE:
|
||
|
|
+ {
|
||
|
|
+ buffer.append(c);
|
||
|
|
+ nws_length=buffer.length();
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ case PARAM_NAME:
|
||
|
|
+ {
|
||
|
|
+ if (param_name<0)
|
||
|
|
+ param_name=nws_length;
|
||
|
|
+ buffer.append(c);
|
||
|
|
+ nws_length=buffer.length();
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ case PARAM_VALUE:
|
||
|
|
+ {
|
||
|
|
+ if (param_value<0)
|
||
|
|
+ param_value=nws_length;
|
||
|
|
+ buffer.append(c);
|
||
|
|
+ nws_length=buffer.length();
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /**
|
||
|
|
+ * Called when a value and it's parameters has been parsed
|
||
|
|
+ * @param buffer Containing the trimmed value and parameters
|
||
|
|
+ */
|
||
|
|
+ protected void parsedValueAndParams(StringBuffer buffer)
|
||
|
|
+ {
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /**
|
||
|
|
+ * Called when a value has been parsed (prior to any parameters)
|
||
|
|
+ * @param buffer Containing the trimmed value, which may be mutated
|
||
|
|
+ */
|
||
|
|
+ protected void parsedValue(StringBuffer buffer)
|
||
|
|
+ {
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /**
|
||
|
|
+ * Called when a parameter has been parsed
|
||
|
|
+ * @param buffer Containing the trimmed value and all parameters, which may be mutated
|
||
|
|
+ * @param valueLength The length of the value
|
||
|
|
+ * @param paramName The index of the start of the parameter just parsed
|
||
|
|
+ * @param paramValue The index of the start of the parameter value just parsed, or -1
|
||
|
|
+ */
|
||
|
|
+ protected void parsedParam(StringBuffer buffer, int valueLength, int paramName, int paramValue)
|
||
|
|
+ {
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+}
|
||
|
|
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java
|
||
|
|
index be3990794ed..e098a68e635 100644
|
||
|
|
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java
|
||
|
|
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java
|
||
|
|
@@ -30,7 +30,7 @@
|
||
|
|
import org.eclipse.jetty.http.HttpFields;
|
||
|
|
import org.eclipse.jetty.http.HttpHeader;
|
||
|
|
import org.eclipse.jetty.http.HttpScheme;
|
||
|
|
-import org.eclipse.jetty.http.QuotedCSV;
|
||
|
|
+import org.eclipse.jetty.http.QuotedCSVParser;
|
||
|
|
import org.eclipse.jetty.server.HttpConfiguration.Customizer;
|
||
|
|
import org.eclipse.jetty.util.ArrayTrie;
|
||
|
|
import org.eclipse.jetty.util.HostPort;
|
||
|
|
@@ -42,8 +42,6 @@
|
||
|
|
import static java.lang.invoke.MethodType.methodType;
|
||
|
|
|
||
|
|
|
||
|
|
-/* ------------------------------------------------------------ */
|
||
|
|
-
|
||
|
|
/**
|
||
|
|
* Customize Requests for Proxy Forwarding.
|
||
|
|
* <p>
|
||
|
|
@@ -157,7 +155,7 @@ public String getForcedHost()
|
||
|
|
*/
|
||
|
|
public void setForcedHost(String hostAndPort)
|
||
|
|
{
|
||
|
|
- _forcedHost = new HostPortHttpField(hostAndPort);
|
||
|
|
+ _forcedHost = new HostPortHttpField(new ForcedHostPort(hostAndPort));
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
@@ -377,76 +375,26 @@ public void customize(Connector connector, HttpConfiguration config, Request req
|
||
|
|
throw new RuntimeException(e);
|
||
|
|
}
|
||
|
|
|
||
|
|
- // Determine host
|
||
|
|
- if (_forcedHost != null)
|
||
|
|
- {
|
||
|
|
- // Update host header
|
||
|
|
- httpFields.put(_forcedHost);
|
||
|
|
- request.setAuthority(_forcedHost.getHost(), _forcedHost.getPort());
|
||
|
|
- }
|
||
|
|
- else if (forwarded._rfc7239 != null && forwarded._rfc7239._host != null)
|
||
|
|
- {
|
||
|
|
- HostPortHttpField auth = forwarded._rfc7239._host;
|
||
|
|
- httpFields.put(auth);
|
||
|
|
- request.setAuthority(auth.getHost(), auth.getPort());
|
||
|
|
- }
|
||
|
|
- else if (forwarded._forwardedHost != null)
|
||
|
|
- {
|
||
|
|
- HostPortHttpField auth = new HostPortHttpField(forwarded._forwardedHost);
|
||
|
|
- httpFields.put(auth);
|
||
|
|
- request.setAuthority(auth.getHost(), auth.getPort());
|
||
|
|
- }
|
||
|
|
- else if (_proxyAsAuthority)
|
||
|
|
+ if (forwarded._proto!=null)
|
||
|
|
{
|
||
|
|
- if (forwarded._rfc7239 != null && forwarded._rfc7239._by != null)
|
||
|
|
- {
|
||
|
|
- HostPortHttpField auth = forwarded._rfc7239._by;
|
||
|
|
- httpFields.put(auth);
|
||
|
|
- request.setAuthority(auth.getHost(), auth.getPort());
|
||
|
|
- }
|
||
|
|
- else if (forwarded._forwardedServer != null)
|
||
|
|
- {
|
||
|
|
- request.setAuthority(forwarded._forwardedServer, request.getServerPort());
|
||
|
|
- }
|
||
|
|
+ request.setScheme(forwarded._proto);
|
||
|
|
+ if (forwarded._proto.equalsIgnoreCase(config.getSecureScheme()))
|
||
|
|
+ request.setSecure(true);
|
||
|
|
}
|
||
|
|
|
||
|
|
- // handle remote end identifier
|
||
|
|
- if (forwarded._rfc7239 != null && forwarded._rfc7239._for != null)
|
||
|
|
- {
|
||
|
|
- request.setRemoteAddr(InetSocketAddress.createUnresolved(forwarded._rfc7239._for.getHost(), forwarded._rfc7239._for.getPort()));
|
||
|
|
- }
|
||
|
|
- else if (forwarded._forwardedFor != null)
|
||
|
|
+ if (forwarded._host!=null)
|
||
|
|
{
|
||
|
|
- int port = (forwarded._forwardedPort > 0)
|
||
|
|
- ? forwarded._forwardedPort
|
||
|
|
- : (forwarded._forwardedFor.getPort() > 0)
|
||
|
|
- ? forwarded._forwardedFor.getPort()
|
||
|
|
- : request.getRemotePort();
|
||
|
|
- request.setRemoteAddr(InetSocketAddress.createUnresolved(forwarded._forwardedFor.getHost(), port));
|
||
|
|
+ httpFields.put(new HostPortHttpField(forwarded._host));
|
||
|
|
+ request.setAuthority(forwarded._host.getHost(), forwarded._host.getPort());
|
||
|
|
}
|
||
|
|
|
||
|
|
- // handle protocol identifier
|
||
|
|
- if (forwarded._rfc7239 != null && forwarded._rfc7239._proto != null)
|
||
|
|
+ if (forwarded._for!=null)
|
||
|
|
{
|
||
|
|
- request.setScheme(forwarded._rfc7239._proto);
|
||
|
|
- if (forwarded._rfc7239._proto.equals(config.getSecureScheme()))
|
||
|
|
- request.setSecure(true);
|
||
|
|
- }
|
||
|
|
- else if (forwarded._forwardedProto != null)
|
||
|
|
- {
|
||
|
|
- request.setScheme(forwarded._forwardedProto);
|
||
|
|
- if (forwarded._forwardedProto.equals(config.getSecureScheme()))
|
||
|
|
- request.setSecure(true);
|
||
|
|
- }
|
||
|
|
- else if (forwarded._forwardedHttps != null && ("on".equalsIgnoreCase(forwarded._forwardedHttps) || "true".equalsIgnoreCase(forwarded._forwardedHttps)))
|
||
|
|
- {
|
||
|
|
- request.setScheme(HttpScheme.HTTPS.asString());
|
||
|
|
- if (HttpScheme.HTTPS.asString().equals(config.getSecureScheme()))
|
||
|
|
- request.setSecure(true);
|
||
|
|
+ int port = forwarded._for.getPort()>0 ? forwarded._for.getPort() : request.getRemotePort();
|
||
|
|
+ request.setRemoteAddr(InetSocketAddress.createUnresolved(forwarded._for.getHost(),port));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
- /* ------------------------------------------------------------ */
|
||
|
|
protected String getLeftMost(String headerValue)
|
||
|
|
{
|
||
|
|
if (headerValue == null)
|
||
|
|
@@ -464,26 +412,6 @@ protected String getLeftMost(String headerValue)
|
||
|
|
return headerValue.substring(0, commaIndex).trim();
|
||
|
|
}
|
||
|
|
|
||
|
|
- protected HostPort getRemoteAddr(String headerValue)
|
||
|
|
- {
|
||
|
|
- String leftMost = getLeftMost(headerValue);
|
||
|
|
- if (leftMost == null)
|
||
|
|
- {
|
||
|
|
- return null;
|
||
|
|
- }
|
||
|
|
-
|
||
|
|
- try
|
||
|
|
- {
|
||
|
|
- return new HostPort(leftMost);
|
||
|
|
- }
|
||
|
|
- catch (Exception e)
|
||
|
|
- {
|
||
|
|
- // failed to parse in host[:port] format
|
||
|
|
- LOG.ignore(e);
|
||
|
|
- return null;
|
||
|
|
- }
|
||
|
|
- }
|
||
|
|
-
|
||
|
|
@Override
|
||
|
|
public String toString()
|
||
|
|
{
|
||
|
|
@@ -507,48 +435,6 @@ public void setHostHeader(String hostHeader)
|
||
|
|
_forcedHost = new HostPortHttpField(hostHeader);
|
||
|
|
}
|
||
|
|
|
||
|
|
- private final class RFC7239 extends QuotedCSV
|
||
|
|
- {
|
||
|
|
- HostPortHttpField _by;
|
||
|
|
- HostPortHttpField _for;
|
||
|
|
- HostPortHttpField _host;
|
||
|
|
- String _proto;
|
||
|
|
-
|
||
|
|
- private RFC7239()
|
||
|
|
- {
|
||
|
|
- super(false);
|
||
|
|
- }
|
||
|
|
-
|
||
|
|
- @Override
|
||
|
|
- protected void parsedParam(StringBuffer buffer, int valueLength, int paramName, int paramValue)
|
||
|
|
- {
|
||
|
|
- if (valueLength == 0 && paramValue > paramName)
|
||
|
|
- {
|
||
|
|
- String name = StringUtil.asciiToLowerCase(buffer.substring(paramName, paramValue - 1));
|
||
|
|
- String value = buffer.substring(paramValue);
|
||
|
|
- switch (name)
|
||
|
|
- {
|
||
|
|
- case "by":
|
||
|
|
- if (_by == null && !value.startsWith("_") && !"unknown".equals(value))
|
||
|
|
- _by = new HostPortHttpField(value);
|
||
|
|
- break;
|
||
|
|
- case "for":
|
||
|
|
- if (_for == null && !value.startsWith("_") && !"unknown".equals(value))
|
||
|
|
- _for = new HostPortHttpField(value);
|
||
|
|
- break;
|
||
|
|
- case "host":
|
||
|
|
- if (_host == null)
|
||
|
|
- _host = new HostPortHttpField(value);
|
||
|
|
- break;
|
||
|
|
- case "proto":
|
||
|
|
- if (_proto == null)
|
||
|
|
- _proto = value;
|
||
|
|
- break;
|
||
|
|
- }
|
||
|
|
- }
|
||
|
|
- }
|
||
|
|
- }
|
||
|
|
-
|
||
|
|
private void updateHandles()
|
||
|
|
{
|
||
|
|
int size = 0;
|
||
|
|
@@ -589,23 +475,52 @@ private void updateHandles()
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
- private class Forwarded
|
||
|
|
+ private static class ForcedHostPort extends HostPort
|
||
|
|
+ {
|
||
|
|
+ ForcedHostPort(String authority)
|
||
|
|
+ {
|
||
|
|
+ super(authority);
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ private static class XHostPort extends HostPort
|
||
|
|
+ {
|
||
|
|
+ XHostPort(String authority)
|
||
|
|
+ {
|
||
|
|
+ super(authority);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ XHostPort(String host, int port)
|
||
|
|
+ {
|
||
|
|
+ super(host, port);
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ private static class Rfc7239HostPort extends HostPort
|
||
|
|
+ {
|
||
|
|
+ Rfc7239HostPort(String authority)
|
||
|
|
+ {
|
||
|
|
+ super(authority);
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ private class Forwarded extends QuotedCSVParser
|
||
|
|
{
|
||
|
|
HttpConfiguration _config;
|
||
|
|
Request _request;
|
||
|
|
|
||
|
|
- RFC7239 _rfc7239 = null;
|
||
|
|
- String _forwardedHost = null;
|
||
|
|
- String _forwardedServer = null;
|
||
|
|
- String _forwardedProto = null;
|
||
|
|
- HostPort _forwardedFor = null;
|
||
|
|
- int _forwardedPort = -1;
|
||
|
|
- String _forwardedHttps = null;
|
||
|
|
+ boolean _protoRfc7239;
|
||
|
|
+ String _proto;
|
||
|
|
+ HostPort _for;
|
||
|
|
+ HostPort _host;
|
||
|
|
|
||
|
|
public Forwarded(Request request, HttpConfiguration config)
|
||
|
|
{
|
||
|
|
+ super(false);
|
||
|
|
_request = request;
|
||
|
|
_config = config;
|
||
|
|
+ if (_forcedHost!=null)
|
||
|
|
+ _host = _forcedHost.getHostPort();
|
||
|
|
}
|
||
|
|
|
||
|
|
public void handleCipherSuite(HttpField field)
|
||
|
|
@@ -630,39 +545,87 @@ public void handleSslSessionId(HttpField field)
|
||
|
|
|
||
|
|
public void handleHost(HttpField field)
|
||
|
|
{
|
||
|
|
- _forwardedHost = getLeftMost(field.getValue());
|
||
|
|
+ if (_host==null)
|
||
|
|
+ _host = new XHostPort(getLeftMost(field.getValue()));
|
||
|
|
}
|
||
|
|
|
||
|
|
public void handleServer(HttpField field)
|
||
|
|
{
|
||
|
|
- _forwardedServer = getLeftMost(field.getValue());
|
||
|
|
+ if (_proxyAsAuthority && _host==null)
|
||
|
|
+ _host = new XHostPort(getLeftMost(field.getValue()));
|
||
|
|
}
|
||
|
|
|
||
|
|
public void handleProto(HttpField field)
|
||
|
|
{
|
||
|
|
- _forwardedProto = getLeftMost(field.getValue());
|
||
|
|
+ if (_proto==null)
|
||
|
|
+ _proto = getLeftMost(field.getValue());
|
||
|
|
}
|
||
|
|
|
||
|
|
public void handleFor(HttpField field)
|
||
|
|
{
|
||
|
|
- _forwardedFor = getRemoteAddr(field.getValue());
|
||
|
|
+ if (_for==null)
|
||
|
|
+ _for = new XHostPort(getLeftMost(field.getValue()));
|
||
|
|
+ else if (_for instanceof XHostPort && "unknown".equals(_for.getHost()))
|
||
|
|
+ _for = new XHostPort(HostPort.normalizeHost(getLeftMost(field.getValue())),_for.getPort());
|
||
|
|
}
|
||
|
|
|
||
|
|
public void handlePort(HttpField field)
|
||
|
|
{
|
||
|
|
- _forwardedPort = field.getIntValue();
|
||
|
|
+ if (_for == null)
|
||
|
|
+ _for = new XHostPort("unknown", field.getIntValue());
|
||
|
|
+ else if (_for instanceof XHostPort && _for.getPort()<=0)
|
||
|
|
+ _for = new XHostPort(HostPort.normalizeHost(_for.getHost()), field.getIntValue());
|
||
|
|
}
|
||
|
|
|
||
|
|
public void handleHttps(HttpField field)
|
||
|
|
{
|
||
|
|
- _forwardedHttps = getLeftMost(field.getValue());
|
||
|
|
+ if (_proto==null && ("on".equalsIgnoreCase(field.getValue()) || "true".equalsIgnoreCase(field.getValue())))
|
||
|
|
+ _proto = HttpScheme.HTTPS.asString();
|
||
|
|
}
|
||
|
|
|
||
|
|
public void handleRFC7239(HttpField field)
|
||
|
|
{
|
||
|
|
- if (_rfc7239 == null)
|
||
|
|
- _rfc7239 = new RFC7239();
|
||
|
|
- _rfc7239.addValue(field.getValue());
|
||
|
|
+ addValue(field.getValue());
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ @Override
|
||
|
|
+ protected void parsedParam(StringBuffer buffer, int valueLength, int paramName, int paramValue)
|
||
|
|
+ {
|
||
|
|
+ if (valueLength == 0 && paramValue > paramName)
|
||
|
|
+ {
|
||
|
|
+ String name = StringUtil.asciiToLowerCase(buffer.substring(paramName, paramValue - 1));
|
||
|
|
+ String value = buffer.substring(paramValue);
|
||
|
|
+ switch (name)
|
||
|
|
+ {
|
||
|
|
+ case "by":
|
||
|
|
+ if (!_proxyAsAuthority)
|
||
|
|
+ break;
|
||
|
|
+ if (value.startsWith("_") || "unknown".equals(value))
|
||
|
|
+ break;
|
||
|
|
+ if (_host == null || _host instanceof XHostPort)
|
||
|
|
+ _host = new Rfc7239HostPort(value);
|
||
|
|
+ break;
|
||
|
|
+ case "for":
|
||
|
|
+ if (value.startsWith("_") || "unknown".equals(value))
|
||
|
|
+ break;
|
||
|
|
+ if (_for == null || _for instanceof XHostPort)
|
||
|
|
+ _for = new Rfc7239HostPort(value);
|
||
|
|
+ break;
|
||
|
|
+ case "host":
|
||
|
|
+ if (value.startsWith("_") || "unknown".equals(value))
|
||
|
|
+ break;
|
||
|
|
+ if (_host == null || _host instanceof XHostPort)
|
||
|
|
+ _host = new Rfc7239HostPort(value);
|
||
|
|
+ break;
|
||
|
|
+ case "proto":
|
||
|
|
+ if (_proto == null || !_protoRfc7239)
|
||
|
|
+ {
|
||
|
|
+ _protoRfc7239 = true;
|
||
|
|
+ _proto = value;
|
||
|
|
+ }
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ForwardedRequestCustomizerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ForwardedRequestCustomizerTest.java
|
||
|
|
index 0a1cecec0c2..db8a9ad64e0 100644
|
||
|
|
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/ForwardedRequestCustomizerTest.java
|
||
|
|
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ForwardedRequestCustomizerTest.java
|
||
|
|
@@ -95,6 +95,68 @@ public void destroy() throws Exception
|
||
|
|
_server.join();
|
||
|
|
}
|
||
|
|
|
||
|
|
+ @Test
|
||
|
|
+ public void testHostIpv4() throws Exception
|
||
|
|
+ {
|
||
|
|
+ String response=_connector.getResponse(
|
||
|
|
+ "GET / HTTP/1.1\n"+
|
||
|
|
+ "Host: 1.2.3.4:2222\n"+
|
||
|
|
+ "\n");
|
||
|
|
+ assertThat(response, Matchers.containsString("200 OK"));
|
||
|
|
+ assertEquals("http",_results.poll());
|
||
|
|
+ assertEquals("1.2.3.4",_results.poll());
|
||
|
|
+ assertEquals("2222",_results.poll());
|
||
|
|
+ assertEquals("0.0.0.0",_results.poll());
|
||
|
|
+ assertEquals("0",_results.poll());
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ @Test
|
||
|
|
+ public void testHostIpv6() throws Exception
|
||
|
|
+ {
|
||
|
|
+ String response=_connector.getResponse(
|
||
|
|
+ "GET / HTTP/1.1\n"+
|
||
|
|
+ "Host: [::1]:2222\n"+
|
||
|
|
+ "\n");
|
||
|
|
+ assertThat(response, Matchers.containsString("200 OK"));
|
||
|
|
+ assertEquals("http",_results.poll());
|
||
|
|
+ assertEquals("[::1]",_results.poll());
|
||
|
|
+ assertEquals("2222",_results.poll());
|
||
|
|
+ assertEquals("0.0.0.0",_results.poll());
|
||
|
|
+ assertEquals("0",_results.poll());
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+ @Test
|
||
|
|
+ public void testURIIpv4() throws Exception
|
||
|
|
+ {
|
||
|
|
+ String response=_connector.getResponse(
|
||
|
|
+ "GET http://1.2.3.4:2222/ HTTP/1.1\n"+
|
||
|
|
+ "Host: wrong\n"+
|
||
|
|
+ "\n");
|
||
|
|
+ assertThat(response, Matchers.containsString("200 OK"));
|
||
|
|
+ assertEquals("http",_results.poll());
|
||
|
|
+ assertEquals("1.2.3.4",_results.poll());
|
||
|
|
+ assertEquals("2222",_results.poll());
|
||
|
|
+ assertEquals("0.0.0.0",_results.poll());
|
||
|
|
+ assertEquals("0",_results.poll());
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ @Test
|
||
|
|
+ public void testURIIpv6() throws Exception
|
||
|
|
+ {
|
||
|
|
+ String response=_connector.getResponse(
|
||
|
|
+ "GET http://[::1]:2222/ HTTP/1.1\n"+
|
||
|
|
+ "Host: wrong\n"+
|
||
|
|
+ "\n");
|
||
|
|
+ assertThat(response, Matchers.containsString("200 OK"));
|
||
|
|
+ assertEquals("http",_results.poll());
|
||
|
|
+ assertEquals("[::1]",_results.poll());
|
||
|
|
+ assertEquals("2222",_results.poll());
|
||
|
|
+ assertEquals("0.0.0.0",_results.poll());
|
||
|
|
+ assertEquals("0",_results.poll());
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
|
||
|
|
@Test
|
||
|
|
public void testRFC7239_Examples_4() throws Exception
|
||
|
|
@@ -208,6 +270,7 @@ public void testFor() throws Exception
|
||
|
|
"GET / HTTP/1.1\n"+
|
||
|
|
"Host: myhost\n"+
|
||
|
|
"X-Forwarded-For: 10.9.8.7,6.5.4.3\n"+
|
||
|
|
+ "X-Forwarded-For: 8.9.8.7,7.5.4.3\n"+
|
||
|
|
"\n");
|
||
|
|
assertThat(response, Matchers.containsString("200 OK"));
|
||
|
|
assertEquals("http",_results.poll());
|
||
|
|
@@ -264,6 +327,21 @@ public void testForIpv6AndPort() throws Exception
|
||
|
|
assertEquals("80",_results.poll());
|
||
|
|
assertEquals("[1:2:3:4:5:6:7:8]",_results.poll());
|
||
|
|
assertEquals("2222",_results.poll());
|
||
|
|
+
|
||
|
|
+ response=_connector.getResponse(
|
||
|
|
+ "GET / HTTP/1.1\n"+
|
||
|
|
+ "Host: myhost\n"+
|
||
|
|
+ "X-Forwarded-Port: 2222\n"+
|
||
|
|
+ "X-Forwarded-For: 1:2:3:4:5:6:7:8\n"+
|
||
|
|
+ "X-Forwarded-For: 7:7:7:7:7:7:7:7\n"+
|
||
|
|
+ "X-Forwarded-Port: 3333\n"+
|
||
|
|
+ "\n");
|
||
|
|
+ assertThat(response, Matchers.containsString("200 OK"));
|
||
|
|
+ assertEquals("http",_results.poll());
|
||
|
|
+ assertEquals("myhost",_results.poll());
|
||
|
|
+ assertEquals("80",_results.poll());
|
||
|
|
+ assertEquals("[1:2:3:4:5:6:7:8]",_results.poll());
|
||
|
|
+ assertEquals("2222",_results.poll());
|
||
|
|
}
|
||
|
|
|
||
|
|
@Test
|
||
|
|
@@ -355,7 +433,26 @@ public void testSslCertificate() throws Exception
|
||
|
|
assertTrue(_wasSecure.get());
|
||
|
|
assertEquals("0123456789abcdef",_sslCertificate.get());
|
||
|
|
}
|
||
|
|
-
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+ @Test
|
||
|
|
+ public void testMixed() throws Exception
|
||
|
|
+ {
|
||
|
|
+ String response = _connector.getResponse(
|
||
|
|
+ "GET / HTTP/1.1\n" +
|
||
|
|
+ "Host: myhost\n" +
|
||
|
|
+ "X-Forwarded-For: 11.9.8.7:1111,8.5.4.3:2222\n" +
|
||
|
|
+ "X-Forwarded-Port: 3333\n" +
|
||
|
|
+ "Forwarded: for=192.0.2.43,for=198.51.100.17;by=203.0.113.60;proto=http;host=example.com\n"+
|
||
|
|
+ "X-Forwarded-For: 11.9.8.7:1111,8.5.4.3:2222\n" +
|
||
|
|
+ "\n");
|
||
|
|
+
|
||
|
|
+ assertEquals("http",_results.poll());
|
||
|
|
+ assertEquals("example.com",_results.poll());
|
||
|
|
+ assertEquals("80",_results.poll());
|
||
|
|
+ assertEquals("192.0.2.43",_results.poll());
|
||
|
|
+ assertEquals("0",_results.poll());
|
||
|
|
+ }
|
||
|
|
|
||
|
|
|
||
|
|
interface RequestTester
|