Author: remy.maucherat(a)jboss.com
Date: 2011-07-13 12:31:38 -0400 (Wed, 13 Jul 2011)
New Revision: 1781
Modified:
trunk/java/org/apache/catalina/connector/LocalStrings.properties
trunk/java/org/apache/catalina/connector/OutputBuffer.java
trunk/java/org/apache/catalina/connector/Request.java
trunk/java/org/apache/catalina/connector/RequestFacade.java
trunk/java/org/apache/catalina/connector/Response.java
trunk/java/org/apache/catalina/connector/ResponseFacade.java
trunk/java/org/apache/catalina/servlets/DefaultServlet.java
trunk/java/org/apache/coyote/Request.java
trunk/java/org/apache/coyote/Response.java
trunk/java/org/apache/coyote/http11/Http11AprProcessor.java
trunk/webapps/docs/changelog.xml
Log:
- Refactor sendfile as its own custom API, similar to sendError and sendRedirect.
Modified: trunk/java/org/apache/catalina/connector/LocalStrings.properties
===================================================================
--- trunk/java/org/apache/catalina/connector/LocalStrings.properties 2011-07-13 15:43:16
UTC (rev 1780)
+++ trunk/java/org/apache/catalina/connector/LocalStrings.properties 2011-07-13 16:31:38
UTC (rev 1781)
@@ -36,6 +36,9 @@
coyoteResponse.sendError.ise=Cannot call sendError() after the response has been
committed
coyoteResponse.sendRedirect.ise=Cannot call sendRedirect() after the response has been
committed
coyoteResponse.setBufferSize.ise=Cannot change buffer size after data has been written
+coyoteResponse.sendFile.ise=Cannot call sendFile() after the response has been committed
+coyoteResponse.sendFile.no=Sendfile is disabled
+coyoteResponse.sendFile.path=Invalid path
#
# CoyoteRequest
Modified: trunk/java/org/apache/catalina/connector/OutputBuffer.java
===================================================================
--- trunk/java/org/apache/catalina/connector/OutputBuffer.java 2011-07-13 15:43:16 UTC
(rev 1780)
+++ trunk/java/org/apache/catalina/connector/OutputBuffer.java 2011-07-13 16:31:38 UTC
(rev 1781)
@@ -602,6 +602,10 @@
return -1;
}
+ public void setBytesWritten(long bytesWritten) {
+ this.bytesWritten = bytesWritten;
+ }
+
public int getCharsWritten() {
if (charsWritten < Integer.MAX_VALUE) {
return (int) charsWritten;
Modified: trunk/java/org/apache/catalina/connector/Request.java
===================================================================
--- trunk/java/org/apache/catalina/connector/Request.java 2011-07-13 15:43:16 UTC (rev
1780)
+++ trunk/java/org/apache/catalina/connector/Request.java 2011-07-13 16:31:38 UTC (rev
1781)
@@ -3301,6 +3301,11 @@
}
+ public boolean hasSendfile() {
+ return coyoteRequest.hasSendfile();
+ }
+
+
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append(sm.getString("coyoteRequest.servletStack",
Thread.currentThread().getName()));
Modified: trunk/java/org/apache/catalina/connector/RequestFacade.java
===================================================================
--- trunk/java/org/apache/catalina/connector/RequestFacade.java 2011-07-13 15:43:16 UTC
(rev 1780)
+++ trunk/java/org/apache/catalina/connector/RequestFacade.java 2011-07-13 16:31:38 UTC
(rev 1781)
@@ -1112,4 +1112,13 @@
return request.getParts();
}
+ public boolean hasSendfile() {
+ if (request == null) {
+ throw new IllegalStateException(
+ sm.getString("requestFacade.nullRequest"));
+ }
+
+ return request.hasSendfile();
+ }
+
}
Modified: trunk/java/org/apache/catalina/connector/Response.java
===================================================================
--- trunk/java/org/apache/catalina/connector/Response.java 2011-07-13 15:43:16 UTC (rev
1780)
+++ trunk/java/org/apache/catalina/connector/Response.java 2011-07-13 16:31:38 UTC (rev
1781)
@@ -19,6 +19,7 @@
package org.apache.catalina.connector;
+import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
@@ -46,6 +47,8 @@
import org.apache.catalina.util.CharsetMapper;
import org.apache.catalina.util.DateTool;
import org.apache.catalina.util.StringManager;
+import org.apache.naming.resources.CacheEntry;
+import org.apache.naming.resources.ProxyDirContext;
import org.apache.tomcat.util.buf.CharChunk;
import org.apache.tomcat.util.buf.UEncoder;
import org.apache.tomcat.util.http.FastHttpDateFormat;
@@ -1338,6 +1341,66 @@
}
+ public void sendFile(String path, String absolutePath, long start, long end) {
+
+ if (isCommitted())
+ throw new IllegalStateException
+ (sm.getString("coyoteResponse.sendFile.ise"));
+
+ // Ignore any call from an included servlet
+ if (included)
+ return;
+
+ if (!request.hasSendfile())
+ throw new
IllegalStateException(sm.getString("coyoteResponse.sendFile.no"));
+
+ if (Globals.IS_SECURITY_ENABLED) {
+ if (path != null) {
+ CacheEntry cacheEntry =
+ ((ProxyDirContext)
request.getContext().getResources()).lookupCache(path);
+ if (cacheEntry.exists && cacheEntry.resource != null &&
(end > start)
+ && cacheEntry.attributes.getCanonicalPath() != null) {
+
coyoteResponse.setSendfilePath(cacheEntry.attributes.getCanonicalPath());
+ coyoteResponse.setSendfileStart(start);
+ coyoteResponse.setSendfileEnd(end);
+ }
+ } else if (absolutePath != null) {
+ String canonicalPath = null;
+ try {
+ canonicalPath = new File(absolutePath).getCanonicalPath();
+ } catch (IOException e) {
+ throw new
IllegalArgumentException(sm.getString("coyoteResponse.sendFile.path"));
+ }
+ System.getSecurityManager().checkRead(canonicalPath);
+ coyoteResponse.setSendfilePath(absolutePath);
+ coyoteResponse.setSendfileStart(start);
+ coyoteResponse.setSendfileEnd(end);
+ }
+ } else {
+ if (absolutePath != null) {
+ coyoteResponse.setSendfilePath(absolutePath);
+ coyoteResponse.setSendfileStart(start);
+ coyoteResponse.setSendfileEnd(end);
+ } else {
+ CacheEntry cacheEntry =
+ ((ProxyDirContext)
request.getContext().getResources()).lookupCache(path);
+ if (cacheEntry.exists && cacheEntry.resource != null &&
(end > start)
+ && cacheEntry.attributes.getCanonicalPath() != null) {
+
coyoteResponse.setSendfilePath(cacheEntry.attributes.getCanonicalPath());
+ coyoteResponse.setSendfileStart(start);
+ coyoteResponse.setSendfileEnd(end);
+ }
+ }
+ }
+
+ outputBuffer.setBytesWritten(end - start);
+
+ // Cause the response to be finished (from the application perspective)
+ setSuspended(true);
+
+ }
+
+
/**
* Set the specified date header to the specified value.
*
Modified: trunk/java/org/apache/catalina/connector/ResponseFacade.java
===================================================================
--- trunk/java/org/apache/catalina/connector/ResponseFacade.java 2011-07-13 15:43:16 UTC
(rev 1780)
+++ trunk/java/org/apache/catalina/connector/ResponseFacade.java 2011-07-13 16:31:38 UTC
(rev 1781)
@@ -442,7 +442,18 @@
}
+ public void sendFile(String path, String absolutePath, long start, long end) {
+
+ if (isCommitted())
+ throw new IllegalStateException
+ (/*sm.getString("responseBase.reset.ise")*/);
+ response.setAppCommitted(true);
+
+ response.sendFile(path, absolutePath, start, end);
+
+ }
+
public void setDateHeader(String name, long date) {
if (isCommitted())
Modified: trunk/java/org/apache/catalina/servlets/DefaultServlet.java
===================================================================
--- trunk/java/org/apache/catalina/servlets/DefaultServlet.java 2011-07-13 15:43:16 UTC
(rev 1780)
+++ trunk/java/org/apache/catalina/servlets/DefaultServlet.java 2011-07-13 16:31:38 UTC
(rev 1781)
@@ -59,6 +59,8 @@
import javax.xml.transform.stream.StreamSource;
import org.apache.catalina.Globals;
+import org.apache.catalina.connector.RequestFacade;
+import org.apache.catalina.connector.ResponseFacade;
import org.apache.catalina.util.RequestUtil;
import org.apache.catalina.util.ServerInfo;
import org.apache.catalina.util.StringManager;
@@ -805,7 +807,7 @@
// Silent catch
}
if (ostream != null) {
- if (!checkSendfile(request, response, cacheEntry, contentLength,
null))
+ if (!checkSendfile(request, response, path, cacheEntry,
contentLength, null))
copy(cacheEntry, renderResult, ostream);
} else {
copy(cacheEntry, renderResult, writer);
@@ -850,7 +852,7 @@
// Silent catch
}
if (ostream != null) {
- if (!checkSendfile(request, response, cacheEntry, range.end -
range.start + 1, range))
+ if (!checkSendfile(request, response, path, cacheEntry, range.end
- range.start + 1, range))
copy(cacheEntry, ostream, range);
} else {
copy(cacheEntry, writer, range);
@@ -1494,24 +1496,21 @@
*/
protected boolean checkSendfile(HttpServletRequest request,
HttpServletResponse response,
- CacheEntry entry,
+ String path, CacheEntry entry,
long length, Range range) {
if ((sendfileSize > 0)
&& (entry.resource != null)
&& ((length > sendfileSize) || (entry.resource.getContent() ==
null))
&& (entry.attributes.getCanonicalPath() != null)
- && (Boolean.TRUE ==
request.getAttribute("org.apache.tomcat.sendfile.support"))
&&
(request.getClass().getName().equals("org.apache.catalina.connector.RequestFacade"))
- &&
(response.getClass().getName().equals("org.apache.catalina.connector.ResponseFacade")))
{
- request.setAttribute("org.apache.tomcat.sendfile.filename",
entry.attributes.getCanonicalPath());
+ &&
(response.getClass().getName().equals("org.apache.catalina.connector.ResponseFacade"))
+ && ((RequestFacade) request).hasSendfile()) {
+ ResponseFacade responseFacade = (ResponseFacade) response;
if (range == null) {
- request.setAttribute("org.apache.tomcat.sendfile.start", new
Long(0L));
- request.setAttribute("org.apache.tomcat.sendfile.end", new
Long(length));
+ responseFacade.sendFile(path, entry.attributes.getCanonicalPath(), 0,
length);
} else {
- request.setAttribute("org.apache.tomcat.sendfile.start", new
Long(range.start));
- request.setAttribute("org.apache.tomcat.sendfile.end", new
Long(range.end + 1));
+ responseFacade.sendFile(path, entry.attributes.getCanonicalPath(),
range.start, range.end + 1);
}
- request.setAttribute("org.apache.tomcat.sendfile.token", this);
return true;
} else {
return false;
Modified: trunk/java/org/apache/coyote/Request.java
===================================================================
--- trunk/java/org/apache/coyote/Request.java 2011-07-13 15:43:16 UTC (rev 1780)
+++ trunk/java/org/apache/coyote/Request.java 2011-07-13 16:31:38 UTC (rev 1781)
@@ -144,6 +144,7 @@
// Time of the request - usefull to avoid repeated calls to System.currentTime
private long startTime = 0L;
private int available = 0;
+ private boolean sendfile = false;
private RequestInfo reqProcessorMX=new RequestInfo(this);
// ------------------------------------------------------------- Properties
@@ -170,6 +171,16 @@
return urlDecoder;
}
+ public boolean hasSendfile() {
+ return sendfile;
+ }
+
+
+ public void setSendfile(boolean sendfile) {
+ this.sendfile = sendfile;
+ }
+
+
// -------------------- Request data --------------------
Modified: trunk/java/org/apache/coyote/Response.java
===================================================================
--- trunk/java/org/apache/coyote/Response.java 2011-07-13 15:43:16 UTC (rev 1780)
+++ trunk/java/org/apache/coyote/Response.java 2011-07-13 16:31:38 UTC (rev 1781)
@@ -127,6 +127,10 @@
protected int lastWrite = 1;
protected boolean flushLeftovers = true;
+ protected String sendfilePath = null;
+ protected long sendfileStart = 0;
+ protected long sendfileEnd = 0;
+
// ------------------------------------------------------------- Properties
public Request getRequest() {
@@ -557,7 +561,30 @@
return contentLength;
}
+ public String getSendfilePath() {
+ return sendfilePath;
+ }
+ public void setSendfilePath(String sendfilePath) {
+ this.sendfilePath = sendfilePath;
+ }
+
+ public long getSendfileStart() {
+ return sendfileStart;
+ }
+
+ public void setSendfileStart(long sendfileStart) {
+ this.sendfileStart = sendfileStart;
+ }
+
+ public long getSendfileEnd() {
+ return sendfileEnd;
+ }
+
+ public void setSendfileEnd(long sendfileEnd) {
+ this.sendfileEnd = sendfileEnd;
+ }
+
/**
* Write a chunk of bytes.
*/
@@ -585,6 +612,8 @@
errorURI = null;
headers.clear();
+ sendfilePath = null;
+
// update counters
lastWrite = 1;
bytesWritten=0;
Modified: trunk/java/org/apache/coyote/http11/Http11AprProcessor.java
===================================================================
--- trunk/java/org/apache/coyote/http11/Http11AprProcessor.java 2011-07-13 15:43:16 UTC
(rev 1780)
+++ trunk/java/org/apache/coyote/http11/Http11AprProcessor.java 2011-07-13 16:31:38 UTC
(rev 1781)
@@ -94,13 +94,17 @@
request = new Request();
inputBuffer = new InternalAprInputBuffer(request, headerBufferSize, endpoint);
request.setInputBuffer(inputBuffer);
+ if (endpoint.getUseSendfile()) {
+ request.setSendfile(true);
+ }
response = new Response();
response.setHook(this);
outputBuffer = new InternalAprOutputBuffer(response, headerBufferSize,
endpoint);
response.setOutputBuffer(outputBuffer);
+
request.setResponse(response);
-
+
ssl = endpoint.isSSLEnabled();
initializeFilters();
@@ -1495,11 +1499,6 @@
contentDelimitation = true;
}
- // Advertise sendfile support through a request attribute
- if (endpoint.getUseSendfile()) {
- request.setAttribute("org.apache.tomcat.sendfile.support",
Boolean.TRUE);
- }
-
}
@@ -1672,20 +1671,15 @@
}
// Sendfile support
- if (endpoint.getUseSendfile()) {
- String fileName = (String)
request.getAttribute("org.apache.tomcat.sendfile.filename");
- if (fileName != null) {
- // No entity body sent here
- outputBuffer.addActiveFilter
- (outputFilters[Constants.VOID_FILTER]);
- contentDelimitation = true;
- sendfileData = new AprEndpoint.SendfileData();
- sendfileData.fileName = fileName;
- sendfileData.start =
- ((Long)
request.getAttribute("org.apache.tomcat.sendfile.start")).longValue();
- sendfileData.end =
- ((Long)
request.getAttribute("org.apache.tomcat.sendfile.end")).longValue();
- }
+ if (response.getSendfilePath() != null) {
+ // No entity body sent here
+ outputBuffer.addActiveFilter
+ (outputFilters[Constants.VOID_FILTER]);
+ contentDelimitation = true;
+ sendfileData = new AprEndpoint.SendfileData();
+ sendfileData.fileName = response.getSendfilePath();
+ sendfileData.start = response.getSendfileStart();
+ sendfileData.end = response.getSendfileEnd();
}
// Check for compression
Modified: trunk/webapps/docs/changelog.xml
===================================================================
--- trunk/webapps/docs/changelog.xml 2011-07-13 15:43:16 UTC (rev 1780)
+++ trunk/webapps/docs/changelog.xml 2011-07-13 16:31:38 UTC (rev 1781)
@@ -30,6 +30,9 @@
<fix>
Fix handling of sendfile errors when calling add. (markt)
</fix>
+ <update>
+ Refactor sendfile as its own API, similar to sendError. (remm)
+ </update>
</changelog>
</subsection>
</section>