Skip to content

Commit 2b6c7e5

Browse files
authored
Merge pull request #1650 from fl4via/backport_2.3.x
[UNDERTOW-2417][UNDERTOW-2256][UNDERTOW-2381] Backport fixes to 2.3.x
2 parents fd6f4f9 + 9d10d49 commit 2b6c7e5

File tree

5 files changed

+189
-21
lines changed

5 files changed

+189
-21
lines changed

core/src/main/java/io/undertow/protocols/http2/HPackHuffman.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,10 @@ public static void decode(ByteBuffer data, int length, StringBuilder target) thr
397397
eosCount = 0;
398398
}
399399
} else {
400+
// we need to check for EOS symbol in the string literal
401+
if (((val >> 16) & LOW_MASK) == 256) {
402+
throw UndertowMessages.MESSAGES.hpackFailed();
403+
}
400404
//bit not set, we want the lower part of the tree
401405
if ((val & HIGH_TERMINAL_BIT) == 0) {
402406
treePos = (val >> 16) & LOW_MASK;

core/src/main/java/io/undertow/server/handlers/resource/DirectoryUtils.java

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,29 @@ public static StringBuilder renderDirectoryListing(final HttpServerExchange exch
108108
if (!path.endsWith("/")){
109109
path += "/";
110110
}
111+
112+
String relative = null;
113+
if (exchange != null) {
114+
final Map<String, Object> context = exchange.getAttachment(Predicate.PREDICATE_CONTEXT);
115+
if (context != null) {
116+
final PathPrefixPredicate.PathPrefixMatchRecord trans = (PathPrefixMatchRecord) context
117+
.get(PathPrefixPredicate.PREFIX_MATCH_RECORD);
118+
if (trans != null) {
119+
if (trans.isOverWritten()) {
120+
relative = trans.getPrefix();
121+
if (!relative.endsWith("/") && !path.startsWith("/")) {
122+
relative += "/";
123+
}
124+
}
125+
}
126+
}
127+
}
128+
111129
StringBuilder builder = new StringBuilder();
112-
builder.append("<html>\n<head>\n<script src='").append(path).append("?js'></script>\n")
113-
.append("<link rel='stylesheet' type='text/css' href='").append(path).append("?css' />\n</head>\n");
130+
builder.append("<html>\n<head>\n<script src='").append(relative == null ? path : relative + path).append("?js'></script>\n")
131+
.append("<link rel='stylesheet' type='text/css' href='").append(relative == null ? path : relative + path).append("?css' />\n</head>\n");
114132
builder.append("<body onresize='growit()' onload='growit()'>\n<table id='thetable'>\n<thead>\n");
115-
builder.append("<tr><th class='loc' colspan='3'>Directory Listing - ").append(path).append("</th></tr>\n")
133+
builder.append("<tr><th class='loc' colspan='3'>Directory Listing - ").append(relative == null ? path : relative + path).append("</th></tr>\n")
116134
.append("<tr><th class='label offset'>Name</th><th class='label'>Last Modified</th><th class='label'>Size</th></tr>\n</thead>\n")
117135
.append("<tfoot>\n<tr><th class=\"loc footer\" colspan=\"3\">Powered by Undertow</th></tr>\n</tfoot>\n<tbody>\n");
118136

@@ -137,23 +155,6 @@ public static StringBuilder renderDirectoryListing(final HttpServerExchange exch
137155
}
138156
}
139157

140-
String relative = null;
141-
if (exchange != null) {
142-
final Map<String, Object> context = exchange.getAttachment(Predicate.PREDICATE_CONTEXT);
143-
if (context != null) {
144-
final PathPrefixPredicate.PathPrefixMatchRecord trans = (PathPrefixMatchRecord) context
145-
.get(PathPrefixPredicate.PREFIX_MATCH_RECORD);
146-
if (trans != null) {
147-
if (trans.isOverWritten()) {
148-
relative = trans.getPrefix();
149-
if (!relative.endsWith("/") && !path.startsWith("/")) {
150-
relative += "/";
151-
}
152-
}
153-
}
154-
}
155-
}
156-
157158
SimpleDateFormat format = new SimpleDateFormat("MMM dd, yyyy HH:mm:ss", Locale.US);
158159
int i = 0;
159160
if (parent != null) {
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* JBoss, Home of Professional Open Source.
3+
* Copyright 2014 Red Hat, Inc., and individual contributors
4+
* as indicated by the @author tags.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package io.undertow.protocols.http2;
20+
21+
22+
import io.undertow.testutils.category.UnitTest;
23+
import org.junit.Assert;
24+
import org.junit.Test;
25+
import org.junit.experimental.categories.Category;
26+
27+
import java.nio.ByteBuffer;
28+
29+
30+
31+
32+
/**
33+
* @author Marek Jusko
34+
*/
35+
@Category(UnitTest.class)
36+
public class HpackHuffmanDecodingStringLiteralRepresentation {
37+
38+
/**
39+
* Sends a Huffman-encoded string literal representation containing the EOS symbol.
40+
* <p>
41+
* Requirement: The endpoint MUST treat this as a decoding error.
42+
*/
43+
@Test
44+
public void testStringLiteralContainingEOS() throws HpackException {
45+
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};
46+
HpackDecoder decoder = new HpackDecoder(256);
47+
48+
Assert.assertThrows(HpackException.class, () -> decoder.decode(ByteBuffer.wrap(data), false));
49+
}
50+
51+
/**
52+
* Sends a Huffman-encoded string literal representation with padding longer than 7 bits.
53+
* <p>
54+
* Requirement: The endpoint MUST treat this as a decoding error.
55+
*/
56+
@Test
57+
public void testStringLiteralPaddingLongerThan7Bits() throws HpackException {
58+
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};
59+
HpackDecoder decoder = new HpackDecoder(256);
60+
61+
Assert.assertThrows(HpackException.class, () -> decoder.decode(ByteBuffer.wrap(data), false));
62+
}
63+
64+
/**
65+
* Sends a Huffman-encoded string literal representation padded by zero.
66+
* <p>
67+
* Requirement: The endpoint MUST treat this as a decoding error.
68+
*/
69+
@Test
70+
public void testStringLiteralPaddedByZero() throws HpackException {
71+
byte[] data = new byte[]{0x00, (byte) 0x85, (byte) 0xf2, (byte) 0xb2, 0x4a, (byte) 0x84, (byte) 0xff, (byte) 0x83, 0x49, (byte) 0x50, (byte) 0x90};
72+
HpackDecoder decoder = new HpackDecoder(256);
73+
74+
Assert.assertThrows(HpackException.class, () -> decoder.decode(ByteBuffer.wrap(data), false));
75+
}
76+
77+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* JBoss, Home of Professional Open Source.
3+
* Copyright 2024 Red Hat, Inc., and individual contributors
4+
* as indicated by the @author tags.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
package io.undertow.server.handlers.file;
19+
20+
import io.undertow.predicate.PredicatesHandler;
21+
import io.undertow.server.handlers.ResponseCodeHandler;
22+
import io.undertow.server.handlers.builder.PredicatedHandler;
23+
import io.undertow.server.handlers.builder.PredicatedHandlersParser;
24+
import io.undertow.server.handlers.resource.DirectoryUtils;
25+
import io.undertow.testutils.DefaultServer;
26+
import io.undertow.testutils.TestHttpClient;
27+
import org.apache.http.HttpEntity;
28+
import org.apache.http.client.methods.HttpGet;
29+
import org.apache.http.util.EntityUtils;
30+
import org.junit.Assert;
31+
import org.junit.Test;
32+
import org.junit.runner.RunWith;
33+
34+
import java.io.IOException;
35+
import java.net.URISyntaxException;
36+
import java.nio.file.Path;
37+
import java.nio.file.Paths;
38+
import java.util.List;
39+
40+
@RunWith(DefaultServer.class)
41+
public class FileHandlerWithPredicateTestCase {
42+
@Test
43+
public void testIfHandlerReturnsResourcesWhenItIsInPredicate() throws IOException, URISyntaxException {
44+
TestHttpClient client = new TestHttpClient();
45+
Path rootPath = Paths.get(getClass().getResource("page.html").toURI()).getParent();
46+
try {
47+
List<PredicatedHandler> predicatedHandlers = PredicatedHandlersParser.parse("path-prefix(/subdir)-> { set(attribute=%U,value=${remaining}); resource(location='"+ rootPath +"',allow-listing=true) }", FileHandlerWithPredicateTestCase.class.getClassLoader());
48+
PredicatesHandler predicatesHandler = new PredicatesHandler(new ResponseCodeHandler(200));
49+
for (PredicatedHandler handler : predicatedHandlers) {
50+
predicatesHandler.addPredicatedHandler(handler);
51+
}
52+
DefaultServer.setRootHandler(predicatesHandler);
53+
54+
//Make sure that we receive a body with the js needed to render the page.
55+
CheckResponse(client, "/subdir/?js", true, false);
56+
57+
//Same for css
58+
CheckResponse(client, "/subdir/?css", false, false);
59+
60+
//Make sure that we receive a body with the js needed to render the page.
61+
CheckResponse(client, "/?js", true, true);
62+
63+
//Same for css
64+
CheckResponse(client, "/?css", false, true);
65+
66+
} finally {
67+
client.getConnectionManager().shutdown();
68+
}
69+
}
70+
71+
private void CheckResponse(TestHttpClient client, String path, Boolean isJs, Boolean emptyResponseExpected) throws IOException {
72+
//Make sure that we receive a body with the js needed to render the page.
73+
HttpGet get = new HttpGet(DefaultServer.getDefaultServerURL() + path);
74+
HttpEntity result = client.execute(get).getEntity();
75+
76+
if (emptyResponseExpected){
77+
Assert.assertEquals("The response is not empty", "", EntityUtils.toString(result));
78+
} else {
79+
if (isJs){
80+
Assert.assertEquals("The returned js code is different or empty", DirectoryUtils.Blobs.FILE_JS, EntityUtils.toString(result));
81+
} else {
82+
Assert.assertEquals("The returned css code is different or empty", DirectoryUtils.Blobs.FILE_CSS, EntityUtils.toString(result));
83+
}
84+
}
85+
}
86+
}

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@
193193
</compilerArgs>
194194
<!-- need to specify directly, for some reason properties are ignored -->
195195
<showDeprecation>${maven.compiler.showDeprecation}</showDeprecation>
196-
<showWarnings>${maven.compilie${maven.compiler.showWarnings}</showWarnings>
196+
<showWarnings>${maven.compiler.showWarnings}</showWarnings>
197197
</configuration>
198198
</plugin>
199199

0 commit comments

Comments
 (0)