On 11/30/2021 1:58 PM, Christopher Schultz wrote:
Jerry,
On 11/30/21 14:17, Jerry Malcolm wrote:
Chris, Thanks for the response.
Sorry... forgot to include the TC ver -- 8.5.69.
I had a situation a while back where I spun a longrunning thread and
held the request object after the main response was returned. I fixed
that situation. In this situation, it is occurring on the main
request/response thread. Is there any situation where the request
object could be recycled before the associated response is returned?
Not usually. So the thread hitting the NPE is something like
[catalina-exec- ...]?
And you are sure you aren't doing anything funny with the request
object? No storing it in the session or getting a reference from some
cross-thread storage mechanism?
Looking at the code
(https://github.com/apache/tomcat/blob/8.5.x/java/org/apache/catalina/connector/Request.java#L2465):
@Override
public StringBuffer getRequestURL() {
StringBuffer url = new StringBuffer();
String scheme = getScheme();
int port = getServerPort();
if (port < 0)
{
port = 80; // Work around java.net.URL bug
}
url.append(scheme);
url.append("://");
url.append(getServerName());
if ((scheme.equals("http") && (port != 80))
|| (scheme.equals("https") && (port != 443))) {
url.append(':'); // <<<< This is line 2465
url.append(port);
}
url.append(getRequestURI());
return url;
}
I don't see how an NPE could happen on that line.
But 8.5.69 was released on 2021-07-05, and that code is here:
https://github.com/apache/tomcat/blob/3e9dd49b20f9d6e270f8709d4f16d5595977595e/java/org/apache/catalina/connector/Request.java
This makes a little more sense:
@Override
public StringBuffer getRequestURL() {
StringBuffer url = new StringBuffer();
String scheme = getScheme();
int port = getServerPort();
if (port < 0)
{
port = 80; // Work around java.net.URL bug
}
url.append(scheme);
url.append("://");
url.append(getServerName());
if ((scheme.equals("http") && (port != 80)) // <<< This is 2465
|| (scheme.equals("https") && (port != 443))) {
url.append(':');
url.append(port);
}
url.append(getRequestURI());
return url;
}
So the scheme is null. That's odd, since getScheme is:
public String getScheme() {
return coyoteRequest.scheme().toString();
}
Oh, but coyoteRequest.scheme() returns a MessageBytes object whose
toString method can (somewhat surprisingly) return null(!) when the
type is T_NULL. And wouldn't you know it, here is the code for
MessageBytes.recycle() (which gets called whenever the request, and
therefore all of the various parts of the request, is recycled):
public void recycle() {
type=T_NULL;
byteC.recycle();
charC.recycle();
strValue=null;
hasStrValue=false;
hasHashCode=false;
hasLongValue=false;
}
So it definitely looks like your request has been recycled somehow.
-chris
Chris, I was running 8.5.69. (I just bumped to 8.5.72). So I agree
that everything looks like a recycled request. This is a REST api.
Pretty much come in, do the work, return. The request object is carried
around throughout the api in a 'briefcase' object. But nothing is
cached in the session object or anywhere. Pretty much a new sunrise on
every api/servlet call coming in.
Just to confirm my understanding of request recycling, a request object
is assigned before the request is handed to my handler servlet. When
the servlet exits, the request object is recycled and returned to the
pool. For this problem to be a recycled request problem, it would mean
that I saved off a reference to a request and referenced it on a
different servlet call. It would have to be on a different call, since
the service of the api is a single thread in and out. I've been around
too long to say that it couldn't happen. But at this point, I'm
struggling with how. It would mean I would have to discard the correct
request for the servlet call and replace it with an old version. I'm
going to have add some logging statements. Is there a unique id or
something for each request object in the pool that I might be able to
get access to? If so, I can start logging the request UID at the
beginning of the servlet call and log the UID on each access to the
request object.
Let me know if there's some magic ID I can log to try to figure out when
i might be using a recycled instance?
Thx
Jerry
On 11/29/2021 7:42 PM, Christopher Schultz wrote:
Jerry,
On 11/29/21 19:33, Jerry Malcolm wrote:
Can anyone tell me what I might be doing that would cause an NPE
inside the request object on getRequestURL()? The NPE only happens
about 10% of the time. I can't figure out what is happening
differently in that 10% of the calls to this code. Thx
java.lang.NullPointerException
at
org.apache.catalina.connector.Request.getRequestURL(Request.java:2465)
at
org.apache.catalina.connector.RequestFacade.getRequestURL(RequestFacade.java:868)
Thoughts:
1. Tomcat version?
2. Retained reference to request object that has been recycled?
-chris
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org