Skip to content
This repository was archived by the owner on May 28, 2018. It is now read-only.

Commit c8baeb5

Browse files
Michal GajdosGerrit Code Review
authored andcommitted
Merge "JERSEY-2730: Servlet container processing threads get stuck when unmapped or null exception is registered in async response. To reproduce the problem use org.glassfish.jersey.containers:jersey-container-servlet-core:2.17 and 3 tests out of 4 will fail. Various tests added (including one that tests 404 which makes the ServletContainer.filter() enter the 'webComponent.forwardOn404 && !response.isCommitted() && statusValue.get() == 404' true path). Tested on newest development Glassfish, Weblogic 12.2.1.0.0 and production Jetty 8,9."
2 parents 5ab7483 + 0cafc45 commit c8baeb5

File tree

11 files changed

+677
-2
lines changed

11 files changed

+677
-2
lines changed

containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/ServletContainer.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -545,11 +545,17 @@ private void doFilter(final HttpServletRequest request, final HttpServletRespons
545545
return;
546546
}
547547

548-
final int status = service(baseUri, requestUri, request, response).get();
548+
final Value<Integer> statusValue = service(baseUri, requestUri, request, response);
549549

550550
// If forwarding is configured and response is a 404 with no entity
551551
// body then call the next filter in the chain
552-
if (webComponent.forwardOn404 && status == 404 && !response.isCommitted()) {
552+
553+
if (webComponent.forwardOn404 && !response.isCommitted()
554+
// TODO when switched to servlet-api-3.0 and higher, use response.getStatus() to retrieve the status
555+
// statusValue.get() forwards the call to
556+
// org.glassfish.jersey.servlet.internal.ResponseWriter#getResponseContext() which may block the thread
557+
// as a consequence, we must call it only if we're sure it will not block unintentionally
558+
&& statusValue.get() == 404) {
553559
// lets clear the response to OK before we forward to the next in the chain
554560
// as OK is the default set by servlet containers before filters/servlets do any wor
555561
// so lets hide our footsteps and pretend we were never in the chain at all and let the
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
4+
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
5+
6+
Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved.
7+
8+
The contents of this file are subject to the terms of either the GNU
9+
General Public License Version 2 only ("GPL") or the Common Development
10+
and Distribution License("CDDL") (collectively, the "License"). You
11+
may not use this file except in compliance with the License. You can
12+
obtain a copy of the License at
13+
http://glassfish.java.net/public/CDDL+GPL_1_1.html
14+
or packager/legal/LICENSE.txt. See the License for the specific
15+
language governing permissions and limitations under the License.
16+
17+
When distributing the software, include this License Header Notice in each
18+
file and include the License file at packager/legal/LICENSE.txt.
19+
20+
GPL Classpath Exception:
21+
Oracle designates this particular file as subject to the "Classpath"
22+
exception as provided by Oracle in the GPL Version 2 section of the License
23+
file that accompanied this code.
24+
25+
Modifications:
26+
If applicable, add the following below the License Header, with the fields
27+
enclosed by brackets [] replaced by your own identifying information:
28+
"Portions Copyright [year] [name of copyright owner]"
29+
30+
Contributor(s):
31+
If you wish your version of this file to be governed by only the CDDL or
32+
only the GPL Version 2, indicate your decision by adding "[Contributor]
33+
elects to include this software in this distribution under the [CDDL or GPL
34+
Version 2] license." If you don't indicate a single choice of license, a
35+
recipient has the option to distribute your version of this file under
36+
either the CDDL, the GPL Version 2 or to extend the choice of license to
37+
its licensees as provided above. However, if you add GPL Version 2 code
38+
and therefore, elected the GPL Version 2 license, then the option applies
39+
only if the new code is made subject to such option by the copyright
40+
holder.
41+
42+
-->
43+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
44+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
45+
<modelVersion>4.0.0</modelVersion>
46+
47+
<parent>
48+
<groupId>org.glassfish.jersey.tests.integration</groupId>
49+
<artifactId>project</artifactId>
50+
<version>2.18-SNAPSHOT</version>
51+
</parent>
52+
53+
<artifactId>jersey-2730</artifactId>
54+
<packaging>war</packaging>
55+
<name>jersey-tests-integration-jersey-2730</name>
56+
57+
<description>
58+
This web project reproduces ticket JERSEY-2730
59+
</description>
60+
61+
<dependencies>
62+
<dependency>
63+
<groupId>org.glassfish.jersey.containers</groupId>
64+
<artifactId>jersey-container-servlet</artifactId>
65+
</dependency>
66+
<dependency>
67+
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
68+
<artifactId>jersey-test-framework-provider-external</artifactId>
69+
<scope>test</scope>
70+
</dependency>
71+
</dependencies>
72+
73+
<build>
74+
<plugins>
75+
<plugin>
76+
<groupId>org.apache.maven.plugins</groupId>
77+
<artifactId>maven-compiler-plugin</artifactId>
78+
</plugin>
79+
<plugin>
80+
<groupId>org.apache.maven.plugins</groupId>
81+
<artifactId>maven-failsafe-plugin</artifactId>
82+
</plugin>
83+
<plugin>
84+
<groupId>org.mortbay.jetty</groupId>
85+
<artifactId>jetty-maven-plugin</artifactId>
86+
</plugin>
87+
</plugins>
88+
</build>
89+
90+
</project>
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3+
*
4+
* Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved.
5+
*
6+
* The contents of this file are subject to the terms of either the GNU
7+
* General Public License Version 2 only ("GPL") or the Common Development
8+
* and Distribution License("CDDL") (collectively, the "License"). You
9+
* may not use this file except in compliance with the License. You can
10+
* obtain a copy of the License at
11+
* http://glassfish.java.net/public/CDDL+GPL_1_1.html
12+
* or packager/legal/LICENSE.txt. See the License for the specific
13+
* language governing permissions and limitations under the License.
14+
*
15+
* When distributing the software, include this License Header Notice in each
16+
* file and include the License file at packager/legal/LICENSE.txt.
17+
*
18+
* GPL Classpath Exception:
19+
* Oracle designates this particular file as subject to the "Classpath"
20+
* exception as provided by Oracle in the GPL Version 2 section of the License
21+
* file that accompanied this code.
22+
*
23+
* Modifications:
24+
* If applicable, add the following below the License Header, with the fields
25+
* enclosed by brackets [] replaced by your own identifying information:
26+
* "Portions Copyright [year] [name of copyright owner]"
27+
*
28+
* Contributor(s):
29+
* If you wish your version of this file to be governed by only the CDDL or
30+
* only the GPL Version 2, indicate your decision by adding "[Contributor]
31+
* elects to include this software in this distribution under the [CDDL or GPL
32+
* Version 2] license." If you don't indicate a single choice of license, a
33+
* recipient has the option to distribute your version of this file under
34+
* either the CDDL, the GPL Version 2 or to extend the choice of license to
35+
* its licensees as provided above. However, if you add GPL Version 2 code
36+
* and therefore, elected the GPL Version 2 license, then the option applies
37+
* only if the new code is made subject to such option by the copyright
38+
* holder.
39+
*/
40+
41+
package org.glassfish.jersey.tests.integration.jersey2730;
42+
43+
import javax.ws.rs.ApplicationPath;
44+
45+
import org.glassfish.jersey.server.ResourceConfig;
46+
47+
import org.glassfish.jersey.tests.integration.jersey2730.exception.MappedExceptionMapper;
48+
49+
/**
50+
* Jersey application for JERSEY-2730.
51+
*
52+
* @author Stepan Vavra (stepan.vavra at oracle.com)
53+
*/
54+
@ApplicationPath("/")
55+
public class TestApplication extends ResourceConfig {
56+
57+
public TestApplication() {
58+
register(TestExceptionResource.class);
59+
register(MappedExceptionMapper.class);
60+
}
61+
}
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*
2+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3+
*
4+
* Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved.
5+
*
6+
* The contents of this file are subject to the terms of either the GNU
7+
* General Public License Version 2 only ("GPL") or the Common Development
8+
* and Distribution License("CDDL") (collectively, the "License"). You
9+
* may not use this file except in compliance with the License. You can
10+
* obtain a copy of the License at
11+
* http://glassfish.java.net/public/CDDL+GPL_1_1.html
12+
* or packager/legal/LICENSE.txt. See the License for the specific
13+
* language governing permissions and limitations under the License.
14+
*
15+
* When distributing the software, include this License Header Notice in each
16+
* file and include the License file at packager/legal/LICENSE.txt.
17+
*
18+
* GPL Classpath Exception:
19+
* Oracle designates this particular file as subject to the "Classpath"
20+
* exception as provided by Oracle in the GPL Version 2 section of the License
21+
* file that accompanied this code.
22+
*
23+
* Modifications:
24+
* If applicable, add the following below the License Header, with the fields
25+
* enclosed by brackets [] replaced by your own identifying information:
26+
* "Portions Copyright [year] [name of copyright owner]"
27+
*
28+
* Contributor(s):
29+
* If you wish your version of this file to be governed by only the CDDL or
30+
* only the GPL Version 2, indicate your decision by adding "[Contributor]
31+
* elects to include this software in this distribution under the [CDDL or GPL
32+
* Version 2] license." If you don't indicate a single choice of license, a
33+
* recipient has the option to distribute your version of this file under
34+
* either the CDDL, the GPL Version 2 or to extend the choice of license to
35+
* its licensees as provided above. However, if you add GPL Version 2 code
36+
* and therefore, elected the GPL Version 2 license, then the option applies
37+
* only if the new code is made subject to such option by the copyright
38+
* holder.
39+
*/
40+
package org.glassfish.jersey.tests.integration.jersey2730;
41+
42+
import javax.ws.rs.GET;
43+
import javax.ws.rs.Path;
44+
import javax.ws.rs.container.AsyncResponse;
45+
import javax.ws.rs.container.Suspended;
46+
47+
import javax.inject.Singleton;
48+
49+
import org.glassfish.jersey.servlet.internal.ResponseWriter;
50+
51+
import org.glassfish.jersey.tests.integration.jersey2730.exception.MappedException;
52+
import org.glassfish.jersey.tests.integration.jersey2730.exception.UnmappedException;
53+
import org.glassfish.jersey.tests.integration.jersey2730.exception.UnmappedRuntimeException;
54+
55+
/**
56+
* @author Stepan Vavra (stepan.vavra at oracle.com)
57+
*/
58+
@Path("/exception")
59+
@Singleton
60+
public class TestExceptionResource {
61+
62+
/**
63+
* An instance of thread that was processing a last request to this resource.
64+
*/
65+
private Thread lastProcessingThread;
66+
67+
@GET
68+
@Path("null")
69+
public void get(@Suspended final AsyncResponse asyncResponse) {
70+
lastProcessingThread = Thread.currentThread();
71+
asyncResponse.resume((Throwable) null);
72+
}
73+
74+
@GET
75+
@Path("mapped")
76+
public void getMappedException(@Suspended final AsyncResponse asyncResponse) {
77+
lastProcessingThread = Thread.currentThread();
78+
asyncResponse.resume(new MappedException());
79+
}
80+
81+
@GET
82+
@Path("unmapped")
83+
public void getUnmappedException(@Suspended final AsyncResponse asyncResponse) {
84+
lastProcessingThread = Thread.currentThread();
85+
asyncResponse.resume(new UnmappedException());
86+
}
87+
88+
@GET
89+
@Path("runtime")
90+
public void getUnmappedRuntimeException(@Suspended final AsyncResponse asyncResponse) {
91+
lastProcessingThread = Thread.currentThread();
92+
asyncResponse.resume(new UnmappedRuntimeException());
93+
}
94+
95+
/**
96+
* Returns whether a thread that was processing a last request got stuck in {@link ResponseWriter}.
97+
* <p/>
98+
* Under normal circumstances, the last processing thread should return back to the servlet container
99+
* and its pool.
100+
* <p/>
101+
* May not work when executed in parallel.
102+
*
103+
* @return
104+
*/
105+
@GET
106+
@Path("rpc/lastthreadstuck")
107+
public boolean lastThreadStuckRpc() {
108+
if (lastProcessingThread == null || Thread.currentThread() == lastProcessingThread) {
109+
return false;
110+
}
111+
112+
switch (lastProcessingThread.getState()) {
113+
case BLOCKED:
114+
case TIMED_WAITING:
115+
case WAITING:
116+
for (StackTraceElement stackTraceElement : lastProcessingThread.getStackTrace()) {
117+
if (ResponseWriter.class.getName().equals(stackTraceElement.getClassName())) {
118+
return true;
119+
}
120+
}
121+
}
122+
123+
return false;
124+
}
125+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3+
*
4+
* Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved.
5+
*
6+
* The contents of this file are subject to the terms of either the GNU
7+
* General Public License Version 2 only ("GPL") or the Common Development
8+
* and Distribution License("CDDL") (collectively, the "License"). You
9+
* may not use this file except in compliance with the License. You can
10+
* obtain a copy of the License at
11+
* http://glassfish.java.net/public/CDDL+GPL_1_1.html
12+
* or packager/legal/LICENSE.txt. See the License for the specific
13+
* language governing permissions and limitations under the License.
14+
*
15+
* When distributing the software, include this License Header Notice in each
16+
* file and include the License file at packager/legal/LICENSE.txt.
17+
*
18+
* GPL Classpath Exception:
19+
* Oracle designates this particular file as subject to the "Classpath"
20+
* exception as provided by Oracle in the GPL Version 2 section of the License
21+
* file that accompanied this code.
22+
*
23+
* Modifications:
24+
* If applicable, add the following below the License Header, with the fields
25+
* enclosed by brackets [] replaced by your own identifying information:
26+
* "Portions Copyright [year] [name of copyright owner]"
27+
*
28+
* Contributor(s):
29+
* If you wish your version of this file to be governed by only the CDDL or
30+
* only the GPL Version 2, indicate your decision by adding "[Contributor]
31+
* elects to include this software in this distribution under the [CDDL or GPL
32+
* Version 2] license." If you don't indicate a single choice of license, a
33+
* recipient has the option to distribute your version of this file under
34+
* either the CDDL, the GPL Version 2 or to extend the choice of license to
35+
* its licensees as provided above. However, if you add GPL Version 2 code
36+
* and therefore, elected the GPL Version 2 license, then the option applies
37+
* only if the new code is made subject to such option by the copyright
38+
* holder.
39+
*/
40+
package org.glassfish.jersey.tests.integration.jersey2730.exception;
41+
42+
/**
43+
* This exception will get mapped to a 432 response with the application exception mapper
44+
* implemented by {@link MappedExceptionMapper} class.
45+
*
46+
* @author Stepan Vavra (stepan.vavra at oracle.com)
47+
*/
48+
public class MappedException extends Exception {
49+
50+
}

0 commit comments

Comments
 (0)