In my Java / Struts2 / Tomcat application, when requesting some resources that generate a "304 Not Modified" response, the file is still being sent in the response.
This is a response example captured with Fiddler:
HTTP/1.1 304 Not Modified
Date: Thu, 26 Jun 2014 11:27:27 GMT
Server: Apache/2.2.16 (Ubuntu)
Connection: Keep-Alive
Keep-Alive: timeout=15, max=100
Vary: Accept-Encoding
/*! jQuery v1.7.2 jquery.com | jquery.org/license */
(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?
a.defaultView||a.parentWindow:!1}function cu(a){if(!cj[a]){var b=c.body,d=f("
<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ck||
[...]
This is a problem because the content of the returned file is inserted into the next requested file, ending up in corruption and weird behavior.
This only happens on resources loaded from the "/struts" path, like:
/struts/utils.js
/struts/js/base/jquery-1.10.2.min.js
/struts/js/base/jquery.ui.core.min.js?s2j=3.7.0
The "/struts" path is handled by the struts2 class
org.apache.struts2.dispatcher.DefaultStaticContentLoader
These are the relevant elements of the system:
- Ubuntu 12.04.4 LTS (GNU/Linux 3.5.0-27-generic x86_64)
- JVM 1.6.0_31-b31 Sun Microsystems Inc. (also tried with ibm-java-x86_64-71)
- Apache2 2.2.22-1ubuntu1.6 with modjk
- Apache Tomcat/6.0.35
- Struts 2.3.16
- Sitemesh 3.0.0
When connecting directly to tomcat I don't get any unexpected data after the Not Modified header.
The Apache Server configuration hasn't been modified much, just an alias for /contents and two modjk directives:
JkMount /* ajp13_worker
JkUnMount /contents/* ajp13_worker
There is nothing related to /struts or caching or anything exotic. ModJK configuration is the default settings.
Any suggestion?
This is an answer that doesn't solve the problem, but opens new questions.
The response corruption occurs when using sitemesh3 behind apache server. If I access the tomcat server directly, the response is a clean 304. If I access through a modjk/apache, the response contains unexpected data.
The reason for the unexpected data is due to how sitemesh works: when sending the response, at some point it forces struts to ignore any "If-Modified-Since" header, writing the requested content to the response buffer. It then goes on by adding the 304 headers as well at the beginning of the buffer.
See, for a start
org.sitemesh.webapp.contentfilter.HttpServletRequestFilterable
org.apache.struts2.dispatcher.DefaultStaticContentLoader.process()
I don't know where to go from here. Is it a bug? Is it an Apache Server bug or a Tomcat bug or a Struts bug or a Sitemesh bug?!
To replicate the problem, you need a tomcat behind apache running a struts webapp with sitemesh in it, and fetch this url twice while fiddler2 is active:
http://[test.server.address]/struts/utils.js
Piece of cake o_O'
Edit:
If I check the modjk log, I can clearly see the file transmitted back to Apache server:
: trying to connect socket 29 to 127.0.0.1:9009
: socket 29 [127.0.0.1:57195 -> 127.0.0.1:9009] connected
: sending to ajp13 pos=4 len=581 max=8192
.4.A....HTTP/1.1
.../struts/utils
.js...2.235.97.2
[...]
...Accept-Langua
ge..#en,en-US;q=
0.8,it-IT;q=0.6,
it;q=0.4....+JSE
SSIONID=B77369AB
D8239724A27A5CC5
6E06DED8...If-Mo
dified-Since...F
ri,.27.Jun.2014.
08:37:46.GMT....
.0....AJP_REMOTE
_PORT...19143...
.JK_LB_ACTIVATIO
N...............
: (rdp_worker) request body to send 0 - request body to resend 0
: received from ajp13 pos=0 len=20 max=8192
..0..Not.Modifie
d...............
: status = 304
: Number of headers is = 0
: received from ajp13 pos=0 len=4767 max=8192
.../*..*.$Id:.ut
ils.js.1240312.2
012-02-03.19:44:
51Z.jogep.$..*..
*.Licensed.to.th
e.Apache.Softwar
e.Foundation.(AS
F).under.one..*.
or.more.contribu
tor.license.agre
ements...See.the
[...]
the.ajaxValidati
on.interceptor.S
trutsUtils.getVa
lidationErrors.=
: ws_write::mod_jk.c (537): written 4763 out of 4763
: received from ajp13 pos=0 len=4 max=8192
................
: received from ajp13 pos=0 len=2 max=8192
................
: AJP13 protocol: Reuse is OK
When I access tomcat directly and dump the TCP traffic with tcpflow, I don't see any spurious data:
# tcpflow -p -s -c host xxx.xxx.xxx.xxx and port 8080
xxx.xxx.xxx.xxx.19292-yyy.yyy.yyy.yyy.08080: GET /rdp/struts/utils.js HTTP/1.1
Host: xxx.net:8080
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en,en-US;q=0.8,it-IT;q=0.6,it;q=0.4
Cookie: JSESSIONID=B0F02CXXXEC3448F1B927C0E8C579A9B
If-Modified-Since: Fri, 27 Jun 2014 08:49:23 GMT
yyy.yyy.yyy.yyy.08080-xxx.xxx.xxx.xxx.19292: HTTP/1.1 304 Not Modified
Server: Apache-Coyote/1.1
Date: Fri, 27 Jun 2014 08:52:43 GMT
So there seems to be a different behavior in returning the buffer to an ajp port and returning it to a network socket. This is too low level for me to get any further.
Edit:
Workaround
The workaround I have implemented consists in letting Apache Server handle the /struts context:
- extract from the struts and struts-jquery-plugin jars all files that are affected (the content of org\apache\struts2\static and the content of template respectively)
- copy these files on a directory on the server
- create an alias in apache to serve that directory when the /struts path is encountered
- unmap the /struts path from modJK
来源:https://stackoverflow.com/questions/24430135/not-modified-header-followed-by-unexpected-content-body-with-sitemesh3-and-mod