pass existing compliance tests
Signed-off-by: Greg Wilkins <gregw@webtide.com>
This commit is contained in:
parent
d8dead35ae
commit
7e516e29fb
|
@ -35,15 +35,12 @@ import org.eclipse.jetty.client.Origin;
|
|||
import org.eclipse.jetty.client.api.Response;
|
||||
import org.eclipse.jetty.client.util.FutureResponseListener;
|
||||
import org.eclipse.jetty.http.HttpCompliance;
|
||||
import org.eclipse.jetty.http.HttpComplianceSection;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.io.ByteArrayEndPoint;
|
||||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
||||
import org.eclipse.jetty.util.Promise;
|
||||
import org.hamcrest.CoreMatchers;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
|
@ -54,12 +51,7 @@ import org.junit.runners.Parameterized;
|
|||
|
||||
@RunWith(Parameterized.class)
|
||||
public class HttpReceiverOverHTTPTest
|
||||
{
|
||||
static
|
||||
{
|
||||
HttpCompliance.CUSTOM0.sections().remove(HttpComplianceSection.RFC7230_3_2_4_NO_WS_AFTER_FIELD_NAME);
|
||||
}
|
||||
|
||||
{
|
||||
@Rule
|
||||
public final TestTracker tracker = new TestTracker();
|
||||
|
||||
|
@ -76,7 +68,6 @@ public class HttpReceiverOverHTTPTest
|
|||
{
|
||||
return Arrays.asList(
|
||||
new Object[] { HttpCompliance.LEGACY },
|
||||
new Object[] { HttpCompliance.CUSTOM0 },
|
||||
new Object[] { HttpCompliance.RFC2616 },
|
||||
new Object[] { HttpCompliance.RFC7230 }
|
||||
);
|
||||
|
@ -235,37 +226,6 @@ public class HttpReceiverOverHTTPTest
|
|||
Assert.assertTrue(e.getCause() instanceof HttpResponseException);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Receive_Invalid_Response_With_Weak_Compliance() throws Exception
|
||||
{
|
||||
endPoint.addInput("" +
|
||||
"HTTP/1.1 200 OK\r\n" +
|
||||
"Content-length : 0\r\n" +
|
||||
"\r\n");
|
||||
HttpExchange exchange = newExchange();
|
||||
FutureResponseListener listener = (FutureResponseListener)exchange.getResponseListeners().get(0);
|
||||
connection.getHttpChannel().receive();
|
||||
|
||||
try {
|
||||
Response response = listener.get(5, TimeUnit.SECONDS);
|
||||
|
||||
Assert.assertThat(compliance, Matchers.lessThanOrEqualTo(HttpCompliance.CUSTOM0));
|
||||
Assert.assertNotNull(response);
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
Assert.assertEquals("OK", response.getReason());
|
||||
Assert.assertSame(HttpVersion.HTTP_1_1, response.getVersion());
|
||||
HttpFields headers = response.getHeaders();
|
||||
Assert.assertNotNull(headers);
|
||||
Assert.assertEquals(1, headers.size());
|
||||
Assert.assertEquals("0", headers.get(HttpHeader.CONTENT_LENGTH));
|
||||
} catch (Exception e) {
|
||||
Assert.assertThat(compliance, Matchers.greaterThan(HttpCompliance.CUSTOM0));
|
||||
Throwable cause = e.getCause();
|
||||
Assert.assertThat(cause, CoreMatchers.instanceOf(HttpResponseException.class));
|
||||
Assert.assertThat(cause.getMessage(), Matchers.containsString("HTTP protocol violation"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_FillInterested_RacingWith_BufferRelease() throws Exception
|
||||
|
|
|
@ -38,8 +38,13 @@ public enum HttpCompliance
|
|||
{
|
||||
// TODO in Jetty-10 convert this enum to a class so that extra custom modes can be defined dynamically
|
||||
LEGACY(sectionsBySpec("LEGACY")),
|
||||
RFC2616(sectionsBySpec("RFC2616")),
|
||||
RFC7230(sectionsBySpec("RFC7230,-RFC7230_3_1_1_METHOD_CASE_SENSITIVE")), // TODO fix in Jetty-10
|
||||
|
||||
// Jetty's historic RFC2616 support incorrectly allowed no colon and case insensitive methods
|
||||
RFC2616(sectionsBySpec("RFC2616,-RFC7230_3_2_FIELD_COLON,-RFC7230_3_1_1_METHOD_CASE_SENSITIVE")),
|
||||
|
||||
// TODO Jetty's current RFC7230 support incorrectly handles methods case insensitively
|
||||
RFC7230(sectionsBySpec("RFC7230,-RFC7230_3_1_1_METHOD_CASE_SENSITIVE")),
|
||||
|
||||
CUSTOM0(sectionsByProperty("CUSTOM0")),
|
||||
CUSTOM1(sectionsByProperty("CUSTOM1")),
|
||||
CUSTOM2(sectionsByProperty("CUSTOM2")),
|
||||
|
@ -59,17 +64,25 @@ public enum HttpCompliance
|
|||
int i=0;
|
||||
|
||||
switch(elements[i])
|
||||
{
|
||||
{
|
||||
case "0":
|
||||
sections = EnumSet.noneOf(HttpComplianceSection.class);
|
||||
i++;
|
||||
break;
|
||||
|
||||
case "*":
|
||||
i++;
|
||||
sections = EnumSet.allOf(HttpComplianceSection.class);
|
||||
break;
|
||||
|
||||
case "RFC2616":
|
||||
sections = EnumSet.complementOf(EnumSet.of(
|
||||
HttpComplianceSection.RFC7230_3_2_4_NO_WS_AFTER_FIELD_NAME,
|
||||
HttpComplianceSection.RFC7230_3_2_4_NO_FOLDING,
|
||||
HttpComplianceSection.RFC7230_A2_NO_HTTP_9));
|
||||
i++;
|
||||
break;
|
||||
|
||||
case "RFC7230":
|
||||
case "*":
|
||||
i++;
|
||||
sections = EnumSet.allOf(HttpComplianceSection.class);
|
||||
break;
|
||||
|
@ -79,10 +92,6 @@ public enum HttpCompliance
|
|||
i++;
|
||||
break;
|
||||
|
||||
case "0":
|
||||
sections = EnumSet.noneOf(HttpComplianceSection.class);
|
||||
i++;
|
||||
break;
|
||||
default:
|
||||
sections = EnumSet.noneOf(HttpComplianceSection.class);
|
||||
break;
|
||||
|
@ -135,8 +144,6 @@ public enum HttpCompliance
|
|||
return __required.get(section);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private final EnumSet<HttpComplianceSection> _sections;
|
||||
|
||||
private HttpCompliance(EnumSet<HttpComplianceSection> sections)
|
||||
|
|
|
@ -31,8 +31,23 @@ public enum HttpComplianceSection
|
|||
RFC7230_A2_NO_HTTP_9("https://tools.ietf.org/html/rfc7230#appendix-A.2","No HTTP/0.9"),
|
||||
;
|
||||
|
||||
final String url;
|
||||
final String description;
|
||||
|
||||
HttpComplianceSection(String url,String description)
|
||||
{
|
||||
|
||||
this.url = url;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getURL()
|
||||
{
|
||||
return url;
|
||||
}
|
||||
|
||||
public String getDescription()
|
||||
{
|
||||
return description;
|
||||
}
|
||||
|
||||
}
|
|
@ -35,8 +35,6 @@ import org.eclipse.jetty.util.Utf8StringBuilder;
|
|||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
import static org.eclipse.jetty.http.HttpCompliance.RFC2616;
|
||||
import static org.eclipse.jetty.http.HttpCompliance.RFC7230;
|
||||
import static org.eclipse.jetty.http.HttpTokens.CARRIAGE_RETURN;
|
||||
import static org.eclipse.jetty.http.HttpTokens.LINE_FEED;
|
||||
import static org.eclipse.jetty.http.HttpTokens.SPACE;
|
||||
|
@ -1068,7 +1066,7 @@ public class HttpParser
|
|||
case HttpTokens.SPACE:
|
||||
case HttpTokens.TAB:
|
||||
{
|
||||
if (complianceViolation(HttpComplianceSection.RFC7230_3_2_4_NO_FOLDING,"Folded "+_headerString))
|
||||
if (complianceViolation(HttpComplianceSection.RFC7230_3_2_4_NO_FOLDING,_headerString))
|
||||
throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Header Folding");
|
||||
|
||||
// header value without name - continuation?
|
||||
|
@ -1279,6 +1277,7 @@ public class HttpParser
|
|||
}
|
||||
|
||||
// Fallthrough
|
||||
|
||||
case WS_AFTER_NAME:
|
||||
if (b==HttpTokens.COLON)
|
||||
{
|
||||
|
@ -1293,7 +1292,7 @@ public class HttpParser
|
|||
break;
|
||||
}
|
||||
|
||||
if (b==HttpTokens.LINE_FEED && !complianceViolation(HttpComplianceSection.RFC7230_3_2_FIELD_COLON,null))
|
||||
if (b==HttpTokens.LINE_FEED)
|
||||
{
|
||||
if (_headerString==null)
|
||||
{
|
||||
|
@ -1304,8 +1303,11 @@ public class HttpParser
|
|||
_valueString="";
|
||||
_length=-1;
|
||||
|
||||
setState(FieldState.FIELD);
|
||||
break;
|
||||
if (!complianceViolation(HttpComplianceSection.RFC7230_3_2_FIELD_COLON,_headerString))
|
||||
{
|
||||
setState(FieldState.FIELD);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Ignore trailing whitespaces
|
||||
|
|
|
@ -27,6 +27,7 @@ import java.util.List;
|
|||
import org.eclipse.jetty.http.BadMessageException;
|
||||
import org.eclipse.jetty.http.HostPortHttpField;
|
||||
import org.eclipse.jetty.http.HttpCompliance;
|
||||
import org.eclipse.jetty.http.HttpComplianceSection;
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpGenerator;
|
||||
|
@ -505,7 +506,7 @@ public class HttpChannelOverHttp extends HttpChannel implements HttpParser.Reque
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onComplianceViolation(HttpCompliance compliance, HttpCompliance required, String reason)
|
||||
public void onComplianceViolation(HttpCompliance compliance, HttpComplianceSection violation, String reason)
|
||||
{
|
||||
if (_httpConnection.isRecordHttpComplianceViolations())
|
||||
{
|
||||
|
@ -513,10 +514,11 @@ public class HttpChannelOverHttp extends HttpChannel implements HttpParser.Reque
|
|||
{
|
||||
_complianceViolations = new ArrayList<>();
|
||||
}
|
||||
String violation = String.format("%s<%s: %s for %s", compliance, required, reason, getHttpTransport());
|
||||
_complianceViolations.add(violation);
|
||||
String record = String.format("%s (see %s) in mode %s for %s in %s",
|
||||
violation.getDescription(), violation.getURL(), compliance, reason, getHttpTransport());
|
||||
_complianceViolations.add(record);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug(violation);
|
||||
LOG.debug(record);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,7 +105,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
|
|||
_channel = newHttpChannel();
|
||||
_input = _channel.getRequest().getHttpInput();
|
||||
_parser = newHttpParser(compliance);
|
||||
_recordHttpComplianceViolations=recordComplianceViolations;
|
||||
_recordHttpComplianceViolations = recordComplianceViolations;
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("New HTTP Connection {}", this);
|
||||
}
|
||||
|
|
|
@ -147,7 +147,7 @@ public class ComplianceViolations2616Test
|
|||
|
||||
String response = connector.getResponse(req1.toString());
|
||||
assertThat("Response status", response, containsString("HTTP/1.1 200 OK"));
|
||||
assertThat("Response headers", response, containsString("X-Http-Violation-0: RFC2616<RFC7230: https://tools.ietf.org/html/rfc7230#section-3.2 No colon"));
|
||||
assertThat("Response headers", response, containsString("X-Http-Violation-0: Fields must have a Colon"));
|
||||
assertThat("Response body", response, containsString("[Name] = []"));
|
||||
}
|
||||
|
||||
|
@ -164,7 +164,7 @@ public class ComplianceViolations2616Test
|
|||
|
||||
String response = connector.getResponse(req1.toString());
|
||||
assertThat("Response status", response, containsString("HTTP/1.1 200"));
|
||||
assertThat("Response headers", response, containsString("X-Http-Violation-0: RFC2616<RFC7230: https://tools.ietf.org/html/rfc7230#section-3.2 No colon"));
|
||||
assertThat("Response headers", response, containsString("X-Http-Violation-0: Fields must have a Colon"));
|
||||
assertThat("Response body", response, containsString("[Name] = []"));
|
||||
}
|
||||
|
||||
|
@ -182,7 +182,8 @@ public class ComplianceViolations2616Test
|
|||
|
||||
String response = connector.getResponse(req1.toString());
|
||||
assertThat("Response status", response, containsString("HTTP/1.1 200"));
|
||||
assertThat("Response headers", response, containsString("X-Http-Violation-0: RFC2616<RFC7230: https://tools.ietf.org/html/rfc7230#section-3.2.4 folding"));
|
||||
assertThat("Response headers", response, containsString("X-Http-Violation-0: No line Folding (see https://tools.ietf.org/html/rfc7230#section-3.2.4) in mode RFC2616 for"));
|
||||
assertThat("Response body", response, containsString("[Name] = [Some Value]"));
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue