Skip to content

Commit 82f11fd

Browse files
committed
Merge remote-tracking branch 'origin/jetty-12.0.x' into jetty-12.1.x
# Conflicts: # jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/internal/HttpChannelState.java # jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/FilterMapping.java
2 parents 336eeac + 9b54bfe commit 82f11fd

File tree

11 files changed

+372
-198
lines changed

11 files changed

+372
-198
lines changed

jetty-core/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientFailureTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ public void testPendingRequestContentThenTotalTimeout() throws Exception
175175
completed.incrementAndGet();
176176
assertThat(result.getRequestFailure(), notNullValue());
177177
assertThat(result.getResponseFailure(), nullValue());
178-
assertThat(result.getResponse().getStatus(), is(HttpStatus.OK_200));
178+
assertThat(result.getResponse().getStatus(), is(HttpStatus.INTERNAL_SERVER_ERROR_500));
179179
resultLatch.countDown();
180180
});
181181

jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/internal/HttpChannelState.java

Lines changed: 175 additions & 146 deletions
Large diffs are not rendered by default.

jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/StatisticsHandlerTest.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@
4848
import static org.hamcrest.Matchers.instanceOf;
4949
import static org.hamcrest.Matchers.is;
5050
import static org.hamcrest.Matchers.lessThan;
51-
import static org.hamcrest.Matchers.nullValue;
5251
import static org.hamcrest.Matchers.startsWith;
5352
import static org.junit.jupiter.api.Assertions.assertEquals;
5453
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -360,9 +359,13 @@ public boolean handle(Request request, Response response, Callback callback)
360359
\r
361360
""";
362361

363-
String response = _connector.getResponse(request);
364-
assertThat(response, is(nullValue()));
365-
await().atMost(5, TimeUnit.SECONDS).until(_statsHandler::getResponses5xx, is(1));
362+
try (StacklessLogging ignored = new StacklessLogging(Response.class))
363+
{
364+
String response = _connector.getResponse(request);
365+
assertThat(response, containsString("HTTP/1.1 500 "));
366+
assertThat(response, containsString("content-length 1 != 0 written"));
367+
await().atMost(5, TimeUnit.SECONDS).until(_statsHandler::getResponses5xx, is(1));
368+
}
366369
}
367370

368371
@Test

jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/ExceptionUtil.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,34 @@ public static boolean areNotAssociated(Throwable t1, Throwable t2)
216216
return true;
217217
}
218218

219+
/**
220+
* Checks if a given {@link Throwable} has an association with a specific type of {@link Throwable}.
221+
* The association is determined by whether the provided type matches the throwable or any of its causes
222+
* or suppressed exceptions.
223+
*
224+
* @param failure The {@link Throwable} to check for association. Can be null.
225+
* @param throwable The type of {@link Throwable} class to check association against. Can be null.
226+
* @return true if the {@link Throwable} is associated with the provided type; otherwise, false.
227+
*/
228+
public static boolean hasAssociated(Throwable failure, Class<? extends Throwable> throwable)
229+
{
230+
if (failure == null || throwable == null)
231+
return false;
232+
233+
Throwable cause = failure;
234+
while (cause != null)
235+
{
236+
if (throwable.isInstance(cause))
237+
return true;
238+
cause = cause.getCause();
239+
}
240+
241+
for (Throwable s : failure.getSuppressed())
242+
if (hasAssociated(s, throwable))
243+
return true;
244+
return false;
245+
}
246+
219247
/**
220248
* Add a suppressed exception if it is not associated.
221249
* @see #areNotAssociated(Throwable, Throwable)
@@ -336,6 +364,8 @@ public static Throwable combine(Throwable t1, Throwable t2)
336364
{
337365
if (t1 == null)
338366
return t2;
367+
if (t2 == null)
368+
return t1;
339369
addSuppressedIfNotAssociated(t1, t2);
340370
return t1;
341371
}

jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/FilterMapping.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,14 @@ boolean appliesTo(String path, int type)
138138
*/
139139
boolean appliesTo(int type)
140140
{
141-
FilterHolder holder = _holder;
142-
if (holder == null)
143-
return false;
141+
if (type == ASYNC)
142+
{
143+
FilterHolder holder = _holder;
144+
if (holder == null || !holder.isAsyncSupported())
145+
return false;
146+
}
144147
if (_dispatches == 0)
145-
return type == REQUEST || type == ASYNC && holder.isAsyncSupported();
148+
return type == REQUEST || type == ASYNC;
146149
return (_dispatches & type) != 0;
147150
}
148151

jetty-ee10/jetty-ee10-servlets/src/main/java/org/eclipse/jetty/ee10/servlets/EventSourceServlet.java

Lines changed: 38 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
public abstract class EventSourceServlet extends HttpServlet
5151
{
5252
private static final byte[] CRLF = new byte[]{'\r', '\n'};
53+
private static final byte[] CRLF_CRLF = new byte[]{'\r', '\n', '\r', '\n'};
5354
private static final byte[] EVENT_FIELD = "event: ".getBytes(StandardCharsets.UTF_8);
5455
private static final byte[] DATA_FIELD = "data: ".getBytes(StandardCharsets.UTF_8);
5556
private static final byte[] COMMENT_FIELD = ": ".getBytes(StandardCharsets.UTF_8);
@@ -76,7 +77,6 @@ public void destroy()
7677
@Override
7778
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
7879
{
79-
@SuppressWarnings("unchecked")
8080
Enumeration<String> acceptValues = request.getHeaders("Accept");
8181
while (acceptValues.hasMoreElements())
8282
{
@@ -92,11 +92,11 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) t
9292
{
9393
respond(request, response);
9494
AsyncContext async = request.startAsync();
95-
// Infinite timeout because the continuation is never resumed,
95+
// Infinite timeout because the continuation is never resumed
9696
// but only completed on close
9797
async.setTimeout(0);
9898
EventSourceEmitter emitter = new EventSourceEmitter(eventSource, async);
99-
emitter.scheduleHeartBeat();
99+
emitter.heartBeat = scheduler.schedule(emitter, heartBeatPeriod, TimeUnit.SECONDS);
100100
open(eventSource, emitter);
101101
}
102102
return;
@@ -145,10 +145,12 @@ public void event(String name, String data) throws IOException
145145
{
146146
try (AutoLock l = lock.lock())
147147
{
148+
if (closed)
149+
throw new IOException("closed");
148150
output.write(EVENT_FIELD);
149151
output.write(name.getBytes(StandardCharsets.UTF_8));
150152
output.write(CRLF);
151-
data(data);
153+
lockedData(data);
152154
}
153155
}
154156

@@ -157,28 +159,38 @@ public void data(String data) throws IOException
157159
{
158160
try (AutoLock l = lock.lock())
159161
{
160-
BufferedReader reader = new BufferedReader(new StringReader(data));
161-
String line;
162-
while ((line = reader.readLine()) != null)
163-
{
164-
output.write(DATA_FIELD);
165-
output.write(line.getBytes(StandardCharsets.UTF_8));
166-
output.write(CRLF);
167-
}
162+
if (closed)
163+
throw new IOException("closed");
164+
lockedData(data);
165+
}
166+
}
167+
168+
private void lockedData(String data) throws IOException
169+
{
170+
assert lock.isHeldByCurrentThread();
171+
172+
BufferedReader reader = new BufferedReader(new StringReader(data));
173+
String line;
174+
while ((line = reader.readLine()) != null)
175+
{
176+
output.write(DATA_FIELD);
177+
output.write(line.getBytes(StandardCharsets.UTF_8));
168178
output.write(CRLF);
169-
flush();
170179
}
180+
output.write(CRLF);
181+
flush();
171182
}
172183

173184
@Override
174185
public void comment(String comment) throws IOException
175186
{
176187
try (AutoLock l = lock.lock())
177188
{
189+
if (closed)
190+
throw new IOException("closed");
178191
output.write(COMMENT_FIELD);
179192
output.write(comment.getBytes(StandardCharsets.UTF_8));
180-
output.write(CRLF);
181-
output.write(CRLF);
193+
output.write(CRLF_CRLF);
182194
flush();
183195
}
184196
}
@@ -189,17 +201,17 @@ public void run()
189201
// If the other peer closes the connection, the first
190202
// flush() should generate a TCP reset that is detected
191203
// on the second flush()
192-
try
204+
try (AutoLock l = lock.lock())
193205
{
194-
try (AutoLock l = lock.lock())
195-
{
196-
output.write('\r');
197-
flush();
198-
output.write('\n');
199-
flush();
200-
}
206+
if (closed)
207+
return;
208+
output.write('\r');
209+
flush();
210+
output.write('\n');
211+
flush();
212+
201213
// We could write, reschedule heartbeat
202-
scheduleHeartBeat();
214+
heartBeat = scheduler.schedule(this, heartBeatPeriod, TimeUnit.SECONDS);
203215
}
204216
catch (Throwable x)
205217
{
@@ -228,19 +240,12 @@ public void close()
228240
{
229241
try (AutoLock l = lock.lock())
230242
{
243+
if (closed)
244+
return;
231245
closed = true;
232246
heartBeat.cancel(false);
233247
}
234248
async.complete();
235249
}
236-
237-
private void scheduleHeartBeat()
238-
{
239-
try (AutoLock l = lock.lock())
240-
{
241-
if (!closed)
242-
heartBeat = scheduler.schedule(this, heartBeatPeriod, TimeUnit.SECONDS);
243-
}
244-
}
245250
}
246251
}

jetty-ee10/jetty-ee10-tests/jetty-ee10-test-quickstart/src/test/java/org/eclipse/jetty/ee10/quickstart/QuickStartTest.java

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.junit.jupiter.params.provider.ValueSource;
3939

4040
import static org.hamcrest.MatcherAssert.assertThat;
41+
import static org.hamcrest.Matchers.containsString;
4142
import static org.junit.jupiter.api.Assertions.assertEquals;
4243
import static org.junit.jupiter.api.Assertions.assertNotNull;
4344
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -80,7 +81,7 @@ public void testExplodedWebAppDirNoWebXml(boolean defaultMode) throws Exception
8081
URL url = new URL("http://127.0.0.1:" + server.getBean(NetworkConnector.class).getLocalPort() + "/index.html");
8182
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
8283
assertEquals(200, connection.getResponseCode());
83-
assertThat(IO.toString((InputStream)connection.getContent()), Matchers.containsString("<p>Contents of no-web-xml</p>"));
84+
assertThat(IO.toString((InputStream)connection.getContent()), containsString("<p>Contents of no-web-xml</p>"));
8485

8586
server.stop();
8687
}
@@ -132,7 +133,7 @@ public void testStandardTestWar() throws Exception
132133
URL url = new URL("http://127.0.0.1:" + server.getBean(NetworkConnector.class).getLocalPort() + "/test/dump/info");
133134
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
134135
assertEquals(200, connection.getResponseCode());
135-
assertThat(IO.toString((InputStream)connection.getContent()), Matchers.containsString("Dump Servlet"));
136+
assertThat(IO.toString((InputStream)connection.getContent()), containsString("Dump Servlet"));
136137

137138
server.stop();
138139
}
@@ -188,7 +189,7 @@ public void testSpecWar() throws Exception
188189
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
189190
assertEquals(200, connection.getResponseCode());
190191
String content = IO.toString((InputStream)connection.getContent());
191-
assertThat(content, Matchers.containsString("Welcome to a Fragment"));
192+
assertThat(content, containsString("Welcome to a Fragment"));
192193

193194
//test annotations etc
194195
url = new URL("http://127.0.0.1:" + server.getBean(NetworkConnector.class).getLocalPort() + "/test/");
@@ -197,8 +198,8 @@ public void testSpecWar() throws Exception
197198

198199
assertEquals(200, connection.getResponseCode());
199200
content = IO.toString((InputStream)connection.getContent());
200-
assertThat(content, Matchers.containsString("Results"));
201-
assertThat(content, Matchers.not(Matchers.containsString("FAIL")));
201+
assertThat(content, containsString("Results"));
202+
assertThat(content, Matchers.not(containsString("FAIL")));
202203
server.stop();
203204
}
204205

@@ -252,8 +253,43 @@ public void testJNDIWar() throws Exception
252253
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
253254
String content = IO.toString((InputStream)connection.getContent());
254255
assertEquals(200, connection.getResponseCode());
255-
assertThat(content, Matchers.containsString("JNDI Demo WebApp"));
256+
assertThat(content, containsString("JNDI Demo WebApp"));
256257

257258
server.stop();
258259
}
260+
261+
@Test
262+
public void testFilterMappings() throws Exception
263+
{
264+
Path workdir = MavenPaths.targetTestDir(PreconfigureSpecWar.class.getSimpleName());
265+
FS.ensureEmpty(workdir);
266+
Path target = workdir.resolve("test-filter-mappings");
267+
FS.ensureEmpty(target);
268+
FS.ensureDirExists(target.resolve("WEB-INF"));
269+
270+
Path sourceWebXml = MavenPaths.findTestResourceFile("filter-web.xml");
271+
Files.copy(sourceWebXml, target.resolve("WEB-INF/web.xml"));
272+
System.setProperty("jetty.home", target.toString());
273+
274+
PreconfigureQuickStartWar.main(target.toString());
275+
276+
Path quickStartXml = target.resolve("WEB-INF/quickstart-web.xml");
277+
String quickStartContents = Files.readString(quickStartXml);
278+
assertThat(quickStartContents, containsString("""
279+
<filter>
280+
<filter-name>CustomFilter</filter-name>
281+
<filter-class>org.example.CustomFilter</filter-class>
282+
<async-supported>false</async-supported>
283+
</filter>
284+
<filter-mapping>
285+
<filter-name>CustomFilter</filter-name>
286+
<url-pattern>/foo/*</url-pattern>
287+
<dispatcher>REQUEST</dispatcher>
288+
<dispatcher>ERROR</dispatcher>
289+
<dispatcher>FORWARD</dispatcher>
290+
<dispatcher>INCLUDE</dispatcher>
291+
</filter-mapping>
292+
"""));
293+
}
294+
259295
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<web-app
3+
xmlns="https://jakarta.ee/xml/ns/jakartaee"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
6+
version="6.0"> <filter>
7+
<filter-name>CustomFilter</filter-name>
8+
<filter-class>org.example.CustomFilter</filter-class>
9+
</filter>
10+
<filter-mapping>
11+
<filter-name>CustomFilter</filter-name>
12+
<url-pattern>/foo/*</url-pattern>
13+
<dispatcher>REQUEST</dispatcher>
14+
<dispatcher>FORWARD</dispatcher>
15+
<dispatcher>INCLUDE</dispatcher>
16+
<dispatcher>ERROR</dispatcher>
17+
</filter-mapping>
18+
</web-app>

jetty-ee9/jetty-ee9-servlet/src/main/java/org/eclipse/jetty/ee9/servlet/FilterMapping.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,6 @@ boolean appliesTo(String path, int type)
151151
*/
152152
boolean appliesTo(int type)
153153
{
154-
FilterHolder holder = _holder;
155-
if (_holder == null)
156-
return false;
157154
if (_dispatches == 0)
158155
return type == REQUEST || type == ASYNC && (_holder != null && _holder.isAsyncSupported());
159156
return (_dispatches & type) != 0;

0 commit comments

Comments
 (0)