https://issues.apache.org/bugzilla/show_bug.cgi?id=54571
Bug ID: 54571
Summary: Race condition when handling comet event in thread
other than the serving servlet
Product: Tomcat 6
Version: 6.0.36
Hardware: PC
OS: Linux
Status: NEW
Severity: normal
Priority: P2
Component: Catalina
Assignee: [email protected]
Reporter: [email protected]
Classification: Unclassified
Created attachment 29958
--> https://issues.apache.org/bugzilla/attachment.cgi?id=29958&action=edit
A werid http stream which has no http header in response
OS: Linux hostname 2.6.32-279.11.1.el6.x86_64 #1 SMP Sat Sep 22 07:10:26 EDT
2012 x86_64 x86_64 x86_64 GNU/Linux
I have a servlet which post the comet event to other thread for further
handling, there is no synchronize mechanism between this handling thread the
servlet.
And I have a simple python script as a client for testing, it act as a client:
1. make a connection to the servlet
2. send http request and check the response
3. close the connection
After some long sequence of test above, I got a bizarre response with header
Transfer-Encoding: chunked.
The demo code is as following
[code][filename]TestServlet.java[/filename]
import javax.servlet.ServletException;
import java.io.PrintWriter;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.apache.catalina.CometEvent;
import org.apache.catalina.CometEvent.EventSubType;
import org.apache.catalina.CometProcessor;
import java.util.concurrent.LinkedBlockingQueue;
public class TestServlet extends HttpServlet implements CometProcessor {
static String
response1="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
static String
response2="bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
protected ThreadModule fRunner=null;
public void init() throws ServletException {
fRunner=new ThreadModule();
Thread runningThread=new Thread(fRunner,"test");
runningThread.setDaemon(true);
runningThread.start();
}
public void event(CometEvent event) throws IOException, ServletException
{
HttpServletRequest request = event.getHttpServletRequest();
HttpServletResponse response = event.getHttpServletResponse();
if (event.getEventType() == CometEvent.EventType.BEGIN) {
//log("Begin for session: " + request.getSession(true).getId());
if (request.getContentLength() <= 0){
String uri = request.getRequestURI();
if (uri.contains("HELLO")) {
fRunner.PostMessage(new ThreadMessage(1,response));
}
else if (uri.contains("WORLD")){
fRunner.PostMessage(new ThreadMessage(2,response));
}
else if (uri.contains("SAD")){
fRunner.PostMessage(new ThreadMessage(3,response));
}
else{
fRunner.PostMessage(new ThreadMessage(4,response));
}
}
} else if (event.getEventType() == CometEvent.EventType.ERROR) {
//log("Error for session: " + request.getSession(true).getId());
event.close();
} else if (event.getEventType() == CometEvent.EventType.END) {
//log("End for session: " + request.getSession(true).getId());
event.close();
} else if (event.getEventType() == CometEvent.EventType.READ) {
}
}
public class ThreadMessage {
public int resType;
public HttpServletResponse response;
public ThreadMessage(int inresType, HttpServletResponse inresponse){
this.resType=inresType;
this.response=inresponse;
}
}
public class ThreadModule implements Runnable {
protected LinkedBlockingQueue<ThreadMessage> queue = new
LinkedBlockingQueue<ThreadMessage>();
protected Object waitObject = new Object();
public ThreadModule(){
}
public void PostMessage(ThreadMessage inMessage){
queue.offer(inMessage);
synchronized (waitObject) {
waitObject.notify();
}
}
public void HandleMessage(ThreadMessage inMessage){
try{
if (inMessage.resType == 1){
inMessage.response.setStatus(200);
PrintWriter writer = inMessage.response.getWriter();
writer.write(response1);
writer.close();
}
else if (inMessage.resType == 2){
inMessage.response.setStatus(404);
PrintWriter writer = inMessage.response.getWriter();
writer.write("");
writer.close();
}
else if (inMessage.resType == 3){
inMessage.response.setStatus(307);
PrintWriter writer = inMessage.response.getWriter();
writer.write(response2);
writer.close();
}
else{
inMessage.response.setStatus(500);
PrintWriter writer = inMessage.response.getWriter();
writer.write("");
writer.close();
}
}
catch (Exception e) {
}
}
public void run(){
while (true) {
try{
ThreadMessage tempmessage=null;
if (queue.isEmpty()) {
synchronized (waitObject) {
if (queue.isEmpty()){
waitObject.wait();
}
}
}
if (!queue.isEmpty()){
tempmessage = queue.poll();
}
if (tempmessage != null){
//sleep,if no sleep here, seems we got a race condition
//Thread.sleep(5);
HandleMessage(tempmessage);
}
}
catch (Exception e) {
}
}
}
}
}
[/code]
The client testing code
[code][filename]tempclient.py[/filename/
import httplib
import time
commonheaders = {"Connection":"close"}
def GetContent(addr, requesturl, expectcode, expectbody=None, notexpect=None):
data=None
try:
conn = httplib.HTTPConnection(addr)
conn.request("GET", requesturl,'',commonheaders)
r1 = conn.getresponse()
rescode=r1.status
data=r1.read()
conn.close()
except Exception as exp_obj:
print "connection fail, try again"
print exp_obj
data=None
if data==None:
conn = httplib.HTTPConnection(addr)
conn.request("GET", requesturl,'',commonheaders)
r1 = conn.getresponse()
rescode=r1.status
#print rescode
data=r1.read()
conn.close()
if rescode != expectcode:
raise Exception("Fail to get
expectcode:"+str(expectcode)+",with:--"+data)
if expectbody!=None and data.find(expectbody)== -1:
raise Exception("Fail to find:"+expectbody+",with:--"+data)
if notexpect!=None and data.find(notexpect)!=-1:
raise Exception("Fail to not find:"+notexpect+",with:--"+data)
if __name__ == "__main__":
testhost="10.90.10.119:8080"
starttime=time.time()
count=0
try:
for index in range(0,150000):
count=count+1
GetContent(testhost,"/david/HelloWorld/HELLO",200, "aaaaaaaa",'b')
GetContent(testhost,"/david/HelloWorld/WORLD",404, )
GetContent(testhost,"/david/HelloWorld/SAD",307,"bbbbbbb",'a')
finally:
endtime=time.time()
totaltime=int(endtime-starttime)
print "count:",count
print "Time:",totaltime
[/code]
I got lots of weird http streams, one of which is attached
I think that there is some race condition between the processing thread and the
servlet/comet thread, because if I add some delay, e.g. Thread.sleep(5);, in
the precessing thread, (which is commented in the code) no weird response
found.
And if the function for sending response is called direct in servlet
thread,(totally remove the second thread) also no werid response found.
--
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]