diff --git a/core/src/main/java/io/undertow/UndertowMessages.java b/core/src/main/java/io/undertow/UndertowMessages.java index 3ed3b6e7b7..c72c7de641 100644 --- a/core/src/main/java/io/undertow/UndertowMessages.java +++ b/core/src/main/java/io/undertow/UndertowMessages.java @@ -513,4 +513,16 @@ public interface UndertowMessages { @Message(id = 161, value = "HTTP/2 header block is too large") String headerBlockTooLarge(); + + @Message(id = 162, value = "Same-site attribute %s is invalid. It must be Strict or Lax") + IllegalArgumentException invalidSameSiteMode(String mode); + + @Message(id = 163, value = "Invalid token %s") + IllegalArgumentException invalidToken(byte c); + + @Message(id = 164, value = "Request contained invalid headers") + IllegalArgumentException invalidHeaders(); + + @Message(id = 165, value = "Invalid character %s in request-target") + String invalidCharacterInRequestTarget(char next); } diff --git a/core/src/main/java/io/undertow/protocols/http2/Http2HeaderBlockParser.java b/core/src/main/java/io/undertow/protocols/http2/Http2HeaderBlockParser.java index 0a386d1b98..0c1b42613e 100644 --- a/core/src/main/java/io/undertow/protocols/http2/Http2HeaderBlockParser.java +++ b/core/src/main/java/io/undertow/protocols/http2/Http2HeaderBlockParser.java @@ -28,6 +28,7 @@ import io.undertow.UndertowLogger; import io.undertow.UndertowMessages; +import io.undertow.server.Connectors; import io.undertow.util.HeaderMap; import io.undertow.util.Headers; import io.undertow.util.HttpString; @@ -177,6 +178,9 @@ public void emitHeader(HttpString name, String value, boolean neverIndex) throws if(c>= 'A' && c <= 'Z') { invalid = true; UndertowLogger.REQUEST_LOGGER.debugf("Malformed request, header %s contains uppercase characters", name); + } else if(c != ':' && !Connectors.isValidTokenCharacter(c)) { + invalid = true; + UndertowLogger.REQUEST_LOGGER.debugf("Malformed request, header %s contains invalid token character", name); } } diff --git a/core/src/main/java/io/undertow/server/Connectors.java b/core/src/main/java/io/undertow/server/Connectors.java index e9375c590f..2bf2d9b82d 100644 --- a/core/src/main/java/io/undertow/server/Connectors.java +++ b/core/src/main/java/io/undertow/server/Connectors.java @@ -19,10 +19,14 @@ package io.undertow.server; import io.undertow.UndertowLogger; +import io.undertow.UndertowMessages; import io.undertow.UndertowOptions; import io.undertow.server.handlers.Cookie; import io.undertow.util.DateUtils; +import io.undertow.util.HeaderMap; +import io.undertow.util.HeaderValues; import io.undertow.util.Headers; +import io.undertow.util.HttpString; import io.undertow.util.ParameterLimitException; import io.undertow.util.StatusCodes; import io.undertow.util.URLUtils; @@ -46,7 +50,40 @@ */ public class Connectors { + private static final boolean[] ALLOWED_TOKEN_CHARACTERS = new boolean[256]; + static { + for(int i = 0; i < ALLOWED_TOKEN_CHARACTERS.length; ++i) { + if((i >='0' && i <= '9') || + (i >='a' && i <= 'z') || + (i >='A' && i <= 'Z')) { + ALLOWED_TOKEN_CHARACTERS[i] = true; + } else { + switch (i) { + case '!': + case '#': + case '$': + case '%': + case '&': + case '\'': + case '*': + case '+': + case '-': + case '.': + case '^': + case '_': + case '`': + case '|': + case '~': { + ALLOWED_TOKEN_CHARACTERS[i] = true; + break; + } + default: + ALLOWED_TOKEN_CHARACTERS[i] = false; + } + } + } + } /** * Flattens the exchange cookie map into the response header map. This should be called by a * connector just before the response is started. @@ -363,4 +400,43 @@ public static void updateResponseBytesSent(HttpServerExchange exchange, long byt public static ConduitStreamSinkChannel getConduitSinkChannel(HttpServerExchange exchange) { return exchange.getConnection().getSinkChannel(); } + + /** + * Verifies that the contents of the HttpString are a valid token according to rfc7230. + * @param header The header to verify + */ + public static void verifyToken(HttpString header) { + int length = header.length(); + for(int i = 0; i < length; ++i) { + byte c = header.byteAt(i); + if(!ALLOWED_TOKEN_CHARACTERS[c]) { + throw UndertowMessages.MESSAGES.invalidToken(c); + } + } + } + + /** + * Returns true if the token character is valid according to rfc7230 + */ + public static boolean isValidTokenCharacter(byte c) { + return ALLOWED_TOKEN_CHARACTERS[c]; + } + + + /** + * Verifies that the provided request headers are valid according to rfc7230. In particular: + * - At most one content-length or transfer encoding + */ + public static boolean areRequestHeadersValid(HeaderMap headers) { + HeaderValues te = headers.get(Headers.TRANSFER_ENCODING); + HeaderValues cl = headers.get(Headers.CONTENT_LENGTH); + if(te != null && cl != null) { + return false; + } else if(te != null && te.size() > 1) { + return false; + } else if(cl != null && cl.size() > 1) { + return false; + } + return true; + } } diff --git a/core/src/main/java/io/undertow/server/protocol/ajp/AjpReadListener.java b/core/src/main/java/io/undertow/server/protocol/ajp/AjpReadListener.java index 700bec7d24..e1abc15eee 100644 --- a/core/src/main/java/io/undertow/server/protocol/ajp/AjpReadListener.java +++ b/core/src/main/java/io/undertow/server/protocol/ajp/AjpReadListener.java @@ -238,6 +238,10 @@ public void handleEvent(AjpServerResponseConduit channel) { if(connectorStatistics != null) { connectorStatistics.setup(httpServerExchange); } + if(!Connectors.areRequestHeadersValid(httpServerExchange.getRequestHeaders())) { + oldState.badRequest = true; + UndertowLogger.REQUEST_IO_LOGGER.debugf("Invalid AJP request from %s, request contained invalid headers", connection.getPeerAddress()); + } if(oldState.badRequest) { httpServerExchange.setStatusCode(StatusCodes.BAD_REQUEST); diff --git a/core/src/main/java/io/undertow/server/protocol/ajp/AjpRequestParser.java b/core/src/main/java/io/undertow/server/protocol/ajp/AjpRequestParser.java index cf395ce560..15647525f8 100644 --- a/core/src/main/java/io/undertow/server/protocol/ajp/AjpRequestParser.java +++ b/core/src/main/java/io/undertow/server/protocol/ajp/AjpRequestParser.java @@ -55,6 +55,7 @@ import io.undertow.UndertowLogger; import io.undertow.UndertowMessages; import io.undertow.security.impl.ExternalAuthenticationMechanism; +import io.undertow.server.Connectors; import io.undertow.server.HttpServerExchange; import io.undertow.util.Headers; import io.undertow.util.HttpString; @@ -345,6 +346,7 @@ public void parse(final ByteBuffer buf, final AjpRequestParseState state, final state.currentHeader = result.header; } else { state.currentHeader = HttpString.tryFromString(result.value); + Connectors.verifyToken(state.currentHeader); } } StringHolder result = parseString(buf, state, StringType.OTHER); @@ -423,7 +425,9 @@ public void parse(final ByteBuffer buf, final AjpRequestParseState state, final } else if (state.currentAttribute.equals(AUTH_TYPE)) { exchange.putAttachment(ExternalAuthenticationMechanism.EXTERNAL_AUTHENTICATION_TYPE, result); } else if (state.currentAttribute.equals(STORED_METHOD)) { - exchange.setRequestMethod(new HttpString(result)); + HttpString requestMethod = new HttpString(result); + Connectors.verifyToken(requestMethod); + exchange.setRequestMethod(requestMethod); } else if (state.currentAttribute.equals(AJP_REMOTE_PORT)) { state.remotePort = Integer.parseInt(result); } else if (state.currentAttribute.equals(SSL_SESSION)) { diff --git a/core/src/main/java/io/undertow/server/protocol/http/HttpReadListener.java b/core/src/main/java/io/undertow/server/protocol/http/HttpReadListener.java index 58de6ee834..d012a7cfed 100644 --- a/core/src/main/java/io/undertow/server/protocol/http/HttpReadListener.java +++ b/core/src/main/java/io/undertow/server/protocol/http/HttpReadListener.java @@ -241,6 +241,10 @@ public void handleEventWithNoRunningRequest(final ConduitStreamSourceChannel cha return; } } + if(!Connectors.areRequestHeadersValid(httpServerExchange.getRequestHeaders())) { + sendBadRequestAndClose(connection.getChannel(), UndertowMessages.MESSAGES.invalidHeaders()); + return; + } Connectors.executeRootHandler(connection.getRootHandler(), httpServerExchange); } catch (Exception e) { sendBadRequestAndClose(connection.getChannel(), e); diff --git a/core/src/main/java/io/undertow/server/protocol/http/HttpRequestParser.java b/core/src/main/java/io/undertow/server/protocol/http/HttpRequestParser.java index e67a5cd2db..f9ff6c87fa 100644 --- a/core/src/main/java/io/undertow/server/protocol/http/HttpRequestParser.java +++ b/core/src/main/java/io/undertow/server/protocol/http/HttpRequestParser.java @@ -167,6 +167,8 @@ public abstract class HttpRequestParser { private final String charset; private final int maxCachedHeaderSize; + private static final boolean[] ALLOWED_TARGET_CHARACTER = new boolean[256]; + static { try { HTTP = "HTTP/1.".getBytes("ASCII"); @@ -174,6 +176,28 @@ public abstract class HttpRequestParser { } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } + for(int i = 0; i < 256; ++i) { + if(i < 32 || i > 126) { + ALLOWED_TARGET_CHARACTER[i] = false; + } else { + switch ((char)i) { + case '\"': + case '#': + case '<': + case '>': + case '\\': + case '^': + case '`': + case '{': + case '|': + case '}': + ALLOWED_TARGET_CHARACTER[i] = false; + break; + default: + ALLOWED_TARGET_CHARACTER[i] = true; + } + } + } } public HttpRequestParser(OptionMap options) { @@ -348,6 +372,9 @@ final void handlePath(ByteBuffer buffer, ParseState state, HttpServerExchange ex while (buffer.hasRemaining()) { char next = (char) (buffer.get() & 0xFF); + if(!ALLOWED_TARGET_CHARACTER[next]) { + throw new BadRequestException(UndertowMessages.MESSAGES.invalidCharacterInRequestTarget(next)); + } if (next == ' ' || next == '\t') { if (stringBuilder.length() != 0) { final String path = stringBuilder.toString(); diff --git a/core/src/main/java/io/undertow/server/protocol/http2/Http2ReceiveListener.java b/core/src/main/java/io/undertow/server/protocol/http2/Http2ReceiveListener.java index 3982909869..b5a5201d04 100644 --- a/core/src/main/java/io/undertow/server/protocol/http2/Http2ReceiveListener.java +++ b/core/src/main/java/io/undertow/server/protocol/http2/Http2ReceiveListener.java @@ -145,6 +145,11 @@ private void handleRequests(Http2Channel channel, Http2StreamSourceChannel frame exchange.setProtocol(Protocols.HTTP_2_0); exchange.setRequestMethod(Methods.fromString(exchange.getRequestHeaders().getFirst(METHOD))); exchange.getRequestHeaders().put(Headers.HOST, exchange.getRequestHeaders().getFirst(AUTHORITY)); + if(!Connectors.areRequestHeadersValid(exchange.getRequestHeaders())) { + UndertowLogger.REQUEST_IO_LOGGER.debugf("Invalid headers in HTTP/2 request, closing connection. Remote peer %s", connection.getPeerAddress()); + channel.sendGoAway(Http2Channel.ERROR_PROTOCOL_ERROR); + return; + } final String path = exchange.getRequestHeaders().getFirst(PATH); if(path == null || path.isEmpty()) { diff --git a/core/src/main/java/io/undertow/util/Methods.java b/core/src/main/java/io/undertow/util/Methods.java index 678d4ee94a..a0801dd3f0 100644 --- a/core/src/main/java/io/undertow/util/Methods.java +++ b/core/src/main/java/io/undertow/util/Methods.java @@ -22,6 +22,8 @@ import java.util.HashMap; import java.util.Map; +import io.undertow.server.Connectors; + /** * NOTE: If you add a new method here you must also add it to {@link io.undertow.server.protocol.http.HttpRequestParser} * @@ -138,7 +140,9 @@ private static void putString(Map methods, HttpString option public static HttpString fromString(String method) { HttpString res = METHODS.get(method); if(res == null) { - return new HttpString(method); + HttpString httpString = new HttpString(method); + Connectors.verifyToken(httpString); + return httpString; } return res; } diff --git a/core/src/test/java/io/undertow/server/InvalidHtpRequestTestCase.java b/core/src/test/java/io/undertow/server/InvalidHtpRequestTestCase.java new file mode 100644 index 0000000000..4761eeb2c2 --- /dev/null +++ b/core/src/test/java/io/undertow/server/InvalidHtpRequestTestCase.java @@ -0,0 +1,134 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2014 Red Hat, Inc., and individual contributors + * as indicated by the @author tags. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.undertow.server; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; + +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpRequestBase; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import io.undertow.server.handlers.ResponseCodeHandler; +import io.undertow.testutils.DefaultServer; +import io.undertow.testutils.HttpOneOnly; +import io.undertow.testutils.ProxyIgnore; +import io.undertow.testutils.TestHttpClient; +import io.undertow.util.Headers; +import io.undertow.util.StatusCodes; + +/** + * @author Stuart Douglas + */ +@RunWith(DefaultServer.class) +@ProxyIgnore +@HttpOneOnly +public class InvalidHtpRequestTestCase { + + @BeforeClass + public static void setup() { + DefaultServer.setRootHandler(ResponseCodeHandler.HANDLE_200); + } + + @Test + public void testInvalidCharacterInMethod() throws IOException { + final TestHttpClient client = new TestHttpClient(); + try { + HttpRequestBase method = new HttpRequestBase() { + + @Override + public String getMethod() { + return "GET;POST"; + } + + @Override + public URI getURI() { + try { + return new URI(DefaultServer.getDefaultServerURL()); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } + }; + HttpResponse result = client.execute(method); + Assert.assertEquals(StatusCodes.BAD_REQUEST, result.getStatusLine().getStatusCode()); + } finally { + client.getConnectionManager().shutdown(); + } + } + + + @Test + public void testInvalidCharacterInHeader() throws IOException { + final TestHttpClient client = new TestHttpClient(); + try { + HttpRequestBase method = new HttpGet(DefaultServer.getDefaultServerURL()); + method.addHeader("fake;header", "value"); + HttpResponse result = client.execute(method); + Assert.assertEquals(StatusCodes.BAD_REQUEST, result.getStatusLine().getStatusCode()); + } finally { + client.getConnectionManager().shutdown(); + } + } + + @Test + public void testMultipleContentLengths() throws IOException { + final TestHttpClient client = new TestHttpClient(); + try { + HttpRequestBase method = new HttpGet(DefaultServer.getDefaultServerURL()); + method.addHeader(Headers.CONTENT_LENGTH_STRING, "0"); + method.addHeader(Headers.CONTENT_LENGTH_STRING, "10"); + HttpResponse result = client.execute(method); + Assert.assertEquals(StatusCodes.BAD_REQUEST, result.getStatusLine().getStatusCode()); + } finally { + client.getConnectionManager().shutdown(); + } + } + @Test + public void testContentLengthAndTransferEncoding() throws IOException { + final TestHttpClient client = new TestHttpClient(); + try { + HttpRequestBase method = new HttpGet(DefaultServer.getDefaultServerURL()); + method.addHeader(Headers.CONTENT_LENGTH_STRING, "0"); + method.addHeader(Headers.TRANSFER_ENCODING_STRING, "chunked"); + HttpResponse result = client.execute(method); + Assert.assertEquals(StatusCodes.BAD_REQUEST, result.getStatusLine().getStatusCode()); + } finally { + client.getConnectionManager().shutdown(); + } + } + + @Test + public void testMultipleTransferEncoding() throws IOException { + final TestHttpClient client = new TestHttpClient(); + try { + HttpRequestBase method = new HttpGet(DefaultServer.getDefaultServerURL()); + method.addHeader(Headers.TRANSFER_ENCODING_STRING, "chunked"); + method.addHeader(Headers.TRANSFER_ENCODING_STRING, "gzip, chunked"); + HttpResponse result = client.execute(method); + Assert.assertEquals(StatusCodes.BAD_REQUEST, result.getStatusLine().getStatusCode()); + } finally { + client.getConnectionManager().shutdown(); + } + } +} diff --git a/core/src/test/java/io/undertow/server/handlers/form/FormDataParserTestCase.java b/core/src/test/java/io/undertow/server/handlers/form/FormDataParserTestCase.java index 7895187b63..a964bb3c96 100644 --- a/core/src/test/java/io/undertow/server/handlers/form/FormDataParserTestCase.java +++ b/core/src/test/java/io/undertow/server/handlers/form/FormDataParserTestCase.java @@ -22,8 +22,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import io.undertow.server.HttpHandler; import io.undertow.server.HttpServerExchange; @@ -35,6 +37,7 @@ import io.undertow.testutils.TestHttpClient; import io.undertow.util.StatusCodes; import junit.textui.TestRunner; +import org.apache.http.Header; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.entity.UrlEncodedFormEntity; @@ -77,7 +80,7 @@ public void handleRequest(final HttpServerExchange exchange) throws Exception { while (it.hasNext()) { String fd = it.next(); for (FormData.FormValue val : data.get(fd)) { - exchange.getResponseHeaders().add(new HttpString(fd), val.getValue()); + exchange.getResponseHeaders().add(new HttpString("res"), fd + ":" + val.getValue()); } } } @@ -100,7 +103,7 @@ public void handleRequest(final HttpServerExchange exchange) throws Exception { while (it.hasNext()) { String fd = it.next(); for (FormData.FormValue val : data.get(fd)) { - exchange.getResponseHeaders().add(new HttpString(fd), val.getValue()); + exchange.getResponseHeaders().add(new HttpString("res"), fd + ":" + val.getValue()); } } } catch (IOException e) { @@ -144,8 +147,15 @@ private void runTest(final NameValuePair... pairs) throws Exception { } private void checkResult(final List data, final HttpResponse result) { + Map res = new HashMap<>(); + for(Header d : result.getHeaders("res")) { + String[] split = d.getValue().split(":"); + res.put(split[0], split.length == 1 ? "" : split[1]); + } + + for (NameValuePair vp : data) { - Assert.assertEquals(vp.getValue() == null ? "" : vp.getValue(), result.getHeaders(vp.getName())[0].getValue()); + Assert.assertEquals(vp.getValue() == null ? "" : vp.getValue(), res.get(vp.getName())); } } diff --git a/core/src/test/java/io/undertow/server/protocol/http/SimpleParserTestCase.java b/core/src/test/java/io/undertow/server/protocol/http/SimpleParserTestCase.java index 5f055f5191..a80b054c50 100644 --- a/core/src/test/java/io/undertow/server/protocol/http/SimpleParserTestCase.java +++ b/core/src/test/java/io/undertow/server/protocol/http/SimpleParserTestCase.java @@ -167,16 +167,16 @@ public void testLineFeedsLineEnds() throws BadRequestException { runTest(in); } - @Test + @Test(expected = BadRequestException.class) public void testTabWhitespace() throws BadRequestException { byte[] in = "GET\t/somepath\tHTTP/1.1\nHost: \t www.somehost.net\nOtherHeader:\tsome\n \t value\n\r\n".getBytes(); runTest(in); } @Test - public void testCanonicalPath() throws BadRequestException { - byte[] in = "GET\thttp://www.somehost.net/somepath\tHTTP/1.1\nHost: \t www.somehost.net\nOtherHeader:\tsome\n \t value\n\r\n".getBytes(); + public void testCanonicalPath() throws BadRequestException { + byte[] in = "GET http://www.somehost.net/somepath HTTP/1.1\nHost: \t www.somehost.net\nOtherHeader:\tsome\n \t value\n\r\n".getBytes(); final ParseState context = new ParseState(5); HttpServerExchange result = new HttpServerExchange(null); HttpRequestParser.instance(OptionMap.EMPTY).handle(ByteBuffer.wrap(in), context, result); @@ -186,7 +186,7 @@ public void testCanonicalPath() throws BadRequestException { @Test public void testNoHeaders() throws BadRequestException { - byte[] in = "GET\t/aa\tHTTP/1.1\n\n\n".getBytes(); + byte[] in = "GET /aa HTTP/1.1\n\n\n".getBytes(); final ParseState context = new ParseState(0); HttpServerExchange result = new HttpServerExchange(null); @@ -215,7 +215,7 @@ public void testQueryParams() throws BadRequestException { @Test public void testSameHttpStringReturned() throws BadRequestException { - byte[] in = "GET\thttp://www.somehost.net/somepath\tHTTP/1.1\nHost: \t www.somehost.net\nAccept-Charset:\tsome\n \t value\n\r\n".getBytes(); + byte[] in = "GET http://www.somehost.net/somepath HTTP/1.1\nHost: \t www.somehost.net\nAccept-Charset:\tsome\n \t value\n\r\n".getBytes(); final ParseState context1 = new ParseState(10); HttpServerExchange result1 = new HttpServerExchange(null); @@ -259,16 +259,14 @@ public void testEmptyQueryParams() throws BadRequestException { Assert.assertEquals("666", result.getQueryParameters().get("777").getFirst()); Assert.assertEquals("44", result.getQueryParameters().get(";?").getFirst()); } - @Test + + @Test(expected = BadRequestException.class) public void testNonEncodedAsciiCharacters() throws UnsupportedEncodingException, BadRequestException { byte[] in = "GET /bÃ¥r HTTP/1.1\r\n\r\n".getBytes("ISO-8859-1"); final ParseState context = new ParseState(10); HttpServerExchange result = new HttpServerExchange(null); HttpRequestParser.instance(OptionMap.EMPTY).handle(ByteBuffer.wrap(in), context, result); - Assert.assertSame(Methods.GET, result.getRequestMethod()); - Assert.assertEquals("/bår", result.getRequestPath()); - Assert.assertEquals("/bÃ¥r", result.getRequestURI()); //not decoded } private void runTest(final byte[] in) throws BadRequestException { diff --git a/parser-generator/src/main/java/io/undertow/annotationprocessor/RequestParserGenerator.java b/parser-generator/src/main/java/io/undertow/annotationprocessor/RequestParserGenerator.java index 3e13588f84..36c87c8007 100644 --- a/parser-generator/src/main/java/io/undertow/annotationprocessor/RequestParserGenerator.java +++ b/parser-generator/src/main/java/io/undertow/annotationprocessor/RequestParserGenerator.java @@ -32,6 +32,7 @@ public class RequestParserGenerator extends AbstractParserGenerator { public static final String PARSE_STATE_CLASS = "io.undertow.server.protocol.http.ParseState"; public static final String HTTP_EXCHANGE_CLASS = "io.undertow.server.HttpServerExchange"; public static final String HTTP_EXCHANGE_DESCRIPTOR = "Lio/undertow/server/HttpServerExchange;"; + private static final String CONNECTORS_CLASS = "io.undertow.server.Connectors"; //parsing states @@ -66,6 +67,8 @@ public boolean isHeader() { public void handleOtherToken(final CodeAttribute c) { c.aload(PARSE_STATE_VAR); c.swap(); + c.dup(); + c.invokestatic(CONNECTORS_CLASS, "verifyToken", "(" + HTTP_STRING_DESCRIPTOR + ")V"); c.putfield(parseStateClass, "nextHeader", HTTP_STRING_DESCRIPTOR); } @@ -150,6 +153,8 @@ public void handleStateMachineMatchedToken(final CodeAttribute c) { public void handleOtherToken(final CodeAttribute c) { c.aload(HTTP_RESULT); c.swap(); + c.dup(); + c.invokestatic(CONNECTORS_CLASS, "verifyToken", "(" + HTTP_STRING_DESCRIPTOR + ")V"); c.invokevirtual(resultClass, "setRequestMethod", "(" + HTTP_STRING_DESCRIPTOR + ")" + HTTP_EXCHANGE_DESCRIPTOR); c.pop(); } diff --git a/servlet/src/test/java/io/undertow/servlet/test/path/PathFilter.java b/servlet/src/test/java/io/undertow/servlet/test/path/PathFilter.java index b3deb1885a..eb1bce216c 100644 --- a/servlet/src/test/java/io/undertow/servlet/test/path/PathFilter.java +++ b/servlet/src/test/java/io/undertow/servlet/test/path/PathFilter.java @@ -43,7 +43,7 @@ public void init(final FilterConfig filterConfig) throws ServletException { @Override public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException { HttpServletResponse resp = (HttpServletResponse) response; - resp.addHeader("filter" + filterConfig.getFilterName(), filterConfig.getFilterName()); + resp.addHeader("filter" + filterConfig.getFilterName().replace("/", "-"), filterConfig.getFilterName()); chain.doFilter(request, response); }