Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/jetty-9.4.x' into jetty-10.0.x
Browse files Browse the repository at this point in the history
Signed-off-by: gregw <gregw@webtide.com>
  • Loading branch information
gregw committed Feb 24, 2021
2 parents bffa62a + 49e73df commit c4dbf97
Show file tree
Hide file tree
Showing 9 changed files with 630 additions and 502 deletions.
20 changes: 10 additions & 10 deletions jetty-http/src/main/java/org/eclipse/jetty/http/HttpCompliance.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static java.util.Arrays.asList;
import static java.util.Collections.unmodifiableSet;
import static java.util.EnumSet.allOf;
Expand All @@ -34,6 +37,7 @@
*/
public final class HttpCompliance implements ComplianceViolation.Mode
{
protected static final Logger LOG = LoggerFactory.getLogger(HttpCompliance.class);

// These are compliance violations, which may optionally be allowed by the compliance mode, which mean that
// the relevant section of the RFC is not strictly adhered to.
Expand All @@ -46,8 +50,7 @@ public enum Violation implements ComplianceViolation
MULTIPLE_CONTENT_LENGTHS("https://tools.ietf.org/html/rfc7230#section-3.3.1", "Multiple Content-Lengths"),
TRANSFER_ENCODING_WITH_CONTENT_LENGTH("https://tools.ietf.org/html/rfc7230#section-3.3.1", "Transfer-Encoding and Content-Length"),
WHITESPACE_AFTER_FIELD_NAME("https://tools.ietf.org/html/rfc7230#section-3.2.4", "Whitespace not allowed after field name"),
NO_COLON_AFTER_FIELD_NAME("https://tools.ietf.org/html/rfc7230#section-3.2", "Fields must have a Colon"),
AMBIGUOUS_PATH_SEGMENTS("https://tools.ietf.org/html/rfc3986#section-3.3", "Ambiguous URI path segments");
NO_COLON_AFTER_FIELD_NAME("https://tools.ietf.org/html/rfc7230#section-3.2", "Fields must have a Colon");

private final String url;
private final String description;
Expand Down Expand Up @@ -81,14 +84,13 @@ public String getDescription()

public static final HttpCompliance RFC7230 = new HttpCompliance("RFC7230", noneOf(Violation.class));
public static final HttpCompliance RFC2616 = new HttpCompliance("RFC2616", of(Violation.HTTP_0_9, Violation.MULTILINE_FIELD_VALUE));
public static final HttpCompliance LEGACY = new HttpCompliance("LEGACY", complementOf(of(Violation.CASE_INSENSITIVE_METHOD, Violation.AMBIGUOUS_PATH_SEGMENTS)));
public static final HttpCompliance LEGACY = new HttpCompliance("LEGACY", complementOf(of(Violation.CASE_INSENSITIVE_METHOD)));
public static final HttpCompliance RFC2616_LEGACY = RFC2616.with("RFC2616_LEGACY",
Violation.CASE_INSENSITIVE_METHOD,
Violation.NO_COLON_AFTER_FIELD_NAME,
Violation.TRANSFER_ENCODING_WITH_CONTENT_LENGTH,
Violation.MULTIPLE_CONTENT_LENGTHS,
Violation.AMBIGUOUS_PATH_SEGMENTS);
public static final HttpCompliance RFC7230_LEGACY = RFC7230.with("RFC7230_LEGACY", Violation.CASE_INSENSITIVE_METHOD, Violation.AMBIGUOUS_PATH_SEGMENTS);
Violation.MULTIPLE_CONTENT_LENGTHS);
public static final HttpCompliance RFC7230_LEGACY = RFC7230.with("RFC7230_LEGACY", Violation.CASE_INSENSITIVE_METHOD);

private static final List<HttpCompliance> KNOWN_MODES = Arrays.asList(RFC7230, RFC2616, LEGACY, RFC2616_LEGACY, RFC7230_LEGACY);
private static final AtomicInteger __custom = new AtomicInteger();
Expand All @@ -100,6 +102,7 @@ public static HttpCompliance valueOf(String name)
if (compliance.getName().equals(name))
return compliance;
}
LOG.warn("Unknown HttpCompliance mode {}", name);
return null;
}

Expand Down Expand Up @@ -141,10 +144,7 @@ public static HttpCompliance from(String spec)
default:
{
HttpCompliance mode = HttpCompliance.valueOf(elements[0]);
if (mode == null)
sections = noneOf(Violation.class);
else
sections = copyOf(mode.getAllowed());
sections = (mode == null) ? noneOf(HttpCompliance.Violation.class) : copyOf(mode.getAllowed());
}
}

Expand Down
72 changes: 61 additions & 11 deletions jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import java.net.URI;
import java.net.URISyntaxException;
import java.util.EnumSet;

import org.eclipse.jetty.util.HostPort;
import org.eclipse.jetty.util.Index;
Expand Down Expand Up @@ -47,6 +48,12 @@
*/
public interface HttpURI
{
enum Ambiguous
{
SEGMENT,
SEPARATOR
}

static Mutable build()
{
return new Mutable();
Expand Down Expand Up @@ -131,8 +138,21 @@ static Immutable from(String scheme, String host, int port, String pathQuery)

boolean isAbsolute();

/**
* @return True if the URI has either an {@link #hasAmbiguousSegment()} or {@link #hasAmbiguousSeparator()}.
*/
boolean isAmbiguous();

/**
* @return True if the URI has a possibly ambiguous segment like '..;' or '%2e%2e'
*/
boolean hasAmbiguousSegment();

/**
* @return True if the URI has a possibly ambiguous separator of %2f
*/
boolean hasAmbiguousSeparator();

default URI toURI()
{
try
Expand All @@ -158,7 +178,7 @@ class Immutable implements HttpURI
private final String _fragment;
private String _uri;
private String _decodedPath;
private boolean _ambiguousSegment;
private final EnumSet<Mutable.Ambiguous> _ambiguous = EnumSet.noneOf(Mutable.Ambiguous.class);

private Immutable(Mutable builder)
{
Expand All @@ -172,7 +192,7 @@ private Immutable(Mutable builder)
_fragment = builder._fragment;
_uri = builder._uri;
_decodedPath = builder._decodedPath;
_ambiguousSegment = builder._ambiguousSegment;
_ambiguous.addAll(builder._ambiguous);
}

private Immutable(String uri)
Expand Down Expand Up @@ -336,10 +356,22 @@ public boolean isAbsolute()
return !StringUtil.isEmpty(_scheme);
}

@Override
public boolean isAmbiguous()
{
return !_ambiguous.isEmpty();
}

@Override
public boolean hasAmbiguousSegment()
{
return _ambiguousSegment;
return _ambiguous.contains(Mutable.Ambiguous.SEGMENT);
}

@Override
public boolean hasAmbiguousSeparator()
{
return _ambiguous.contains(Mutable.Ambiguous.SEPARATOR);
}

@Override
Expand Down Expand Up @@ -411,7 +443,7 @@ private enum State
private String _fragment;
private String _uri;
private String _decodedPath;
private boolean _ambiguousSegment;
private final EnumSet<Ambiguous> _ambiguous = EnumSet.noneOf(Ambiguous.class);

private Mutable()
{
Expand Down Expand Up @@ -535,7 +567,7 @@ public Mutable clear()
_fragment = null;
_uri = null;
_decodedPath = null;
_ambiguousSegment = false;
_ambiguous.clear();
return this;
}

Expand Down Expand Up @@ -659,10 +691,22 @@ public boolean isAbsolute()
return _scheme != null && !_scheme.isEmpty();
}

@Override
public boolean isAmbiguous()
{
return !_ambiguous.isEmpty();
}

@Override
public boolean hasAmbiguousSegment()
{
return _ambiguousSegment;
return _ambiguous.contains(Mutable.Ambiguous.SEGMENT);
}

@Override
public boolean hasAmbiguousSeparator()
{
return _ambiguous.contains(Mutable.Ambiguous.SEPARATOR);
}

public Mutable normalize()
Expand Down Expand Up @@ -766,7 +810,10 @@ public Mutable uri(HttpURI uri)
_query = uri.getQuery();
_uri = null;
_decodedPath = uri.getDecodedPath();
_ambiguousSegment = uri.hasAmbiguousSegment();
if (uri.hasAmbiguousSeparator())
_ambiguous.add(Ambiguous.SEPARATOR);
if (uri.hasAmbiguousSegment())
_ambiguous.add(Ambiguous.SEGMENT);
return this;
}

Expand Down Expand Up @@ -1062,7 +1109,8 @@ else if (c == '/')
break;
case 'f':
case 'F':
_ambiguousSegment |= (escapedSlash == 2);
if (escapedSlash == 2)
_ambiguous.add(Ambiguous.SEPARATOR);
escapedSlash = 0;
break;
default:
Expand Down Expand Up @@ -1183,17 +1231,19 @@ else if (_path != null)
*
* An ambiguous path segment is one that is perhaps technically legal, but is considered undesirable to handle
* due to possible ambiguity. Examples include segments like '..;', '%2e', '%2e%2e' etc.
*
* @param uri The URI string
* @param segment The inclusive starting index of the segment (excluding any '/')
* @param end The exclusive end index of the segment
*/
private void checkSegment(String uri, int segment, int end, boolean param)
{
if (!_ambiguousSegment)
if (!_ambiguous.contains(Ambiguous.SEGMENT))
{
Boolean ambiguous = __ambiguousSegments.get(uri, segment, end - segment);
_ambiguousSegment |= ambiguous == Boolean.TRUE || (param && ambiguous == Boolean.FALSE);
if (ambiguous == Boolean.TRUE || (param && ambiguous == Boolean.FALSE))
_ambiguous.add(Ambiguous.SEGMENT);
}
}
}
}
}

0 comments on commit c4dbf97

Please sign in to comment.