!15 fix CVE-2020-27223
From: @zhanghua1831 Reviewed-by: @wang_yue111,@small_leek,@wangchong1995924 Signed-off-by: @small_leek,@wangchong1995924
This commit is contained in:
commit
ca866b6cd7
545
CVE-2020-27223-pre-1.patch
Normal file
545
CVE-2020-27223-pre-1.patch
Normal file
@ -0,0 +1,545 @@
|
|||||||
|
From 8011c48685e78850a88e7cc06650f678a375037d Mon Sep 17 00:00:00 2001
|
||||||
|
From: Greg Wilkins <gregw@webtide.com>
|
||||||
|
Date: Thu, 28 Feb 2019 18:37:02 +1100
|
||||||
|
Subject: [PATCH 1/4] Issue #3404 Updated QCSV Double usage
|
||||||
|
|
||||||
|
Signed-off-by: Greg Wilkins <gregw@webtide.com>
|
||||||
|
---
|
||||||
|
.../eclipse/jetty/http/QuotedQualityCSV.java | 58 ++++++++++---------
|
||||||
|
1 file changed, 30 insertions(+), 28 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java b/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java
|
||||||
|
index 61cee88bfd5..c7047c57a4b 100644
|
||||||
|
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java
|
||||||
|
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java
|
||||||
|
@@ -25,6 +25,8 @@
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
+import org.eclipse.jetty.util.log.Log;
|
||||||
|
+
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* Implements a quoted comma separated list of quality values
|
||||||
|
@@ -37,21 +39,16 @@
|
||||||
|
*/
|
||||||
|
public class QuotedQualityCSV extends QuotedCSV implements Iterable<String>
|
||||||
|
{
|
||||||
|
- private final static Double ZERO=new Double(0.0);
|
||||||
|
- private final static Double ONE=new Double(1.0);
|
||||||
|
-
|
||||||
|
+ private final static Double ZERO = 0.0D;
|
||||||
|
+ private final static Double ONE = 1.0D;
|
||||||
|
|
||||||
|
/**
|
||||||
|
- * Function to apply a most specific MIME encoding secondary ordering
|
||||||
|
+ * Lambda to apply a most specific MIME encoding secondary ordering
|
||||||
|
*/
|
||||||
|
- public static Function<String, Integer> MOST_SPECIFIC = new Function<String, Integer>()
|
||||||
|
+ public static Function<String, Integer> MOST_SPECIFIC = s ->
|
||||||
|
{
|
||||||
|
- @Override
|
||||||
|
- public Integer apply(String s)
|
||||||
|
- {
|
||||||
|
- String[] elements = s.split("/");
|
||||||
|
- return 1000000*elements.length+1000*elements[0].length()+elements[elements.length-1].length();
|
||||||
|
- }
|
||||||
|
+ String[] elements = s.split("/");
|
||||||
|
+ return 1000000*elements.length+1000*elements[0].length()+elements[elements.length-1].length();
|
||||||
|
};
|
||||||
|
|
||||||
|
private final List<Double> _quality = new ArrayList<>();
|
||||||
|
@@ -74,7 +71,8 @@ public QuotedQualityCSV()
|
||||||
|
*/
|
||||||
|
public QuotedQualityCSV(String[] preferredOrder)
|
||||||
|
{
|
||||||
|
- this((s) -> {
|
||||||
|
+ this((s) ->
|
||||||
|
+ {
|
||||||
|
for (int i=0;i<preferredOrder.length;++i)
|
||||||
|
if (preferredOrder[i].equals(s))
|
||||||
|
return preferredOrder.length-i;
|
||||||
|
@@ -101,6 +99,8 @@ public QuotedQualityCSV(Function<String, Integer> secondaryOrdering)
|
||||||
|
protected void parsedValue(StringBuffer buffer)
|
||||||
|
{
|
||||||
|
super.parsedValue(buffer);
|
||||||
|
+
|
||||||
|
+ // Assume a quality of ONE
|
||||||
|
_quality.add(ONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -108,30 +108,32 @@ protected void parsedValue(StringBuffer buffer)
|
||||||
|
@Override
|
||||||
|
protected void parsedParam(StringBuffer buffer, int valueLength, int paramName, int paramValue)
|
||||||
|
{
|
||||||
|
- if (paramName<0)
|
||||||
|
+ if (paramName < 0)
|
||||||
|
{
|
||||||
|
- if (buffer.charAt(buffer.length()-1)==';')
|
||||||
|
- buffer.setLength(buffer.length()-1);
|
||||||
|
+ if (buffer.charAt(buffer.length() - 1) == ';')
|
||||||
|
+ buffer.setLength(buffer.length() - 1);
|
||||||
|
}
|
||||||
|
- else if (paramValue>=0 &&
|
||||||
|
- buffer.charAt(paramName)=='q' && paramValue>paramName &&
|
||||||
|
- buffer.length()>=paramName && buffer.charAt(paramName+1)=='=')
|
||||||
|
+ else if (paramValue >= 0 &&
|
||||||
|
+ buffer.charAt(paramName) == 'q' && paramValue > paramName &&
|
||||||
|
+ buffer.length() >= paramName && buffer.charAt(paramName + 1) == '=')
|
||||||
|
{
|
||||||
|
Double q;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
- q=(_keepQuotes && buffer.charAt(paramValue)=='"')
|
||||||
|
- ?new Double(buffer.substring(paramValue+1,buffer.length()-1))
|
||||||
|
- :new Double(buffer.substring(paramValue));
|
||||||
|
+ q = (_keepQuotes && buffer.charAt(paramValue) == '"')
|
||||||
|
+ ? Double.valueOf(buffer.substring(paramValue + 1, buffer.length() - 1))
|
||||||
|
+ : Double.valueOf(buffer.substring(paramValue));
|
||||||
|
}
|
||||||
|
- catch(Exception e)
|
||||||
|
+ catch (Exception e)
|
||||||
|
{
|
||||||
|
- q=ZERO;
|
||||||
|
- }
|
||||||
|
- buffer.setLength(Math.max(0,paramName-1));
|
||||||
|
-
|
||||||
|
- if (!ONE.equals(q))
|
||||||
|
- _quality.set(_quality.size()-1,q);
|
||||||
|
+ Log.getLogger(QuotedQualityCSV.class).ignore(e);
|
||||||
|
+ q = ZERO;
|
||||||
|
+ }
|
||||||
|
+ buffer.setLength(Math.max(0, paramName - 1));
|
||||||
|
+
|
||||||
|
+ if (!ONE.equals(q))
|
||||||
|
+ // replace assumed quality
|
||||||
|
+ _quality.set(_quality.size() - 1, q);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
From ca8a10a9d5a50e7d814c65134144f776bff1c07a Mon Sep 17 00:00:00 2001
|
||||||
|
From: Greg Wilkins <gregw@webtide.com>
|
||||||
|
Date: Fri, 1 Mar 2019 10:17:02 +1100
|
||||||
|
Subject: [PATCH 2/4] Issue #3404 Cleanup QCSV mime ordering
|
||||||
|
|
||||||
|
Signed-off-by: Greg Wilkins <gregw@webtide.com>
|
||||||
|
---
|
||||||
|
.../org/eclipse/jetty/http/HttpFields.java | 16 ++++++++-
|
||||||
|
.../eclipse/jetty/http/QuotedQualityCSV.java | 35 ++++++++++---------
|
||||||
|
.../jetty/http/QuotedQualityCSVTest.java | 2 +-
|
||||||
|
.../jetty/server/handler/ErrorHandler.java | 3 +-
|
||||||
|
4 files changed, 37 insertions(+), 19 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java
|
||||||
|
index 14c4335eb5a..5a8b53013a7 100644
|
||||||
|
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java
|
||||||
|
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java
|
||||||
|
@@ -31,6 +31,7 @@
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.StringTokenizer;
|
||||||
|
+import java.util.function.Function;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import java.util.stream.StreamSupport;
|
||||||
|
|
||||||
|
@@ -437,6 +438,19 @@ protected String addCSV(QuotedCSV existing,String... values)
|
||||||
|
* @param header The header
|
||||||
|
*/
|
||||||
|
public List<String> getQualityCSV(HttpHeader header)
|
||||||
|
+ {
|
||||||
|
+ return getQualityCSV(header,null);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Get multiple field values of the same name, split and
|
||||||
|
+ * sorted as a {@link QuotedQualityCSV}
|
||||||
|
+ *
|
||||||
|
+ * @param header The header
|
||||||
|
+ * @param secondaryOrdering Function to apply an ordering other than specified by quality
|
||||||
|
+ * @return List the values in quality order with the q param and OWS stripped
|
||||||
|
+ */
|
||||||
|
+ public List<String> getQualityCSV(HttpHeader header, Function<String, Integer> secondaryOrdering)
|
||||||
|
{
|
||||||
|
QuotedQualityCSV values = null;
|
||||||
|
for (HttpField f : this)
|
||||||
|
@@ -444,7 +458,7 @@ protected String addCSV(QuotedCSV existing,String... values)
|
||||||
|
if (f.getHeader()==header)
|
||||||
|
{
|
||||||
|
if (values==null)
|
||||||
|
- values = new QuotedQualityCSV();
|
||||||
|
+ values = new QuotedQualityCSV(secondaryOrdering);
|
||||||
|
values.addValue(f.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java b/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java
|
||||||
|
index c7047c57a4b..498d4e01491 100644
|
||||||
|
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java
|
||||||
|
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java
|
||||||
|
@@ -38,17 +38,20 @@
|
||||||
|
* @see "https://tools.ietf.org/html/rfc7231#section-5.3.1"
|
||||||
|
*/
|
||||||
|
public class QuotedQualityCSV extends QuotedCSV implements Iterable<String>
|
||||||
|
-{
|
||||||
|
- private final static Double ZERO = 0.0D;
|
||||||
|
- private final static Double ONE = 1.0D;
|
||||||
|
-
|
||||||
|
+{
|
||||||
|
/**
|
||||||
|
- * Lambda to apply a most specific MIME encoding secondary ordering
|
||||||
|
+ * Lambda to apply a most specific MIME encoding secondary ordering.
|
||||||
|
+ * @see "https://tools.ietf.org/html/rfc7231#section-5.3.2"
|
||||||
|
*/
|
||||||
|
- public static Function<String, Integer> MOST_SPECIFIC = s ->
|
||||||
|
+ public static Function<String, Integer> MOST_SPECIFIC_MIME_ORDERING = s ->
|
||||||
|
{
|
||||||
|
- String[] elements = s.split("/");
|
||||||
|
- return 1000000*elements.length+1000*elements[0].length()+elements[elements.length-1].length();
|
||||||
|
+ if ("*/*".equals(s))
|
||||||
|
+ return 0;
|
||||||
|
+ if (s.endsWith("/*"))
|
||||||
|
+ return 1;
|
||||||
|
+ if (s.indexOf(';')<0)
|
||||||
|
+ return 2;
|
||||||
|
+ return 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
private final List<Double> _quality = new ArrayList<>();
|
||||||
|
@@ -61,7 +64,7 @@
|
||||||
|
*/
|
||||||
|
public QuotedQualityCSV()
|
||||||
|
{
|
||||||
|
- this((s) -> 0);
|
||||||
|
+ this((Function)null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
@@ -91,7 +94,7 @@ public QuotedQualityCSV(String[] preferredOrder)
|
||||||
|
*/
|
||||||
|
public QuotedQualityCSV(Function<String, Integer> secondaryOrdering)
|
||||||
|
{
|
||||||
|
- this._secondaryOrdering = secondaryOrdering;
|
||||||
|
+ this._secondaryOrdering = secondaryOrdering == null ? s->0 : secondaryOrdering;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
@@ -101,7 +104,7 @@ protected void parsedValue(StringBuffer buffer)
|
||||||
|
super.parsedValue(buffer);
|
||||||
|
|
||||||
|
// Assume a quality of ONE
|
||||||
|
- _quality.add(ONE);
|
||||||
|
+ _quality.add(1.0D);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
@@ -127,11 +130,11 @@ else if (paramValue >= 0 &&
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.getLogger(QuotedQualityCSV.class).ignore(e);
|
||||||
|
- q = ZERO;
|
||||||
|
+ q = 0.0D;
|
||||||
|
}
|
||||||
|
buffer.setLength(Math.max(0, paramName - 1));
|
||||||
|
|
||||||
|
- if (!ONE.equals(q))
|
||||||
|
+ if (!((Double)1.0D).equals(q))
|
||||||
|
// replace assumed quality
|
||||||
|
_quality.set(_quality.size() - 1, q);
|
||||||
|
}
|
||||||
|
@@ -157,7 +160,7 @@ protected void sort()
|
||||||
|
{
|
||||||
|
_sorted=true;
|
||||||
|
|
||||||
|
- Double last = ZERO;
|
||||||
|
+ Double last = 0.0D;
|
||||||
|
int lastSecondaryOrder = Integer.MIN_VALUE;
|
||||||
|
|
||||||
|
for (int i = _values.size(); i-- > 0;)
|
||||||
|
@@ -172,7 +175,7 @@ protected void sort()
|
||||||
|
_values.set(i + 1, v);
|
||||||
|
_quality.set(i, _quality.get(i + 1));
|
||||||
|
_quality.set(i + 1, q);
|
||||||
|
- last = ZERO;
|
||||||
|
+ last = 0.0D;
|
||||||
|
lastSecondaryOrder=0;
|
||||||
|
i = _values.size();
|
||||||
|
continue;
|
||||||
|
@@ -183,7 +186,7 @@ protected void sort()
|
||||||
|
}
|
||||||
|
|
||||||
|
int last_element=_quality.size();
|
||||||
|
- while(last_element>0 && _quality.get(--last_element).equals(ZERO))
|
||||||
|
+ while(last_element>0 && _quality.get(--last_element).equals(0.0D))
|
||||||
|
{
|
||||||
|
_quality.remove(last_element);
|
||||||
|
_values.remove(last_element);
|
||||||
|
diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/QuotedQualityCSVTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/QuotedQualityCSVTest.java
|
||||||
|
index ba0db4a8972..f03657ba3e5 100644
|
||||||
|
--- a/jetty-http/src/test/java/org/eclipse/jetty/http/QuotedQualityCSVTest.java
|
||||||
|
+++ b/jetty-http/src/test/java/org/eclipse/jetty/http/QuotedQualityCSVTest.java
|
||||||
|
@@ -61,7 +61,7 @@ public void test7231_5_3_2_example3()
|
||||||
|
@Test
|
||||||
|
public void test7231_5_3_2_example3_most_specific()
|
||||||
|
{
|
||||||
|
- QuotedQualityCSV values = new QuotedQualityCSV(QuotedQualityCSV.MOST_SPECIFIC);
|
||||||
|
+ QuotedQualityCSV values = new QuotedQualityCSV(QuotedQualityCSV.MOST_SPECIFIC_MIME_ORDERING);
|
||||||
|
values.addValue("text/*, text/plain, text/plain;format=flowed, */*");
|
||||||
|
|
||||||
|
assertThat(values,Matchers.contains("text/plain;format=flowed","text/plain","text/*","*/*"));
|
||||||
|
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java
|
||||||
|
index 84088146cd3..2820dca3a0c 100644
|
||||||
|
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java
|
||||||
|
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java
|
||||||
|
@@ -38,6 +38,7 @@
|
||||||
|
import org.eclipse.jetty.http.HttpMethod;
|
||||||
|
import org.eclipse.jetty.http.HttpStatus;
|
||||||
|
import org.eclipse.jetty.http.MimeTypes;
|
||||||
|
+import org.eclipse.jetty.http.QuotedQualityCSV;
|
||||||
|
import org.eclipse.jetty.server.Dispatcher;
|
||||||
|
import org.eclipse.jetty.server.Request;
|
||||||
|
import org.eclipse.jetty.server.Server;
|
||||||
|
@@ -159,7 +160,7 @@ else if (old_error_page!=null && old_error_page.equals(error_page))
|
||||||
|
protected void generateAcceptableResponse(Request baseRequest, HttpServletRequest request, HttpServletResponse response, int code, String message)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
- List<String> acceptable=baseRequest.getHttpFields().getQualityCSV(HttpHeader.ACCEPT);
|
||||||
|
+ List<String> acceptable=baseRequest.getHttpFields().getQualityCSV(HttpHeader.ACCEPT, QuotedQualityCSV.MOST_SPECIFIC_MIME_ORDERING);
|
||||||
|
|
||||||
|
if (acceptable.isEmpty() && !baseRequest.getHttpFields().contains(HttpHeader.ACCEPT))
|
||||||
|
{
|
||||||
|
|
||||||
|
From b925380ede948ab7d8757e95a0ce384b2441625b Mon Sep 17 00:00:00 2001
|
||||||
|
From: Greg Wilkins <gregw@webtide.com>
|
||||||
|
Date: Fri, 1 Mar 2019 10:20:10 +1100
|
||||||
|
Subject: [PATCH 3/4] Issue #3404 Updated QCSV Double usage
|
||||||
|
|
||||||
|
Signed-off-by: Greg Wilkins <gregw@webtide.com>
|
||||||
|
---
|
||||||
|
.../src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java | 2 +-
|
||||||
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java b/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java
|
||||||
|
index 498d4e01491..a7407d34199 100644
|
||||||
|
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java
|
||||||
|
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java
|
||||||
|
@@ -134,7 +134,7 @@ else if (paramValue >= 0 &&
|
||||||
|
}
|
||||||
|
buffer.setLength(Math.max(0, paramName - 1));
|
||||||
|
|
||||||
|
- if (!((Double)1.0D).equals(q))
|
||||||
|
+ if (q!=1.0D)
|
||||||
|
// replace assumed quality
|
||||||
|
_quality.set(_quality.size() - 1, q);
|
||||||
|
}
|
||||||
|
|
||||||
|
From 69f6b3b6164228485744918a28ab6a0d4c3facae Mon Sep 17 00:00:00 2001
|
||||||
|
From: Greg Wilkins <gregw@webtide.com>
|
||||||
|
Date: Tue, 5 Mar 2019 08:59:55 +1100
|
||||||
|
Subject: [PATCH 4/4] Issue #3404
|
||||||
|
|
||||||
|
updates after review:
|
||||||
|
+ use ToIntFunction
|
||||||
|
+ reformat
|
||||||
|
|
||||||
|
Signed-off-by: Greg Wilkins <gregw@webtide.com>
|
||||||
|
---
|
||||||
|
.../org/eclipse/jetty/http/HttpFields.java | 4 +-
|
||||||
|
.../eclipse/jetty/http/QuotedQualityCSV.java | 62 +++++++++++--------
|
||||||
|
2 files changed, 37 insertions(+), 29 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java
|
||||||
|
index 5a8b53013a7..395b87bde35 100644
|
||||||
|
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java
|
||||||
|
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java
|
||||||
|
@@ -31,7 +31,7 @@
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.StringTokenizer;
|
||||||
|
-import java.util.function.Function;
|
||||||
|
+import java.util.function.ToIntFunction;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import java.util.stream.StreamSupport;
|
||||||
|
|
||||||
|
@@ -450,7 +450,7 @@ protected String addCSV(QuotedCSV existing,String... values)
|
||||||
|
* @param secondaryOrdering Function to apply an ordering other than specified by quality
|
||||||
|
* @return List the values in quality order with the q param and OWS stripped
|
||||||
|
*/
|
||||||
|
- public List<String> getQualityCSV(HttpHeader header, Function<String, Integer> secondaryOrdering)
|
||||||
|
+ public List<String> getQualityCSV(HttpHeader header, ToIntFunction<String> secondaryOrdering)
|
||||||
|
{
|
||||||
|
QuotedQualityCSV values = null;
|
||||||
|
for (HttpField f : this)
|
||||||
|
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java b/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java
|
||||||
|
index a7407d34199..d148d9e65e1 100644
|
||||||
|
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java
|
||||||
|
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java
|
||||||
|
@@ -18,21 +18,23 @@
|
||||||
|
|
||||||
|
package org.eclipse.jetty.http;
|
||||||
|
|
||||||
|
-import static java.lang.Integer.MIN_VALUE;
|
||||||
|
-
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
-import java.util.function.Function;
|
||||||
|
+import java.util.function.ToIntFunction;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.util.log.Log;
|
||||||
|
|
||||||
|
+import static java.lang.Integer.MIN_VALUE;
|
||||||
|
+
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* Implements a quoted comma separated list of quality values
|
||||||
|
* in accordance with RFC7230 and RFC7231.
|
||||||
|
- * Values are returned sorted in quality order, with OWS and the
|
||||||
|
+ * Values are returned sorted in quality order, with OWS and the
|
||||||
|
* quality parameters removed.
|
||||||
|
+ *
|
||||||
|
* @see "https://tools.ietf.org/html/rfc7230#section-3.2.6"
|
||||||
|
* @see "https://tools.ietf.org/html/rfc7230#section-7"
|
||||||
|
* @see "https://tools.ietf.org/html/rfc7231#section-5.3.1"
|
||||||
|
@@ -41,44 +43,48 @@
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Lambda to apply a most specific MIME encoding secondary ordering.
|
||||||
|
+ *
|
||||||
|
* @see "https://tools.ietf.org/html/rfc7231#section-5.3.2"
|
||||||
|
*/
|
||||||
|
- public static Function<String, Integer> MOST_SPECIFIC_MIME_ORDERING = s ->
|
||||||
|
+ public static ToIntFunction<String> MOST_SPECIFIC_MIME_ORDERING = s ->
|
||||||
|
{
|
||||||
|
if ("*/*".equals(s))
|
||||||
|
return 0;
|
||||||
|
if (s.endsWith("/*"))
|
||||||
|
return 1;
|
||||||
|
- if (s.indexOf(';')<0)
|
||||||
|
+ if (s.indexOf(';') < 0)
|
||||||
|
return 2;
|
||||||
|
return 3;
|
||||||
|
};
|
||||||
|
-
|
||||||
|
+
|
||||||
|
private final List<Double> _quality = new ArrayList<>();
|
||||||
|
private boolean _sorted = false;
|
||||||
|
- private final Function<String, Integer> _secondaryOrdering;
|
||||||
|
-
|
||||||
|
+ private final ToIntFunction<String> _secondaryOrdering;
|
||||||
|
+
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* Sorts values with equal quality according to the length of the value String.
|
||||||
|
*/
|
||||||
|
public QuotedQualityCSV()
|
||||||
|
{
|
||||||
|
- this((Function)null);
|
||||||
|
+ this((ToIntFunction)null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* Sorts values with equal quality according to given order.
|
||||||
|
+ *
|
||||||
|
* @param preferredOrder Array indicating the preferred order of known values
|
||||||
|
*/
|
||||||
|
public QuotedQualityCSV(String[] preferredOrder)
|
||||||
|
{
|
||||||
|
this((s) ->
|
||||||
|
{
|
||||||
|
- for (int i=0;i<preferredOrder.length;++i)
|
||||||
|
+ for (int i = 0; i < preferredOrder.length; ++i)
|
||||||
|
if (preferredOrder[i].equals(s))
|
||||||
|
- return preferredOrder.length-i;
|
||||||
|
+ return preferredOrder.length - i;
|
||||||
|
|
||||||
|
if ("*".equals(s))
|
||||||
|
return preferredOrder.length;
|
||||||
|
@@ -88,15 +94,17 @@ public QuotedQualityCSV(String[] preferredOrder)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* Orders values with equal quality with the given function.
|
||||||
|
+ *
|
||||||
|
* @param secondaryOrdering Function to apply an ordering other than specified by quality
|
||||||
|
*/
|
||||||
|
- public QuotedQualityCSV(Function<String, Integer> secondaryOrdering)
|
||||||
|
+ public QuotedQualityCSV(ToIntFunction<String> secondaryOrdering)
|
||||||
|
{
|
||||||
|
- this._secondaryOrdering = secondaryOrdering == null ? s->0 : secondaryOrdering;
|
||||||
|
+ this._secondaryOrdering = secondaryOrdering == null ? s -> 0 : secondaryOrdering;
|
||||||
|
}
|
||||||
|
-
|
||||||
|
+
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
@Override
|
||||||
|
protected void parsedValue(StringBuffer buffer)
|
||||||
|
@@ -134,7 +142,7 @@ else if (paramValue >= 0 &&
|
||||||
|
}
|
||||||
|
buffer.setLength(Math.max(0, paramName - 1));
|
||||||
|
|
||||||
|
- if (q!=1.0D)
|
||||||
|
+ if (q != 1.0D)
|
||||||
|
// replace assumed quality
|
||||||
|
_quality.set(_quality.size() - 1, q);
|
||||||
|
}
|
||||||
|
@@ -147,7 +155,7 @@ else if (paramValue >= 0 &&
|
||||||
|
sort();
|
||||||
|
return _values;
|
||||||
|
}
|
||||||
|
-
|
||||||
|
+
|
||||||
|
@Override
|
||||||
|
public Iterator<String> iterator()
|
||||||
|
{
|
||||||
|
@@ -158,35 +166,35 @@ else if (paramValue >= 0 &&
|
||||||
|
|
||||||
|
protected void sort()
|
||||||
|
{
|
||||||
|
- _sorted=true;
|
||||||
|
+ _sorted = true;
|
||||||
|
|
||||||
|
Double last = 0.0D;
|
||||||
|
int lastSecondaryOrder = Integer.MIN_VALUE;
|
||||||
|
|
||||||
|
- for (int i = _values.size(); i-- > 0;)
|
||||||
|
+ for (int i = _values.size(); i-- > 0; )
|
||||||
|
{
|
||||||
|
String v = _values.get(i);
|
||||||
|
Double q = _quality.get(i);
|
||||||
|
|
||||||
|
- int compare=last.compareTo(q);
|
||||||
|
- if (compare>0 || (compare==0 && _secondaryOrdering.apply(v)<lastSecondaryOrder))
|
||||||
|
+ int compare = last.compareTo(q);
|
||||||
|
+ if (compare > 0 || (compare == 0 && _secondaryOrdering.applyAsInt(v) < lastSecondaryOrder))
|
||||||
|
{
|
||||||
|
_values.set(i, _values.get(i + 1));
|
||||||
|
_values.set(i + 1, v);
|
||||||
|
_quality.set(i, _quality.get(i + 1));
|
||||||
|
_quality.set(i + 1, q);
|
||||||
|
last = 0.0D;
|
||||||
|
- lastSecondaryOrder=0;
|
||||||
|
+ lastSecondaryOrder = 0;
|
||||||
|
i = _values.size();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
- last=q;
|
||||||
|
- lastSecondaryOrder=_secondaryOrdering.apply(v);
|
||||||
|
+ last = q;
|
||||||
|
+ lastSecondaryOrder = _secondaryOrdering.applyAsInt(v);
|
||||||
|
}
|
||||||
|
-
|
||||||
|
- int last_element=_quality.size();
|
||||||
|
- while(last_element>0 && _quality.get(--last_element).equals(0.0D))
|
||||||
|
+
|
||||||
|
+ int last_element = _quality.size();
|
||||||
|
+ while (last_element > 0 && _quality.get(--last_element).equals(0.0D))
|
||||||
|
{
|
||||||
|
_quality.remove(last_element);
|
||||||
|
_values.remove(last_element);
|
||||||
692
CVE-2020-27223-pre-2.patch
Normal file
692
CVE-2020-27223-pre-2.patch
Normal file
@ -0,0 +1,692 @@
|
|||||||
|
From 05072b34dce43064e87ad0d59065f14666c1f34e Mon Sep 17 00:00:00 2001
|
||||||
|
From: Greg Wilkins <gregw@webtide.com>
|
||||||
|
Date: Wed, 8 May 2019 13:28:16 +0200
|
||||||
|
Subject: [PATCH] Issue #3630 Forwarded-Port
|
||||||
|
|
||||||
|
Added support for the X-Forwarded-Port header.
|
||||||
|
Reimplemented header scanning using more efficient Trie and MethodHandles
|
||||||
|
|
||||||
|
Signed-off-by: Greg Wilkins <gregw@webtide.com>
|
||||||
|
---
|
||||||
|
.../eclipse/jetty/http/HostPortHttpField.java | 13 +
|
||||||
|
.../org/eclipse/jetty/http/HttpHeader.java | 1 +
|
||||||
|
.../main/config/etc/jetty-http-forwarded.xml | 1 +
|
||||||
|
.../main/config/modules/http-forwarded.mod | 1 +
|
||||||
|
.../server/ForwardedRequestCustomizer.java | 274 +++++++++++++-----
|
||||||
|
.../ForwardedRequestCustomizerTest.java | 27 +-
|
||||||
|
.../java/org/eclipse/jetty/util/HostPort.java | 30 +-
|
||||||
|
.../org/eclipse/jetty/util/HostPortTest.java | 13 +-
|
||||||
|
8 files changed, 269 insertions(+), 91 deletions(-)
|
||||||
|
|
||||||
|
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 215c353b4b9..dc386665339 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
|
||||||
|
@@ -49,6 +49,19 @@ protected HostPortHttpField(HttpHeader header, String name, String authority)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ /* ------------------------------------------------------------ */
|
||||||
|
+ public HostPortHttpField(String host, int port)
|
||||||
|
+ {
|
||||||
|
+ this(new HostPort(host, port));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* ------------------------------------------------------------ */
|
||||||
|
+ protected HostPortHttpField(HostPort hostport)
|
||||||
|
+ {
|
||||||
|
+ super(HttpHeader.HOST,HttpHeader.HOST.asString(),hostport.toString());
|
||||||
|
+ _hostPort = hostport;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/** Get the host.
|
||||||
|
* @return the host
|
||||||
|
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeader.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeader.java
|
||||||
|
index f39c0f7df98..ac6bf2be8da 100644
|
||||||
|
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeader.java
|
||||||
|
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeader.java
|
||||||
|
@@ -82,6 +82,7 @@
|
||||||
|
TE("TE"),
|
||||||
|
USER_AGENT("User-Agent"),
|
||||||
|
X_FORWARDED_FOR("X-Forwarded-For"),
|
||||||
|
+ X_FORWARDED_PORT("X-Forwarded-Port"),
|
||||||
|
X_FORWARDED_PROTO("X-Forwarded-Proto"),
|
||||||
|
X_FORWARDED_SERVER("X-Forwarded-Server"),
|
||||||
|
X_FORWARDED_HOST("X-Forwarded-Host"),
|
||||||
|
diff --git a/jetty-server/src/main/config/etc/jetty-http-forwarded.xml b/jetty-server/src/main/config/etc/jetty-http-forwarded.xml
|
||||||
|
index 50b80976a2a..648d6c6a94f 100644
|
||||||
|
--- a/jetty-server/src/main/config/etc/jetty-http-forwarded.xml
|
||||||
|
+++ b/jetty-server/src/main/config/etc/jetty-http-forwarded.xml
|
||||||
|
@@ -11,6 +11,7 @@
|
||||||
|
<Set name="forwardedServerHeader"><Property name="jetty.httpConfig.forwardedServerHeader" default="X-Forwarded-Server"/></Set>
|
||||||
|
<Set name="forwardedProtoHeader"><Property name="jetty.httpConfig.forwardedProtoHeader" default="X-Forwarded-Proto"/></Set>
|
||||||
|
<Set name="forwardedForHeader"><Property name="jetty.httpConfig.forwardedForHeader" default="X-Forwarded-For"/></Set>
|
||||||
|
+ <Set name="forwardedPortHeader"><Property name="jetty.httpConfig.forwardedPortHeader" default="X-Forwarded-Port"/></Set>
|
||||||
|
<Set name="forwardedHttpsHeader"><Property name="jetty.httpConfig.forwardedHttpsHeader" default="X-Proxied-Https"/></Set>
|
||||||
|
<Set name="forwardedSslSessionIdHeader"><Property name="jetty.httpConfig.forwardedSslSessionIdHeader" default="Proxy-ssl-id" /></Set>
|
||||||
|
<Set name="forwardedCipherSuiteHeader"><Property name="jetty.httpConfig.forwardedCipherSuiteHeader" default="Proxy-auth-cert"/></Set>
|
||||||
|
diff --git a/jetty-server/src/main/config/modules/http-forwarded.mod b/jetty-server/src/main/config/modules/http-forwarded.mod
|
||||||
|
index 34e25642b2c..f67822065a4 100644
|
||||||
|
--- a/jetty-server/src/main/config/modules/http-forwarded.mod
|
||||||
|
+++ b/jetty-server/src/main/config/modules/http-forwarded.mod
|
||||||
|
@@ -23,6 +23,7 @@ etc/jetty-http-forwarded.xml
|
||||||
|
# jetty.httpConfig.forwardedServerHeader=X-Forwarded-Server
|
||||||
|
# jetty.httpConfig.forwardedProtoHeader=X-Forwarded-Proto
|
||||||
|
# jetty.httpConfig.forwardedForHeader=X-Forwarded-For
|
||||||
|
+# jetty.httpConfig.forwardedPortHeader=X-Forwarded-Port
|
||||||
|
# jetty.httpConfig.forwardedHttpsHeader=X-Proxied-Https
|
||||||
|
# jetty.httpConfig.forwardedSslSessionIdHeader=Proxy-ssl-id
|
||||||
|
# jetty.httpConfig.forwardedCipherSuiteHeader=Proxy-auth-cert
|
||||||
|
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 f2ffe24fb85..1e64892cbe9 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
|
||||||
|
@@ -18,6 +18,9 @@
|
||||||
|
|
||||||
|
package org.eclipse.jetty.server;
|
||||||
|
|
||||||
|
+import java.lang.invoke.MethodHandle;
|
||||||
|
+import java.lang.invoke.MethodHandles;
|
||||||
|
+import java.lang.invoke.MethodType;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
@@ -29,11 +32,15 @@
|
||||||
|
import org.eclipse.jetty.http.HttpScheme;
|
||||||
|
import org.eclipse.jetty.http.QuotedCSV;
|
||||||
|
import org.eclipse.jetty.server.HttpConfiguration.Customizer;
|
||||||
|
+import org.eclipse.jetty.util.ArrayTrie;
|
||||||
|
import org.eclipse.jetty.util.HostPort;
|
||||||
|
import org.eclipse.jetty.util.StringUtil;
|
||||||
|
+import org.eclipse.jetty.util.Trie;
|
||||||
|
import org.eclipse.jetty.util.log.Log;
|
||||||
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
|
|
||||||
|
+import static java.lang.invoke.MethodType.methodType;
|
||||||
|
+
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/** Customize Requests for Proxy Forwarding.
|
||||||
|
@@ -63,14 +70,21 @@
|
||||||
|
private String _forwardedHeader = HttpHeader.FORWARDED.toString();
|
||||||
|
private String _forwardedHostHeader = HttpHeader.X_FORWARDED_HOST.toString();
|
||||||
|
private String _forwardedServerHeader = HttpHeader.X_FORWARDED_SERVER.toString();
|
||||||
|
- private String _forwardedForHeader = HttpHeader.X_FORWARDED_FOR.toString();
|
||||||
|
private String _forwardedProtoHeader = HttpHeader.X_FORWARDED_PROTO.toString();
|
||||||
|
+ private String _forwardedForHeader = HttpHeader.X_FORWARDED_FOR.toString();
|
||||||
|
+ private String _forwardedPortHeader = HttpHeader.X_FORWARDED_PORT.toString();
|
||||||
|
private String _forwardedHttpsHeader = "X-Proxied-Https";
|
||||||
|
private String _forwardedCipherSuiteHeader = "Proxy-auth-cert";
|
||||||
|
private String _forwardedSslSessionIdHeader = "Proxy-ssl-id";
|
||||||
|
private boolean _proxyAsAuthority=false;
|
||||||
|
private boolean _sslIsSecure=true;
|
||||||
|
-
|
||||||
|
+ private Trie <MethodHandle> _handles;
|
||||||
|
+
|
||||||
|
+ public ForwardedRequestCustomizer()
|
||||||
|
+ {
|
||||||
|
+ updateHandles();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* @return true if the proxy address obtained via
|
||||||
|
* {@code X-Forwarded-Server} or RFC7239 "by" is used as
|
||||||
|
@@ -103,9 +117,9 @@ public void setForwardedOnly(boolean rfc7239only)
|
||||||
|
if (_forwardedHeader==null)
|
||||||
|
_forwardedHeader=HttpHeader.FORWARDED.toString();
|
||||||
|
_forwardedHostHeader=null;
|
||||||
|
- _forwardedHostHeader=null;
|
||||||
|
_forwardedServerHeader=null;
|
||||||
|
_forwardedForHeader=null;
|
||||||
|
+ _forwardedPortHeader=null;
|
||||||
|
_forwardedProtoHeader=null;
|
||||||
|
_forwardedHttpsHeader=null;
|
||||||
|
}
|
||||||
|
@@ -117,11 +131,15 @@ public void setForwardedOnly(boolean rfc7239only)
|
||||||
|
_forwardedServerHeader = HttpHeader.X_FORWARDED_SERVER.toString();
|
||||||
|
if (_forwardedForHeader==null)
|
||||||
|
_forwardedForHeader = HttpHeader.X_FORWARDED_FOR.toString();
|
||||||
|
+ if (_forwardedPortHeader==null)
|
||||||
|
+ _forwardedPortHeader = HttpHeader.X_FORWARDED_PORT.toString();
|
||||||
|
if (_forwardedProtoHeader==null)
|
||||||
|
_forwardedProtoHeader = HttpHeader.X_FORWARDED_PROTO.toString();
|
||||||
|
if (_forwardedHttpsHeader==null)
|
||||||
|
_forwardedHttpsHeader = "X-Proxied-Https";
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ updateHandles();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getForcedHost()
|
||||||
|
@@ -138,6 +156,7 @@ public String getForcedHost()
|
||||||
|
public void setForcedHost(String hostAndPort)
|
||||||
|
{
|
||||||
|
_forcedHost = new HostPortHttpField(hostAndPort);
|
||||||
|
+ updateHandles();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@@ -155,6 +174,7 @@ public String getForwardedHeader()
|
||||||
|
public void setForwardedHeader(String forwardedHeader)
|
||||||
|
{
|
||||||
|
_forwardedHeader = forwardedHeader;
|
||||||
|
+ updateHandles();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getForwardedHostHeader()
|
||||||
|
@@ -169,6 +189,7 @@ public String getForwardedHostHeader()
|
||||||
|
public void setForwardedHostHeader(String forwardedHostHeader)
|
||||||
|
{
|
||||||
|
_forwardedHostHeader = forwardedHostHeader;
|
||||||
|
+ updateHandles();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@@ -186,6 +207,7 @@ public String getForwardedServerHeader()
|
||||||
|
public void setForwardedServerHeader(String forwardedServerHeader)
|
||||||
|
{
|
||||||
|
_forwardedServerHeader = forwardedServerHeader;
|
||||||
|
+ updateHandles();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@@ -203,6 +225,22 @@ public String getForwardedForHeader()
|
||||||
|
public void setForwardedForHeader(String forwardedRemoteAddressHeader)
|
||||||
|
{
|
||||||
|
_forwardedForHeader = forwardedRemoteAddressHeader;
|
||||||
|
+ updateHandles();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public String getForwardedPortHeader()
|
||||||
|
+ {
|
||||||
|
+ return _forwardedHostHeader;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * @param forwardedPortHeader
|
||||||
|
+ * The header name for forwarded hosts (default {@code X-Forwarded-Port})
|
||||||
|
+ */
|
||||||
|
+ public void setForwardedPortHeader(String forwardedPortHeader)
|
||||||
|
+ {
|
||||||
|
+ _forwardedHostHeader = forwardedPortHeader;
|
||||||
|
+ updateHandles();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@@ -224,6 +262,7 @@ public String getForwardedProtoHeader()
|
||||||
|
public void setForwardedProtoHeader(String forwardedProtoHeader)
|
||||||
|
{
|
||||||
|
_forwardedProtoHeader = forwardedProtoHeader;
|
||||||
|
+ updateHandles();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@@ -241,6 +280,7 @@ public String getForwardedCipherSuiteHeader()
|
||||||
|
public void setForwardedCipherSuiteHeader(String forwardedCipherSuite)
|
||||||
|
{
|
||||||
|
_forwardedCipherSuiteHeader = forwardedCipherSuite;
|
||||||
|
+ updateHandles();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@@ -258,6 +298,7 @@ public String getForwardedSslSessionIdHeader()
|
||||||
|
public void setForwardedSslSessionIdHeader(String forwardedSslSessionId)
|
||||||
|
{
|
||||||
|
_forwardedSslSessionIdHeader = forwardedSslSessionId;
|
||||||
|
+ updateHandles();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@@ -274,6 +315,7 @@ public String getForwardedHttpsHeader()
|
||||||
|
public void setForwardedHttpsHeader(String forwardedHttpsHeader)
|
||||||
|
{
|
||||||
|
_forwardedHttpsHeader = forwardedHttpsHeader;
|
||||||
|
+ updateHandles();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@@ -299,118 +341,84 @@ public void customize(Connector connector, HttpConfiguration config, Request req
|
||||||
|
{
|
||||||
|
HttpFields httpFields = request.getHttpFields();
|
||||||
|
|
||||||
|
- RFC7239 rfc7239 = null;
|
||||||
|
- String forwardedHost = null;
|
||||||
|
- String forwardedServer = null;
|
||||||
|
- HostPort forwardedFor = null;
|
||||||
|
- String forwardedProto = null;
|
||||||
|
- String forwardedHttps = null;
|
||||||
|
-
|
||||||
|
// Do a single pass through the header fields as it is a more efficient single iteration.
|
||||||
|
- for (HttpField field : httpFields)
|
||||||
|
+ Forwarded forwarded = new Forwarded(request, config);
|
||||||
|
+ try
|
||||||
|
{
|
||||||
|
- String name = field.getName();
|
||||||
|
-
|
||||||
|
- if (getForwardedCipherSuiteHeader()!=null && getForwardedCipherSuiteHeader().equalsIgnoreCase(name))
|
||||||
|
+ for (HttpField field : httpFields)
|
||||||
|
{
|
||||||
|
- request.setAttribute("javax.servlet.request.cipher_suite",field.getValue());
|
||||||
|
- if (isSslIsSecure())
|
||||||
|
- {
|
||||||
|
- request.setSecure(true);
|
||||||
|
- request.setScheme(config.getSecureScheme());
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- if (getForwardedSslSessionIdHeader()!=null && getForwardedSslSessionIdHeader().equalsIgnoreCase(name))
|
||||||
|
- {
|
||||||
|
- request.setAttribute("javax.servlet.request.ssl_session_id", field.getValue());
|
||||||
|
- if (isSslIsSecure())
|
||||||
|
- {
|
||||||
|
- request.setSecure(true);
|
||||||
|
- request.setScheme(config.getSecureScheme());
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- if (forwardedHost==null && _forwardedHostHeader!=null && _forwardedHostHeader.equalsIgnoreCase(name))
|
||||||
|
- forwardedHost = getLeftMost(field.getValue());
|
||||||
|
-
|
||||||
|
- if (forwardedServer==null && _forwardedServerHeader!=null && _forwardedServerHeader.equalsIgnoreCase(name))
|
||||||
|
- forwardedServer = getLeftMost(field.getValue());
|
||||||
|
-
|
||||||
|
- if (forwardedFor==null && _forwardedForHeader!=null && _forwardedForHeader.equalsIgnoreCase(name))
|
||||||
|
- forwardedFor = getRemoteAddr(field.getValue());
|
||||||
|
-
|
||||||
|
- if (forwardedProto==null && _forwardedProtoHeader!=null && _forwardedProtoHeader.equalsIgnoreCase(name))
|
||||||
|
- forwardedProto = getLeftMost(field.getValue());
|
||||||
|
-
|
||||||
|
- if (forwardedHttps==null && _forwardedHttpsHeader!=null && _forwardedHttpsHeader.equalsIgnoreCase(name))
|
||||||
|
- forwardedHttps = getLeftMost(field.getValue());
|
||||||
|
-
|
||||||
|
- if (_forwardedHeader!=null && _forwardedHeader.equalsIgnoreCase(name))
|
||||||
|
- {
|
||||||
|
- if (rfc7239==null)
|
||||||
|
- rfc7239= new RFC7239();
|
||||||
|
- rfc7239.addValue(field.getValue());
|
||||||
|
+ MethodHandle handle = _handles.get(field.getName());
|
||||||
|
+ if (handle != null)
|
||||||
|
+ handle.invoke(forwarded, field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
-
|
||||||
|
- // Handle host header if if not available any RFC7230.by or X-ForwardedServer header
|
||||||
|
+ catch (Throwable e)
|
||||||
|
+ {
|
||||||
|
+ throw new RuntimeException(e);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // Determine host
|
||||||
|
if (_forcedHost != null)
|
||||||
|
{
|
||||||
|
// Update host header
|
||||||
|
httpFields.put(_forcedHost);
|
||||||
|
request.setAuthority(_forcedHost.getHost(),_forcedHost.getPort());
|
||||||
|
}
|
||||||
|
- else if (rfc7239!=null && rfc7239._host!=null)
|
||||||
|
+ else if (forwarded._rfc7239!=null && forwarded._rfc7239._host!=null)
|
||||||
|
{
|
||||||
|
- HostPortHttpField auth = rfc7239._host;
|
||||||
|
+ HostPortHttpField auth = forwarded._rfc7239._host;
|
||||||
|
httpFields.put(auth);
|
||||||
|
request.setAuthority(auth.getHost(),auth.getPort());
|
||||||
|
}
|
||||||
|
- else if (forwardedHost != null)
|
||||||
|
+ else if (forwarded._forwardedHost != null)
|
||||||
|
{
|
||||||
|
- HostPortHttpField auth = new HostPortHttpField(forwardedHost);
|
||||||
|
+ HostPortHttpField auth = new HostPortHttpField(forwarded._forwardedHost);
|
||||||
|
httpFields.put(auth);
|
||||||
|
- request.setAuthority(auth.getHost(),auth.getPort());
|
||||||
|
+ request.setAuthority(auth.getHost(), auth.getPort());
|
||||||
|
}
|
||||||
|
else if (_proxyAsAuthority)
|
||||||
|
{
|
||||||
|
- if (rfc7239!=null && rfc7239._by!=null)
|
||||||
|
+ if (forwarded._rfc7239!=null && forwarded._rfc7239._by!=null)
|
||||||
|
{
|
||||||
|
- HostPortHttpField auth = rfc7239._by;
|
||||||
|
+ HostPortHttpField auth = forwarded._rfc7239._by;
|
||||||
|
httpFields.put(auth);
|
||||||
|
request.setAuthority(auth.getHost(),auth.getPort());
|
||||||
|
}
|
||||||
|
- else if (forwardedServer != null)
|
||||||
|
+ else if (forwarded._forwardedServer != null)
|
||||||
|
{
|
||||||
|
- request.setAuthority(forwardedServer,request.getServerPort());
|
||||||
|
+ request.setAuthority(forwarded._forwardedServer,request.getServerPort());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle remote end identifier
|
||||||
|
- if (rfc7239!=null && rfc7239._for!=null)
|
||||||
|
+ if (forwarded._rfc7239!=null && forwarded._rfc7239._for!=null)
|
||||||
|
{
|
||||||
|
- request.setRemoteAddr(InetSocketAddress.createUnresolved(rfc7239._for.getHost(),rfc7239._for.getPort()));
|
||||||
|
+ request.setRemoteAddr(InetSocketAddress.createUnresolved(forwarded._rfc7239._for.getHost(),forwarded._rfc7239._for.getPort()));
|
||||||
|
}
|
||||||
|
- else if (forwardedFor != null)
|
||||||
|
+ else if (forwarded._forwardedFor != null)
|
||||||
|
{
|
||||||
|
- request.setRemoteAddr(InetSocketAddress.createUnresolved(forwardedFor.getHost(), (forwardedFor.getPort() > 0) ? forwardedFor.getPort() : request.getRemotePort()));
|
||||||
|
+ int port = (forwarded._forwardedPort>0)
|
||||||
|
+ ? forwarded._forwardedPort
|
||||||
|
+ : (forwarded._forwardedFor.getPort() > 0)
|
||||||
|
+ ? forwarded._forwardedFor.getPort()
|
||||||
|
+ : request.getRemotePort();
|
||||||
|
+ request.setRemoteAddr(InetSocketAddress.createUnresolved(forwarded._forwardedFor.getHost(), port));
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle protocol identifier
|
||||||
|
- if (rfc7239!=null && rfc7239._proto!=null)
|
||||||
|
+ if (forwarded._rfc7239!=null && forwarded._rfc7239._proto!=null)
|
||||||
|
{
|
||||||
|
- request.setScheme(rfc7239._proto);
|
||||||
|
- if (rfc7239._proto.equals(config.getSecureScheme()))
|
||||||
|
+ request.setScheme(forwarded._rfc7239._proto);
|
||||||
|
+ if (forwarded._rfc7239._proto.equals(config.getSecureScheme()))
|
||||||
|
request.setSecure(true);
|
||||||
|
}
|
||||||
|
- else if (forwardedProto != null)
|
||||||
|
+ else if (forwarded._forwardedProto != null)
|
||||||
|
{
|
||||||
|
- request.setScheme(forwardedProto);
|
||||||
|
- if (forwardedProto.equals(config.getSecureScheme()))
|
||||||
|
+ request.setScheme(forwarded._forwardedProto);
|
||||||
|
+ if (forwarded._forwardedProto.equals(config.getSecureScheme()))
|
||||||
|
request.setSecure(true);
|
||||||
|
}
|
||||||
|
- else if (forwardedHttps !=null && ("on".equalsIgnoreCase(forwardedHttps)||"true".equalsIgnoreCase(forwardedHttps)))
|
||||||
|
+ 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()))
|
||||||
|
@@ -521,4 +529,122 @@ protected void parsedParam(StringBuffer buffer, int valueLength, int paramName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ private void updateHandles()
|
||||||
|
+ {
|
||||||
|
+ int size = 0;
|
||||||
|
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||||
|
+ MethodType type = methodType(Void.TYPE, HttpField.class);
|
||||||
|
+
|
||||||
|
+ while(true)
|
||||||
|
+ {
|
||||||
|
+ try
|
||||||
|
+ {
|
||||||
|
+ size += 128;
|
||||||
|
+ _handles = new ArrayTrie<>(size);
|
||||||
|
+
|
||||||
|
+ if (_forwardedCipherSuiteHeader != null && !_handles.put(_forwardedCipherSuiteHeader, lookup.findVirtual(Forwarded.class, "handleCipherSuite", type)))
|
||||||
|
+ continue;
|
||||||
|
+ if (_forwardedSslSessionIdHeader != null && !_handles.put(_forwardedSslSessionIdHeader, lookup.findVirtual(Forwarded.class, "handleSslSessionId", type)))
|
||||||
|
+ continue;
|
||||||
|
+ if (_forwardedHeader != null && !_handles.put(_forwardedHeader, lookup.findVirtual(Forwarded.class, "handleRFC7239", type)))
|
||||||
|
+ continue;
|
||||||
|
+ if (_forwardedForHeader != null && !_handles.put(_forwardedForHeader, lookup.findVirtual(Forwarded.class, "handleFor", type)))
|
||||||
|
+ continue;
|
||||||
|
+ if (_forwardedPortHeader != null && !_handles.put(_forwardedPortHeader, lookup.findVirtual(Forwarded.class, "handlePort", type)))
|
||||||
|
+ continue;
|
||||||
|
+ if (_forwardedHostHeader != null && !_handles.put(_forwardedHostHeader, lookup.findVirtual(Forwarded.class, "handleHost", type)))
|
||||||
|
+ continue;
|
||||||
|
+ if (_forwardedProtoHeader != null && !_handles.put(_forwardedProtoHeader, lookup.findVirtual(Forwarded.class, "handleProto", type)))
|
||||||
|
+ continue;
|
||||||
|
+ if (_forwardedHttpsHeader != null && !_handles.put(_forwardedHttpsHeader, lookup.findVirtual(Forwarded.class, "handleHttps", type)))
|
||||||
|
+ continue;
|
||||||
|
+ if (_forwardedServerHeader != null && !_handles.put(_forwardedServerHeader, lookup.findVirtual(Forwarded.class, "handleServer", type)))
|
||||||
|
+ continue;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ catch (NoSuchMethodException|IllegalAccessException e)
|
||||||
|
+ {
|
||||||
|
+ throw new IllegalStateException(e);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private class Forwarded
|
||||||
|
+ {
|
||||||
|
+ 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;
|
||||||
|
+
|
||||||
|
+ public Forwarded(Request request, HttpConfiguration config)
|
||||||
|
+ {
|
||||||
|
+ _request = request;
|
||||||
|
+ _config = config;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void handleCipherSuite(HttpField field)
|
||||||
|
+ {
|
||||||
|
+ _request.setAttribute("javax.servlet.request.cipher_suite",field.getValue());
|
||||||
|
+ if (isSslIsSecure())
|
||||||
|
+ {
|
||||||
|
+ _request.setSecure(true);
|
||||||
|
+ _request.setScheme(_config.getSecureScheme());
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void handleSslSessionId(HttpField field)
|
||||||
|
+ {
|
||||||
|
+ _request.setAttribute("javax.servlet.request.ssl_session_id", field.getValue());
|
||||||
|
+ if (isSslIsSecure())
|
||||||
|
+ {
|
||||||
|
+ _request.setSecure(true);
|
||||||
|
+ _request.setScheme(_config.getSecureScheme());
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void handleHost(HttpField field)
|
||||||
|
+ {
|
||||||
|
+ _forwardedHost = getLeftMost(field.getValue());
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void handleServer(HttpField field)
|
||||||
|
+ {
|
||||||
|
+ _forwardedServer = getLeftMost(field.getValue());
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void handleProto(HttpField field)
|
||||||
|
+ {
|
||||||
|
+ _forwardedProto = getLeftMost(field.getValue());
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void handleFor(HttpField field)
|
||||||
|
+ {
|
||||||
|
+ _forwardedFor = getRemoteAddr(field.getValue());
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void handlePort(HttpField field)
|
||||||
|
+ {
|
||||||
|
+ _forwardedPort = field.getIntValue();
|
||||||
|
+ }
|
||||||
|
+ public void handleHttps(HttpField field)
|
||||||
|
+ {
|
||||||
|
+ _forwardedHttps = getLeftMost(field.getValue());
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void handleRFC7239(HttpField field)
|
||||||
|
+ {
|
||||||
|
+ if (_rfc7239 ==null)
|
||||||
|
+ _rfc7239 = new RFC7239();
|
||||||
|
+ _rfc7239.addValue(field.getValue());
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
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 5d5467f73bd..0a1cecec0c2 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
|
||||||
|
@@ -18,11 +18,6 @@
|
||||||
|
|
||||||
|
package org.eclipse.jetty.server;
|
||||||
|
|
||||||
|
-import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
-import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
-import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
-import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
-
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.Deque;
|
||||||
|
@@ -41,6 +36,11 @@
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
+import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
+import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
+import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
+import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
+
|
||||||
|
public class ForwardedRequestCustomizerTest
|
||||||
|
{
|
||||||
|
private Server _server;
|
||||||
|
@@ -249,6 +249,23 @@ public void testForIpv6WithPort() throws Exception
|
||||||
|
assertEquals("1111",_results.poll());
|
||||||
|
}
|
||||||
|
|
||||||
|
+ @Test
|
||||||
|
+ public void testForIpv6AndPort() throws Exception
|
||||||
|
+ {
|
||||||
|
+ String response=_connector.getResponse(
|
||||||
|
+ "GET / HTTP/1.1\n"+
|
||||||
|
+ "Host: myhost\n"+
|
||||||
|
+ "X-Forwarded-For: 1:2:3:4:5:6:7:8\n"+
|
||||||
|
+ "X-Forwarded-Port: 2222\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
|
||||||
|
public void testLegacyProto() throws Exception
|
||||||
|
{
|
||||||
|
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/HostPort.java b/jetty-util/src/main/java/org/eclipse/jetty/util/HostPort.java
|
||||||
|
index 1824dd799d1..8fde487ae19 100644
|
||||||
|
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/HostPort.java
|
||||||
|
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/HostPort.java
|
||||||
|
@@ -32,6 +32,12 @@
|
||||||
|
private final String _host;
|
||||||
|
private final int _port;
|
||||||
|
|
||||||
|
+ public HostPort(String host, int port) throws IllegalArgumentException
|
||||||
|
+ {
|
||||||
|
+ _host = host;
|
||||||
|
+ _port = port;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
public HostPort(String authority) throws IllegalArgumentException
|
||||||
|
{
|
||||||
|
if (authority==null)
|
||||||
|
@@ -66,8 +72,16 @@ else if (authority.charAt(0)=='[')
|
||||||
|
int c = authority.lastIndexOf(':');
|
||||||
|
if (c>=0)
|
||||||
|
{
|
||||||
|
- _host=authority.substring(0,c);
|
||||||
|
- _port=StringUtil.toInt(authority,c+1);
|
||||||
|
+ if (c!=authority.indexOf(':'))
|
||||||
|
+ {
|
||||||
|
+ _host="[" + authority + "]";
|
||||||
|
+ _port=0;
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ {
|
||||||
|
+ _host = authority.substring(0, c);
|
||||||
|
+ _port = StringUtil.toInt(authority, c + 1);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@@ -93,7 +107,6 @@ else if (authority.charAt(0)=='[')
|
||||||
|
throw new IllegalArgumentException("Bad port");
|
||||||
|
}
|
||||||
|
|
||||||
|
- /* ------------------------------------------------------------ */
|
||||||
|
/** Get the host.
|
||||||
|
* @return the host
|
||||||
|
*/
|
||||||
|
@@ -102,7 +115,6 @@ public String getHost()
|
||||||
|
return _host;
|
||||||
|
}
|
||||||
|
|
||||||
|
- /* ------------------------------------------------------------ */
|
||||||
|
/** Get the port.
|
||||||
|
* @return the port
|
||||||
|
*/
|
||||||
|
@@ -111,7 +123,6 @@ public int getPort()
|
||||||
|
return _port;
|
||||||
|
}
|
||||||
|
|
||||||
|
- /* ------------------------------------------------------------ */
|
||||||
|
/** Get the port.
|
||||||
|
* @param defaultPort, the default port to return if a port is not specified
|
||||||
|
* @return the port
|
||||||
|
@@ -121,7 +132,14 @@ public int getPort(int defaultPort)
|
||||||
|
return _port>0?_port:defaultPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
- /* ------------------------------------------------------------ */
|
||||||
|
+ @Override
|
||||||
|
+ public String toString()
|
||||||
|
+ {
|
||||||
|
+ if (_port>0)
|
||||||
|
+ return normalizeHost(_host) + ":" + _port;
|
||||||
|
+ return _host;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
/** Normalize IPv6 address as per https://www.ietf.org/rfc/rfc2732.txt
|
||||||
|
* @param host A host name
|
||||||
|
* @return Host name surrounded by '[' and ']' as needed.
|
||||||
|
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/HostPortTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/HostPortTest.java
|
||||||
|
index 705bbbf6fa6..a700262cb90 100644
|
||||||
|
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/HostPortTest.java
|
||||||
|
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/HostPortTest.java
|
||||||
|
@@ -18,17 +18,17 @@
|
||||||
|
|
||||||
|
package org.eclipse.jetty.util;
|
||||||
|
|
||||||
|
-import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
-import static org.hamcrest.Matchers.is;
|
||||||
|
-import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
-import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
-
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
|
|
||||||
|
+import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
+import static org.hamcrest.Matchers.is;
|
||||||
|
+import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
+import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
+
|
||||||
|
public class HostPortTest
|
||||||
|
{
|
||||||
|
private static Stream<Arguments> validAuthorityProvider()
|
||||||
|
@@ -41,7 +41,8 @@
|
||||||
|
Arguments.of("10.10.10.1", "10.10.10.1", null),
|
||||||
|
Arguments.of("10.10.10.1:80", "10.10.10.1", "80"),
|
||||||
|
Arguments.of("[0::0::0::1]", "[0::0::0::1]", null),
|
||||||
|
- Arguments.of("[0::0::0::1]:80", "[0::0::0::1]", "80")
|
||||||
|
+ Arguments.of("[0::0::0::1]:80", "[0::0::0::1]", "80"),
|
||||||
|
+ Arguments.of("0:1:2:3:4:5:6","[0:1:2:3:4:5:6]",null)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
518
CVE-2020-27223-pre-3.patch
Normal file
518
CVE-2020-27223-pre-3.patch
Normal file
@ -0,0 +1,518 @@
|
|||||||
|
From 9f3b0223ab7e3159c4794e102f6b5e06dfc8710d Mon Sep 17 00:00:00 2001
|
||||||
|
From: Greg Wilkins <gregw@webtide.com>
|
||||||
|
Date: Wed, 8 May 2019 14:00:58 +0200
|
||||||
|
Subject: [PATCH] Issue #3630 Forwarded-Port
|
||||||
|
|
||||||
|
reformatted code
|
||||||
|
Avoid updating handles unless configuration is changed.
|
||||||
|
|
||||||
|
Signed-off-by: Greg Wilkins <gregw@webtide.com>
|
||||||
|
---
|
||||||
|
.../server/ForwardedRequestCustomizer.java | 216 ++++++++++--------
|
||||||
|
1 file changed, 117 insertions(+), 99 deletions(-)
|
||||||
|
|
||||||
|
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 1e64892cbe9..be3990794ed 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
|
||||||
|
@@ -43,7 +43,9 @@
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
-/** Customize Requests for Proxy Forwarding.
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * Customize Requests for Proxy Forwarding.
|
||||||
|
* <p>
|
||||||
|
* This customizer looks at at HTTP request for headers that indicate
|
||||||
|
* it has been forwarded by one or more proxies. Specifically handled are
|
||||||
|
@@ -59,7 +61,8 @@
|
||||||
|
* so that the proxy is not seen as the other end point of the connection on which
|
||||||
|
* the request came</p>
|
||||||
|
* <p>Headers can also be defined so that forwarded SSL Session IDs and Cipher
|
||||||
|
- * suites may be customised</p>
|
||||||
|
+ * suites may be customised</p>
|
||||||
|
+ *
|
||||||
|
* @see <a href="http://en.wikipedia.org/wiki/X-Forwarded-For">Wikipedia: X-Forwarded-For</a>
|
||||||
|
*/
|
||||||
|
public class ForwardedRequestCustomizer implements Customizer
|
||||||
|
@@ -76,9 +79,9 @@
|
||||||
|
private String _forwardedHttpsHeader = "X-Proxied-Https";
|
||||||
|
private String _forwardedCipherSuiteHeader = "Proxy-auth-cert";
|
||||||
|
private String _forwardedSslSessionIdHeader = "Proxy-ssl-id";
|
||||||
|
- private boolean _proxyAsAuthority=false;
|
||||||
|
- private boolean _sslIsSecure=true;
|
||||||
|
- private Trie <MethodHandle> _handles;
|
||||||
|
+ private boolean _proxyAsAuthority = false;
|
||||||
|
+ private boolean _sslIsSecure = true;
|
||||||
|
+ private Trie<MethodHandle> _handles;
|
||||||
|
|
||||||
|
public ForwardedRequestCustomizer()
|
||||||
|
{
|
||||||
|
@@ -97,7 +100,7 @@ public boolean getProxyAsAuthority()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param proxyAsAuthority if true, use the proxy address obtained via
|
||||||
|
- * {@code X-Forwarded-Server} or RFC7239 "by" as the request authority.
|
||||||
|
+ * {@code X-Forwarded-Server} or RFC7239 "by" as the request authority.
|
||||||
|
*/
|
||||||
|
public void setProxyAsAuthority(boolean proxyAsAuthority)
|
||||||
|
{
|
||||||
|
@@ -114,49 +117,47 @@ public void setForwardedOnly(boolean rfc7239only)
|
||||||
|
{
|
||||||
|
if (rfc7239only)
|
||||||
|
{
|
||||||
|
- if (_forwardedHeader==null)
|
||||||
|
- _forwardedHeader=HttpHeader.FORWARDED.toString();
|
||||||
|
- _forwardedHostHeader=null;
|
||||||
|
- _forwardedServerHeader=null;
|
||||||
|
- _forwardedForHeader=null;
|
||||||
|
- _forwardedPortHeader=null;
|
||||||
|
- _forwardedProtoHeader=null;
|
||||||
|
- _forwardedHttpsHeader=null;
|
||||||
|
+ if (_forwardedHeader == null)
|
||||||
|
+ _forwardedHeader = HttpHeader.FORWARDED.toString();
|
||||||
|
+ _forwardedHostHeader = null;
|
||||||
|
+ _forwardedServerHeader = null;
|
||||||
|
+ _forwardedForHeader = null;
|
||||||
|
+ _forwardedPortHeader = null;
|
||||||
|
+ _forwardedProtoHeader = null;
|
||||||
|
+ _forwardedHttpsHeader = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
- if (_forwardedHostHeader==null)
|
||||||
|
+ if (_forwardedHostHeader == null)
|
||||||
|
_forwardedHostHeader = HttpHeader.X_FORWARDED_HOST.toString();
|
||||||
|
- if (_forwardedServerHeader==null)
|
||||||
|
+ if (_forwardedServerHeader == null)
|
||||||
|
_forwardedServerHeader = HttpHeader.X_FORWARDED_SERVER.toString();
|
||||||
|
- if (_forwardedForHeader==null)
|
||||||
|
+ if (_forwardedForHeader == null)
|
||||||
|
_forwardedForHeader = HttpHeader.X_FORWARDED_FOR.toString();
|
||||||
|
- if (_forwardedPortHeader==null)
|
||||||
|
+ if (_forwardedPortHeader == null)
|
||||||
|
_forwardedPortHeader = HttpHeader.X_FORWARDED_PORT.toString();
|
||||||
|
- if (_forwardedProtoHeader==null)
|
||||||
|
+ if (_forwardedProtoHeader == null)
|
||||||
|
_forwardedProtoHeader = HttpHeader.X_FORWARDED_PROTO.toString();
|
||||||
|
- if (_forwardedHttpsHeader==null)
|
||||||
|
+ if (_forwardedHttpsHeader == null)
|
||||||
|
_forwardedHttpsHeader = "X-Proxied-Https";
|
||||||
|
}
|
||||||
|
|
||||||
|
updateHandles();
|
||||||
|
}
|
||||||
|
-
|
||||||
|
+
|
||||||
|
public String getForcedHost()
|
||||||
|
{
|
||||||
|
return _forcedHost.getValue();
|
||||||
|
}
|
||||||
|
-
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* Set a forced valued for the host header to control what is returned by {@link ServletRequest#getServerName()} and {@link ServletRequest#getServerPort()}.
|
||||||
|
*
|
||||||
|
- * @param hostAndPort
|
||||||
|
- * The value of the host header to force.
|
||||||
|
+ * @param hostAndPort The value of the host header to force.
|
||||||
|
*/
|
||||||
|
public void setForcedHost(String hostAndPort)
|
||||||
|
{
|
||||||
|
_forcedHost = new HostPortHttpField(hostAndPort);
|
||||||
|
- updateHandles();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@@ -168,13 +169,15 @@ public String getForwardedHeader()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
- * @param forwardedHeader
|
||||||
|
- * The header name for RFC forwarded (default Forwarded)
|
||||||
|
+ * @param forwardedHeader The header name for RFC forwarded (default Forwarded)
|
||||||
|
*/
|
||||||
|
public void setForwardedHeader(String forwardedHeader)
|
||||||
|
{
|
||||||
|
- _forwardedHeader = forwardedHeader;
|
||||||
|
- updateHandles();
|
||||||
|
+ if (_forwardedHeader == null || !_forwardedHeader.equals(forwardedHeader))
|
||||||
|
+ {
|
||||||
|
+ _forwardedHeader = forwardedHeader;
|
||||||
|
+ updateHandles();
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getForwardedHostHeader()
|
||||||
|
@@ -183,13 +186,15 @@ public String getForwardedHostHeader()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
- * @param forwardedHostHeader
|
||||||
|
- * The header name for forwarded hosts (default {@code X-Forwarded-Host})
|
||||||
|
+ * @param forwardedHostHeader The header name for forwarded hosts (default {@code X-Forwarded-Host})
|
||||||
|
*/
|
||||||
|
public void setForwardedHostHeader(String forwardedHostHeader)
|
||||||
|
{
|
||||||
|
- _forwardedHostHeader = forwardedHostHeader;
|
||||||
|
- updateHandles();
|
||||||
|
+ if (_forwardedHostHeader == null || !_forwardedHostHeader.equalsIgnoreCase(forwardedHostHeader))
|
||||||
|
+ {
|
||||||
|
+ _forwardedHostHeader = forwardedHostHeader;
|
||||||
|
+ updateHandles();
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@@ -201,13 +206,15 @@ public String getForwardedServerHeader()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
- * @param forwardedServerHeader
|
||||||
|
- * The header name for forwarded server (default {@code X-Forwarded-Server})
|
||||||
|
+ * @param forwardedServerHeader The header name for forwarded server (default {@code X-Forwarded-Server})
|
||||||
|
*/
|
||||||
|
public void setForwardedServerHeader(String forwardedServerHeader)
|
||||||
|
{
|
||||||
|
- _forwardedServerHeader = forwardedServerHeader;
|
||||||
|
- updateHandles();
|
||||||
|
+ if (_forwardedServerHeader == null || !_forwardedServerHeader.equalsIgnoreCase(forwardedServerHeader))
|
||||||
|
+ {
|
||||||
|
+ _forwardedServerHeader = forwardedServerHeader;
|
||||||
|
+ updateHandles();
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@@ -219,13 +226,15 @@ public String getForwardedForHeader()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
- * @param forwardedRemoteAddressHeader
|
||||||
|
- * The header name for forwarded for (default {@code X-Forwarded-For})
|
||||||
|
+ * @param forwardedRemoteAddressHeader The header name for forwarded for (default {@code X-Forwarded-For})
|
||||||
|
*/
|
||||||
|
public void setForwardedForHeader(String forwardedRemoteAddressHeader)
|
||||||
|
{
|
||||||
|
- _forwardedForHeader = forwardedRemoteAddressHeader;
|
||||||
|
- updateHandles();
|
||||||
|
+ if (_forwardedForHeader == null || !_forwardedForHeader.equalsIgnoreCase(forwardedRemoteAddressHeader))
|
||||||
|
+ {
|
||||||
|
+ _forwardedForHeader = forwardedRemoteAddressHeader;
|
||||||
|
+ updateHandles();
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getForwardedPortHeader()
|
||||||
|
@@ -234,13 +243,15 @@ public String getForwardedPortHeader()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
- * @param forwardedPortHeader
|
||||||
|
- * The header name for forwarded hosts (default {@code X-Forwarded-Port})
|
||||||
|
+ * @param forwardedPortHeader The header name for forwarded hosts (default {@code X-Forwarded-Port})
|
||||||
|
*/
|
||||||
|
public void setForwardedPortHeader(String forwardedPortHeader)
|
||||||
|
{
|
||||||
|
- _forwardedHostHeader = forwardedPortHeader;
|
||||||
|
- updateHandles();
|
||||||
|
+ if (_forwardedHostHeader == null || !_forwardedHostHeader.equalsIgnoreCase(forwardedPortHeader))
|
||||||
|
+ {
|
||||||
|
+ _forwardedHostHeader = forwardedPortHeader;
|
||||||
|
+ updateHandles();
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@@ -256,13 +267,15 @@ public String getForwardedProtoHeader()
|
||||||
|
/**
|
||||||
|
* Set the forwardedProtoHeader.
|
||||||
|
*
|
||||||
|
- * @param forwardedProtoHeader
|
||||||
|
- * the forwardedProtoHeader to set (default {@code X-Forwarded-Proto})
|
||||||
|
+ * @param forwardedProtoHeader the forwardedProtoHeader to set (default {@code X-Forwarded-Proto})
|
||||||
|
*/
|
||||||
|
public void setForwardedProtoHeader(String forwardedProtoHeader)
|
||||||
|
{
|
||||||
|
- _forwardedProtoHeader = forwardedProtoHeader;
|
||||||
|
- updateHandles();
|
||||||
|
+ if (_forwardedProtoHeader == null || !_forwardedProtoHeader.equalsIgnoreCase(forwardedProtoHeader))
|
||||||
|
+ {
|
||||||
|
+ _forwardedProtoHeader = forwardedProtoHeader;
|
||||||
|
+ updateHandles();
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@@ -274,13 +287,15 @@ public String getForwardedCipherSuiteHeader()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
- * @param forwardedCipherSuite
|
||||||
|
- * The header name holding a forwarded cipher suite (default {@code Proxy-auth-cert})
|
||||||
|
+ * @param forwardedCipherSuiteHeader The header name holding a forwarded cipher suite (default {@code Proxy-auth-cert})
|
||||||
|
*/
|
||||||
|
- public void setForwardedCipherSuiteHeader(String forwardedCipherSuite)
|
||||||
|
+ public void setForwardedCipherSuiteHeader(String forwardedCipherSuiteHeader)
|
||||||
|
{
|
||||||
|
- _forwardedCipherSuiteHeader = forwardedCipherSuite;
|
||||||
|
- updateHandles();
|
||||||
|
+ if (_forwardedCipherSuiteHeader == null || !_forwardedCipherSuiteHeader.equalsIgnoreCase(forwardedCipherSuiteHeader))
|
||||||
|
+ {
|
||||||
|
+ _forwardedCipherSuiteHeader = forwardedCipherSuiteHeader;
|
||||||
|
+ updateHandles();
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@@ -292,13 +307,15 @@ public String getForwardedSslSessionIdHeader()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
- * @param forwardedSslSessionId
|
||||||
|
- * The header name holding a forwarded SSL Session ID (default {@code Proxy-ssl-id})
|
||||||
|
+ * @param forwardedSslSessionIdHeader The header name holding a forwarded SSL Session ID (default {@code Proxy-ssl-id})
|
||||||
|
*/
|
||||||
|
- public void setForwardedSslSessionIdHeader(String forwardedSslSessionId)
|
||||||
|
+ public void setForwardedSslSessionIdHeader(String forwardedSslSessionIdHeader)
|
||||||
|
{
|
||||||
|
- _forwardedSslSessionIdHeader = forwardedSslSessionId;
|
||||||
|
- updateHandles();
|
||||||
|
+ if (_forwardedSslSessionIdHeader == null || !_forwardedSslSessionIdHeader.equalsIgnoreCase(forwardedSslSessionIdHeader))
|
||||||
|
+ {
|
||||||
|
+ _forwardedSslSessionIdHeader = forwardedSslSessionIdHeader;
|
||||||
|
+ updateHandles();
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@@ -314,10 +331,13 @@ public String getForwardedHttpsHeader()
|
||||||
|
*/
|
||||||
|
public void setForwardedHttpsHeader(String forwardedHttpsHeader)
|
||||||
|
{
|
||||||
|
- _forwardedHttpsHeader = forwardedHttpsHeader;
|
||||||
|
- updateHandles();
|
||||||
|
+ if (_forwardedHttpsHeader == null || !_forwardedHttpsHeader.equalsIgnoreCase(forwardedHttpsHeader))
|
||||||
|
+ {
|
||||||
|
+ _forwardedHttpsHeader = forwardedHttpsHeader;
|
||||||
|
+ updateHandles();
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
-
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* @return true if the presence of a SSL session or certificate header is sufficient
|
||||||
|
* to indicate a secure request (default is true)
|
||||||
|
@@ -329,7 +349,7 @@ public boolean isSslIsSecure()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param sslIsSecure true if the presence of a SSL session or certificate header is sufficient
|
||||||
|
- * to indicate a secure request (default is true)
|
||||||
|
+ * to indicate a secure request (default is true)
|
||||||
|
*/
|
||||||
|
public void setSslIsSecure(boolean sslIsSecure)
|
||||||
|
{
|
||||||
|
@@ -362,13 +382,13 @@ public void customize(Connector connector, HttpConfiguration config, Request req
|
||||||
|
{
|
||||||
|
// Update host header
|
||||||
|
httpFields.put(_forcedHost);
|
||||||
|
- request.setAuthority(_forcedHost.getHost(),_forcedHost.getPort());
|
||||||
|
+ request.setAuthority(_forcedHost.getHost(), _forcedHost.getPort());
|
||||||
|
}
|
||||||
|
- else if (forwarded._rfc7239!=null && forwarded._rfc7239._host!=null)
|
||||||
|
+ else if (forwarded._rfc7239 != null && forwarded._rfc7239._host != null)
|
||||||
|
{
|
||||||
|
HostPortHttpField auth = forwarded._rfc7239._host;
|
||||||
|
httpFields.put(auth);
|
||||||
|
- request.setAuthority(auth.getHost(),auth.getPort());
|
||||||
|
+ request.setAuthority(auth.getHost(), auth.getPort());
|
||||||
|
}
|
||||||
|
else if (forwarded._forwardedHost != null)
|
||||||
|
{
|
||||||
|
@@ -378,26 +398,26 @@ else if (forwarded._forwardedHost != null)
|
||||||
|
}
|
||||||
|
else if (_proxyAsAuthority)
|
||||||
|
{
|
||||||
|
- if (forwarded._rfc7239!=null && forwarded._rfc7239._by!=null)
|
||||||
|
+ if (forwarded._rfc7239 != null && forwarded._rfc7239._by != null)
|
||||||
|
{
|
||||||
|
HostPortHttpField auth = forwarded._rfc7239._by;
|
||||||
|
httpFields.put(auth);
|
||||||
|
- request.setAuthority(auth.getHost(),auth.getPort());
|
||||||
|
+ request.setAuthority(auth.getHost(), auth.getPort());
|
||||||
|
}
|
||||||
|
else if (forwarded._forwardedServer != null)
|
||||||
|
{
|
||||||
|
- request.setAuthority(forwarded._forwardedServer,request.getServerPort());
|
||||||
|
+ request.setAuthority(forwarded._forwardedServer, request.getServerPort());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle remote end identifier
|
||||||
|
- if (forwarded._rfc7239!=null && forwarded._rfc7239._for!=null)
|
||||||
|
+ if (forwarded._rfc7239 != null && forwarded._rfc7239._for != null)
|
||||||
|
{
|
||||||
|
- request.setRemoteAddr(InetSocketAddress.createUnresolved(forwarded._rfc7239._for.getHost(),forwarded._rfc7239._for.getPort()));
|
||||||
|
+ request.setRemoteAddr(InetSocketAddress.createUnresolved(forwarded._rfc7239._for.getHost(), forwarded._rfc7239._for.getPort()));
|
||||||
|
}
|
||||||
|
else if (forwarded._forwardedFor != null)
|
||||||
|
{
|
||||||
|
- int port = (forwarded._forwardedPort>0)
|
||||||
|
+ int port = (forwarded._forwardedPort > 0)
|
||||||
|
? forwarded._forwardedPort
|
||||||
|
: (forwarded._forwardedFor.getPort() > 0)
|
||||||
|
? forwarded._forwardedFor.getPort()
|
||||||
|
@@ -406,7 +426,7 @@ else if (forwarded._forwardedFor != null)
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle protocol identifier
|
||||||
|
- if (forwarded._rfc7239!=null && forwarded._rfc7239._proto!=null)
|
||||||
|
+ if (forwarded._rfc7239 != null && forwarded._rfc7239._proto != null)
|
||||||
|
{
|
||||||
|
request.setScheme(forwarded._rfc7239._proto);
|
||||||
|
if (forwarded._rfc7239._proto.equals(config.getSecureScheme()))
|
||||||
|
@@ -418,7 +438,7 @@ else if (forwarded._forwardedProto != null)
|
||||||
|
if (forwarded._forwardedProto.equals(config.getSecureScheme()))
|
||||||
|
request.setSecure(true);
|
||||||
|
}
|
||||||
|
- else if (forwarded._forwardedHttps !=null && ("on".equalsIgnoreCase(forwarded._forwardedHttps)||"true".equalsIgnoreCase(forwarded._forwardedHttps)))
|
||||||
|
+ 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()))
|
||||||
|
@@ -441,7 +461,7 @@ protected String getLeftMost(String headerValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The left-most value is the farthest downstream client
|
||||||
|
- return headerValue.substring(0,commaIndex).trim();
|
||||||
|
+ return headerValue.substring(0, commaIndex).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected HostPort getRemoteAddr(String headerValue)
|
||||||
|
@@ -463,11 +483,11 @@ protected HostPort getRemoteAddr(String headerValue)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
-
|
||||||
|
+
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
- return String.format("%s@%x",this.getClass().getSimpleName(),hashCode());
|
||||||
|
+ return String.format("%s@%x", this.getClass().getSimpleName(), hashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
@@ -475,12 +495,11 @@ public String getHostHeader()
|
||||||
|
{
|
||||||
|
return _forcedHost.getValue();
|
||||||
|
}
|
||||||
|
-
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* Set a forced valued for the host header to control what is returned by {@link ServletRequest#getServerName()} and {@link ServletRequest#getServerPort()}.
|
||||||
|
*
|
||||||
|
- * @param hostHeader
|
||||||
|
- * The value of the host header to force.
|
||||||
|
+ * @param hostHeader The value of the host header to force.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public void setHostHeader(String hostHeader)
|
||||||
|
@@ -494,7 +513,7 @@ public void setHostHeader(String hostHeader)
|
||||||
|
HostPortHttpField _for;
|
||||||
|
HostPortHttpField _host;
|
||||||
|
String _proto;
|
||||||
|
-
|
||||||
|
+
|
||||||
|
private RFC7239()
|
||||||
|
{
|
||||||
|
super(false);
|
||||||
|
@@ -503,27 +522,27 @@ private RFC7239()
|
||||||
|
@Override
|
||||||
|
protected void parsedParam(StringBuffer buffer, int valueLength, int paramName, int paramValue)
|
||||||
|
{
|
||||||
|
- if (valueLength==0 && paramValue>paramName)
|
||||||
|
+ if (valueLength == 0 && paramValue > paramName)
|
||||||
|
{
|
||||||
|
- String name=StringUtil.asciiToLowerCase(buffer.substring(paramName,paramValue-1));
|
||||||
|
- String value=buffer.substring(paramValue);
|
||||||
|
- switch(name)
|
||||||
|
+ 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);
|
||||||
|
+ 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);
|
||||||
|
+ if (_for == null && !value.startsWith("_") && !"unknown".equals(value))
|
||||||
|
+ _for = new HostPortHttpField(value);
|
||||||
|
break;
|
||||||
|
case "host":
|
||||||
|
- if (_host==null)
|
||||||
|
- _host=new HostPortHttpField(value);
|
||||||
|
+ if (_host == null)
|
||||||
|
+ _host = new HostPortHttpField(value);
|
||||||
|
break;
|
||||||
|
case "proto":
|
||||||
|
- if (_proto==null)
|
||||||
|
- _proto=value;
|
||||||
|
+ if (_proto == null)
|
||||||
|
+ _proto = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -536,7 +555,7 @@ private void updateHandles()
|
||||||
|
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||||
|
MethodType type = methodType(Void.TYPE, HttpField.class);
|
||||||
|
|
||||||
|
- while(true)
|
||||||
|
+ while (true)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
@@ -563,7 +582,7 @@ private void updateHandles()
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
- catch (NoSuchMethodException|IllegalAccessException e)
|
||||||
|
+ catch (NoSuchMethodException | IllegalAccessException e)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
@@ -591,7 +610,7 @@ public Forwarded(Request request, HttpConfiguration config)
|
||||||
|
|
||||||
|
public void handleCipherSuite(HttpField field)
|
||||||
|
{
|
||||||
|
- _request.setAttribute("javax.servlet.request.cipher_suite",field.getValue());
|
||||||
|
+ _request.setAttribute("javax.servlet.request.cipher_suite", field.getValue());
|
||||||
|
if (isSslIsSecure())
|
||||||
|
{
|
||||||
|
_request.setSecure(true);
|
||||||
|
@@ -633,6 +652,7 @@ public void handlePort(HttpField field)
|
||||||
|
{
|
||||||
|
_forwardedPort = field.getIntValue();
|
||||||
|
}
|
||||||
|
+
|
||||||
|
public void handleHttps(HttpField field)
|
||||||
|
{
|
||||||
|
_forwardedHttps = getLeftMost(field.getValue());
|
||||||
|
@@ -640,11 +660,9 @@ public void handleHttps(HttpField field)
|
||||||
|
|
||||||
|
public void handleRFC7239(HttpField field)
|
||||||
|
{
|
||||||
|
- if (_rfc7239 ==null)
|
||||||
|
+ if (_rfc7239 == null)
|
||||||
|
_rfc7239 = new RFC7239();
|
||||||
|
_rfc7239.addValue(field.getValue());
|
||||||
|
}
|
||||||
|
-
|
||||||
|
-
|
||||||
|
}
|
||||||
|
}
|
||||||
1167
CVE-2020-27223-pre-4.patch
Normal file
1167
CVE-2020-27223-pre-4.patch
Normal file
File diff suppressed because it is too large
Load Diff
228
CVE-2020-27223.patch
Normal file
228
CVE-2020-27223.patch
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
From 10e531756b972162eed402c44d0244f7f6b85131 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Joakim Erdfelt <joakim.erdfelt@gmail.com>
|
||||||
|
Date: Thu, 18 Feb 2021 07:14:38 -0600
|
||||||
|
Subject: [PATCH] Merge pull request from GHSA-m394-8rww-3jr7
|
||||||
|
|
||||||
|
Use comparator based sort
|
||||||
|
Signed-off-by: Joakim Erdfelt <joakim.erdfelt@gmail.com>
|
||||||
|
Signed-off-by: gregw <gregw@webtide.com>
|
||||||
|
|
||||||
|
Co-authored-by: gregw <gregw@webtide.com>
|
||||||
|
---
|
||||||
|
.../eclipse/jetty/http/QuotedQualityCSV.java | 117 +++++++++++++-----
|
||||||
|
1 file changed, 86 insertions(+), 31 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java b/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java
|
||||||
|
index d148d9e..67f9981 100644
|
||||||
|
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java
|
||||||
|
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java
|
||||||
|
@@ -21,12 +21,12 @@ package org.eclipse.jetty.http;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
+import java.util.Objects;
|
||||||
|
import java.util.function.ToIntFunction;
|
||||||
|
+import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.util.log.Log;
|
||||||
|
|
||||||
|
-import static java.lang.Integer.MIN_VALUE;
|
||||||
|
-
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
@@ -57,7 +57,8 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable<String>
|
||||||
|
return 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
- private final List<Double> _quality = new ArrayList<>();
|
||||||
|
+ private final List<QualityValue> _qualities = new ArrayList<>();
|
||||||
|
+ private QualityValue _lastQuality;
|
||||||
|
private boolean _sorted = false;
|
||||||
|
private final ToIntFunction<String> _secondaryOrdering;
|
||||||
|
|
||||||
|
@@ -68,7 +69,7 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable<String>
|
||||||
|
*/
|
||||||
|
public QuotedQualityCSV()
|
||||||
|
{
|
||||||
|
- this((ToIntFunction)null);
|
||||||
|
+ this((ToIntFunction<String>)null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
@@ -89,7 +90,7 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable<String>
|
||||||
|
if ("*".equals(s))
|
||||||
|
return preferredOrder.length;
|
||||||
|
|
||||||
|
- return MIN_VALUE;
|
||||||
|
+ return 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -98,27 +99,43 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable<String>
|
||||||
|
/**
|
||||||
|
* Orders values with equal quality with the given function.
|
||||||
|
*
|
||||||
|
- * @param secondaryOrdering Function to apply an ordering other than specified by quality
|
||||||
|
+ * @param secondaryOrdering Function to apply an ordering other than specified by quality, highest values are sorted first.
|
||||||
|
*/
|
||||||
|
public QuotedQualityCSV(ToIntFunction<String> secondaryOrdering)
|
||||||
|
{
|
||||||
|
this._secondaryOrdering = secondaryOrdering == null ? s -> 0 : secondaryOrdering;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ @Override
|
||||||
|
+ protected void parsedValueAndParams(StringBuffer buffer)
|
||||||
|
+ {
|
||||||
|
+ super.parsedValueAndParams(buffer);
|
||||||
|
+
|
||||||
|
+ // Collect full value with parameters
|
||||||
|
+ _lastQuality = new QualityValue(_lastQuality._quality, buffer.toString(), _lastQuality._index);
|
||||||
|
+ _qualities.set(_lastQuality._index, _lastQuality);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
@Override
|
||||||
|
protected void parsedValue(StringBuffer buffer)
|
||||||
|
{
|
||||||
|
super.parsedValue(buffer);
|
||||||
|
|
||||||
|
+ _sorted = false;
|
||||||
|
+
|
||||||
|
+ // This is the just the value, without parameters.
|
||||||
|
// Assume a quality of ONE
|
||||||
|
- _quality.add(1.0D);
|
||||||
|
+ _lastQuality = new QualityValue(1.0D, buffer.toString(), _qualities.size());
|
||||||
|
+ _qualities.add(_lastQuality);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
@Override
|
||||||
|
protected void parsedParam(StringBuffer buffer, int valueLength, int paramName, int paramValue)
|
||||||
|
{
|
||||||
|
+ _sorted = false;
|
||||||
|
+
|
||||||
|
if (paramName < 0)
|
||||||
|
{
|
||||||
|
if (buffer.charAt(buffer.length() - 1) == ';')
|
||||||
|
@@ -128,7 +145,7 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable<String>
|
||||||
|
buffer.charAt(paramName) == 'q' && paramValue > paramName &&
|
||||||
|
buffer.length() >= paramName && buffer.charAt(paramName + 1) == '=')
|
||||||
|
{
|
||||||
|
- Double q;
|
||||||
|
+ double q;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
q = (_keepQuotes && buffer.charAt(paramValue) == '"')
|
||||||
|
@@ -143,8 +160,10 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable<String>
|
||||||
|
buffer.setLength(Math.max(0, paramName - 1));
|
||||||
|
|
||||||
|
if (q != 1.0D)
|
||||||
|
- // replace assumed quality
|
||||||
|
- _quality.set(_quality.size() - 1, q);
|
||||||
|
+ {
|
||||||
|
+ _lastQuality = new QualityValue(q, buffer.toString(), _lastQuality._index);
|
||||||
|
+ _qualities.set(_lastQuality._index, _lastQuality);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -166,38 +185,74 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable<String>
|
||||||
|
|
||||||
|
protected void sort()
|
||||||
|
{
|
||||||
|
+ _values.clear();
|
||||||
|
+ _qualities.stream()
|
||||||
|
+ .filter((qv) -> qv._quality != 0.0D)
|
||||||
|
+ .sorted()
|
||||||
|
+ .map(QualityValue::getValue)
|
||||||
|
+ .collect(Collectors.toCollection(() -> _values));
|
||||||
|
_sorted = true;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
- Double last = 0.0D;
|
||||||
|
- int lastSecondaryOrder = Integer.MIN_VALUE;
|
||||||
|
+ private class QualityValue implements Comparable<QualityValue>
|
||||||
|
+ {
|
||||||
|
+ private final double _quality;
|
||||||
|
+ private final String _value;
|
||||||
|
+ private final int _index;
|
||||||
|
|
||||||
|
- for (int i = _values.size(); i-- > 0; )
|
||||||
|
+ private QualityValue(double quality, String value, int index)
|
||||||
|
{
|
||||||
|
- String v = _values.get(i);
|
||||||
|
- Double q = _quality.get(i);
|
||||||
|
+ _quality = quality;
|
||||||
|
+ _value = value;
|
||||||
|
+ _index = index;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public int hashCode()
|
||||||
|
+ {
|
||||||
|
+ return Double.hashCode(_quality) ^ Objects.hash(_value, _index);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public boolean equals(Object obj)
|
||||||
|
+ {
|
||||||
|
+ if (!(obj instanceof QualityValue))
|
||||||
|
+ return false;
|
||||||
|
+ QualityValue qv = (QualityValue)obj;
|
||||||
|
+ return _quality == qv._quality && Objects.equals(_value, qv._value) && Objects.equals(_index, qv._index);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private String getValue()
|
||||||
|
+ {
|
||||||
|
+ return _value;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
- int compare = last.compareTo(q);
|
||||||
|
- if (compare > 0 || (compare == 0 && _secondaryOrdering.applyAsInt(v) < lastSecondaryOrder))
|
||||||
|
+ @Override
|
||||||
|
+ public int compareTo(QualityValue o)
|
||||||
|
+ {
|
||||||
|
+ // sort highest quality first
|
||||||
|
+ int compare = Double.compare(o._quality, _quality);
|
||||||
|
+ if (compare == 0)
|
||||||
|
{
|
||||||
|
- _values.set(i, _values.get(i + 1));
|
||||||
|
- _values.set(i + 1, v);
|
||||||
|
- _quality.set(i, _quality.get(i + 1));
|
||||||
|
- _quality.set(i + 1, q);
|
||||||
|
- last = 0.0D;
|
||||||
|
- lastSecondaryOrder = 0;
|
||||||
|
- i = _values.size();
|
||||||
|
- continue;
|
||||||
|
+ // then sort secondary order highest first
|
||||||
|
+ compare = Integer.compare(_secondaryOrdering.applyAsInt(o._value), _secondaryOrdering.applyAsInt(_value));
|
||||||
|
+ if (compare == 0)
|
||||||
|
+ // then sort index lowest first
|
||||||
|
+ compare = -Integer.compare(o._index, _index);
|
||||||
|
}
|
||||||
|
|
||||||
|
- last = q;
|
||||||
|
- lastSecondaryOrder = _secondaryOrdering.applyAsInt(v);
|
||||||
|
+ return compare;
|
||||||
|
}
|
||||||
|
|
||||||
|
- int last_element = _quality.size();
|
||||||
|
- while (last_element > 0 && _quality.get(--last_element).equals(0.0D))
|
||||||
|
+ @Override
|
||||||
|
+ public String toString()
|
||||||
|
{
|
||||||
|
- _quality.remove(last_element);
|
||||||
|
- _values.remove(last_element);
|
||||||
|
+ return String.format("%s@%x[%s,q=%f,i=%d]",
|
||||||
|
+ getClass().getSimpleName(),
|
||||||
|
+ hashCode(),
|
||||||
|
+ _value,
|
||||||
|
+ _quality,
|
||||||
|
+ _index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
--
|
||||||
|
2.23.0
|
||||||
|
|
||||||
10
jetty.spec
10
jetty.spec
@ -12,7 +12,7 @@
|
|||||||
%bcond_with jp_minimal
|
%bcond_with jp_minimal
|
||||||
Name: jetty
|
Name: jetty
|
||||||
Version: 9.4.15
|
Version: 9.4.15
|
||||||
Release: 5
|
Release: 6
|
||||||
Summary: Java Webserver and Servlet Container
|
Summary: Java Webserver and Servlet Container
|
||||||
License: ASL 2.0 or EPL-1.0 or EPL-2.0
|
License: ASL 2.0 or EPL-1.0 or EPL-2.0
|
||||||
URL: http://www.eclipse.org/jetty/
|
URL: http://www.eclipse.org/jetty/
|
||||||
@ -22,6 +22,11 @@ Source3: jetty.logrotate
|
|||||||
Source5: %{name}.service
|
Source5: %{name}.service
|
||||||
Source6: LICENSE-MIT
|
Source6: LICENSE-MIT
|
||||||
Patch0: CVE-2020-27216.patch
|
Patch0: CVE-2020-27216.patch
|
||||||
|
Patch1: CVE-2020-27223-pre-1.patch
|
||||||
|
Patch2: CVE-2020-27223-pre-2.patch
|
||||||
|
Patch3: CVE-2020-27223-pre-3.patch
|
||||||
|
Patch4: CVE-2020-27223-pre-4.patch
|
||||||
|
Patch5: CVE-2020-27223.patch
|
||||||
BuildRequires: maven-local mvn(javax.servlet:javax.servlet-api)
|
BuildRequires: maven-local mvn(javax.servlet:javax.servlet-api)
|
||||||
BuildRequires: mvn(org.apache.felix:maven-bundle-plugin)
|
BuildRequires: mvn(org.apache.felix:maven-bundle-plugin)
|
||||||
BuildRequires: mvn(org.apache.maven.plugins:maven-shade-plugin)
|
BuildRequires: mvn(org.apache.maven.plugins:maven-shade-plugin)
|
||||||
@ -780,6 +785,9 @@ exit 0
|
|||||||
%license LICENSE NOTICE.txt LICENSE-MIT
|
%license LICENSE NOTICE.txt LICENSE-MIT
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Wed Mar 17 2021 zhanghua <zhanghua40@huawei.com> - 9.4.15-6
|
||||||
|
- fix CVE-2020-27223
|
||||||
|
|
||||||
* Mon Feb 8 2021 zhanghua <zhanghua40@huawei.com> - 9.4.15-5
|
* Mon Feb 8 2021 zhanghua <zhanghua40@huawei.com> - 9.4.15-5
|
||||||
- fix CVE-2020-27216
|
- fix CVE-2020-27216
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user