From 8011c48685e78850a88e7cc06650f678a375037d Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Thu, 28 Feb 2019 18:37:02 +1100 Subject: [PATCH 1/4] Issue #3404 Updated QCSV Double usage Signed-off-by: Greg Wilkins --- .../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 { - 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 MOST_SPECIFIC = new Function() + public static Function 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 _quality = new ArrayList<>(); @@ -74,7 +71,8 @@ public QuotedQualityCSV() */ public QuotedQualityCSV(String[] preferredOrder) { - this((s) -> { + this((s) -> + { for (int i=0;i 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 Date: Fri, 1 Mar 2019 10:17:02 +1100 Subject: [PATCH 2/4] Issue #3404 Cleanup QCSV mime ordering Signed-off-by: Greg Wilkins --- .../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 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 getQualityCSV(HttpHeader header, Function 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 -{ - 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 MOST_SPECIFIC = s -> + public static Function 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 _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 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 acceptable=baseRequest.getHttpFields().getQualityCSV(HttpHeader.ACCEPT); + List 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 Date: Fri, 1 Mar 2019 10:20:10 +1100 Subject: [PATCH 3/4] Issue #3404 Updated QCSV Double usage Signed-off-by: Greg Wilkins --- .../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 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 --- .../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 getQualityCSV(HttpHeader header, Function secondaryOrdering) + public List getQualityCSV(HttpHeader header, ToIntFunction 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 MOST_SPECIFIC_MIME_ORDERING = s -> + public static ToIntFunction 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 _quality = new ArrayList<>(); private boolean _sorted = false; - private final Function _secondaryOrdering; - + private final ToIntFunction _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 secondaryOrdering) + public QuotedQualityCSV(ToIntFunction 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 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) 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);