diff --git a/core/src/main/java/io/undertow/protocols/http2/HPackHuffman.java b/core/src/main/java/io/undertow/protocols/http2/HPackHuffman.java index 60f6fd1395..4d8e2db6db 100644 --- a/core/src/main/java/io/undertow/protocols/http2/HPackHuffman.java +++ b/core/src/main/java/io/undertow/protocols/http2/HPackHuffman.java @@ -397,6 +397,10 @@ public static void decode(ByteBuffer data, int length, StringBuilder target) thr eosCount = 0; } } else { + // we need to check for EOS symbol in the string literal + if (((val >> 16) & LOW_MASK) == 256) { + throw UndertowMessages.MESSAGES.hpackFailed(); + } //bit not set, we want the lower part of the tree if ((val & HIGH_TERMINAL_BIT) == 0) { treePos = (val >> 16) & LOW_MASK; diff --git a/core/src/main/java/io/undertow/server/handlers/resource/DirectoryUtils.java b/core/src/main/java/io/undertow/server/handlers/resource/DirectoryUtils.java index 50d20523a0..65f8936683 100644 --- a/core/src/main/java/io/undertow/server/handlers/resource/DirectoryUtils.java +++ b/core/src/main/java/io/undertow/server/handlers/resource/DirectoryUtils.java @@ -108,11 +108,29 @@ public static StringBuilder renderDirectoryListing(final HttpServerExchange exch if (!path.endsWith("/")){ path += "/"; } + + String relative = null; + if (exchange != null) { + final Map context = exchange.getAttachment(Predicate.PREDICATE_CONTEXT); + if (context != null) { + final PathPrefixPredicate.PathPrefixMatchRecord trans = (PathPrefixMatchRecord) context + .get(PathPrefixPredicate.PREFIX_MATCH_RECORD); + if (trans != null) { + if (trans.isOverWritten()) { + relative = trans.getPrefix(); + if (!relative.endsWith("/") && !path.startsWith("/")) { + relative += "/"; + } + } + } + } + } + StringBuilder builder = new StringBuilder(); - builder.append("\n\n\n") - .append("\n\n"); + builder.append("\n\n\n") + .append("\n\n"); builder.append("\n\n\n"); - builder.append("\n") + builder.append("\n") .append("\n\n") .append("\n\n\n\n"); @@ -137,23 +155,6 @@ public static StringBuilder renderDirectoryListing(final HttpServerExchange exch } } - String relative = null; - if (exchange != null) { - final Map context = exchange.getAttachment(Predicate.PREDICATE_CONTEXT); - if (context != null) { - final PathPrefixPredicate.PathPrefixMatchRecord trans = (PathPrefixMatchRecord) context - .get(PathPrefixPredicate.PREFIX_MATCH_RECORD); - if (trans != null) { - if (trans.isOverWritten()) { - relative = trans.getPrefix(); - if (!relative.endsWith("/") && !path.startsWith("/")) { - relative += "/"; - } - } - } - } - } - SimpleDateFormat format = new SimpleDateFormat("MMM dd, yyyy HH:mm:ss", Locale.US); int i = 0; if (parent != null) { diff --git a/core/src/test/java/io/undertow/protocols/http2/HpackHuffmanDecodingStringLiteralRepresentation.java b/core/src/test/java/io/undertow/protocols/http2/HpackHuffmanDecodingStringLiteralRepresentation.java new file mode 100644 index 0000000000..c9897396d6 --- /dev/null +++ b/core/src/test/java/io/undertow/protocols/http2/HpackHuffmanDecodingStringLiteralRepresentation.java @@ -0,0 +1,77 @@ +/* + * 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.protocols.http2; + + +import io.undertow.testutils.category.UnitTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import java.nio.ByteBuffer; + + + + +/** + * @author Marek Jusko + */ +@Category(UnitTest.class) +public class HpackHuffmanDecodingStringLiteralRepresentation { + + /** + * Sends a Huffman-encoded string literal representation containing the EOS symbol. + *

+ * Requirement: The endpoint MUST treat this as a decoding error. + */ + @Test + public void testStringLiteralContainingEOS() throws HpackException { + byte[] data = new byte[]{0x00, (byte) 0x85, (byte) 0xf2, (byte) 0xb2, 0x4a, (byte) 0x84, (byte) 0xff, (byte) 0x87, 0x49, (byte) 0x51, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xfa, 0x7f}; + HpackDecoder decoder = new HpackDecoder(256); + + Assert.assertThrows(HpackException.class, () -> decoder.decode(ByteBuffer.wrap(data), false)); + } + + /** + * Sends a Huffman-encoded string literal representation with padding longer than 7 bits. + *

+ * Requirement: The endpoint MUST treat this as a decoding error. + */ + @Test + public void testStringLiteralPaddingLongerThan7Bits() throws HpackException { + byte[] data = new byte[]{0x00, (byte) 0x85, (byte) 0xf2, (byte) 0xb2, 0x4a, (byte) 0x84, (byte) 0xff, (byte) 0x84, 0x49, (byte) 0x50, (byte) 0x9f, (byte) 0xff}; + HpackDecoder decoder = new HpackDecoder(256); + + Assert.assertThrows(HpackException.class, () -> decoder.decode(ByteBuffer.wrap(data), false)); + } + + /** + * Sends a Huffman-encoded string literal representation padded by zero. + *

+ * Requirement: The endpoint MUST treat this as a decoding error. + */ + @Test + public void testStringLiteralPaddedByZero() throws HpackException { + byte[] data = new byte[]{0x00, (byte) 0x85, (byte) 0xf2, (byte) 0xb2, 0x4a, (byte) 0x84, (byte) 0xff, (byte) 0x83, 0x49, (byte) 0x50, (byte) 0x90}; + HpackDecoder decoder = new HpackDecoder(256); + + Assert.assertThrows(HpackException.class, () -> decoder.decode(ByteBuffer.wrap(data), false)); + } + +} diff --git a/core/src/test/java/io/undertow/server/handlers/file/FileHandlerWithPredicateTestCase.java b/core/src/test/java/io/undertow/server/handlers/file/FileHandlerWithPredicateTestCase.java new file mode 100644 index 0000000000..b580a503b6 --- /dev/null +++ b/core/src/test/java/io/undertow/server/handlers/file/FileHandlerWithPredicateTestCase.java @@ -0,0 +1,86 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2024 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.handlers.file; + +import io.undertow.predicate.PredicatesHandler; +import io.undertow.server.handlers.ResponseCodeHandler; +import io.undertow.server.handlers.builder.PredicatedHandler; +import io.undertow.server.handlers.builder.PredicatedHandlersParser; +import io.undertow.server.handlers.resource.DirectoryUtils; +import io.undertow.testutils.DefaultServer; +import io.undertow.testutils.TestHttpClient; +import org.apache.http.HttpEntity; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.util.EntityUtils; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; + +@RunWith(DefaultServer.class) +public class FileHandlerWithPredicateTestCase { + @Test + public void testIfHandlerReturnsResourcesWhenItIsInPredicate() throws IOException, URISyntaxException { + TestHttpClient client = new TestHttpClient(); + Path rootPath = Paths.get(getClass().getResource("page.html").toURI()).getParent(); + try { + List predicatedHandlers = PredicatedHandlersParser.parse("path-prefix(/subdir)-> { set(attribute=%U,value=${remaining}); resource(location='"+ rootPath +"',allow-listing=true) }", FileHandlerWithPredicateTestCase.class.getClassLoader()); + PredicatesHandler predicatesHandler = new PredicatesHandler(new ResponseCodeHandler(200)); + for (PredicatedHandler handler : predicatedHandlers) { + predicatesHandler.addPredicatedHandler(handler); + } + DefaultServer.setRootHandler(predicatesHandler); + + //Make sure that we receive a body with the js needed to render the page. + CheckResponse(client, "/subdir/?js", true, false); + + //Same for css + CheckResponse(client, "/subdir/?css", false, false); + + //Make sure that we receive a body with the js needed to render the page. + CheckResponse(client, "/?js", true, true); + + //Same for css + CheckResponse(client, "/?css", false, true); + + } finally { + client.getConnectionManager().shutdown(); + } + } + + private void CheckResponse(TestHttpClient client, String path, Boolean isJs, Boolean emptyResponseExpected) throws IOException { + //Make sure that we receive a body with the js needed to render the page. + HttpGet get = new HttpGet(DefaultServer.getDefaultServerURL() + path); + HttpEntity result = client.execute(get).getEntity(); + + if (emptyResponseExpected){ + Assert.assertEquals("The response is not empty", "", EntityUtils.toString(result)); + } else { + if (isJs){ + Assert.assertEquals("The returned js code is different or empty", DirectoryUtils.Blobs.FILE_JS, EntityUtils.toString(result)); + } else { + Assert.assertEquals("The returned css code is different or empty", DirectoryUtils.Blobs.FILE_CSS, EntityUtils.toString(result)); + } + } + } +}

Directory Listing - ").append(path).append("
Directory Listing - ").append(relative == null ? path : relative + path).append("
NameLast ModifiedSize
Powered by Undertow