--- /dev/null
+// AsIsFrame.java\r
+// $Id: AsIsFrame.java,v 1.1 2010/06/15 12:24:18 smhuang Exp $\r
+// (c) COPYRIGHT MIT, INRIA and Keio, 2001.\r
+// Please first read the full copyright statement in file COPYRIGHT.html\r
+\r
+package org.w3c.jigsaw.frames;\r
+\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.FileNotFoundException;\r
+import java.io.IOException;\r
+\r
+import java.util.Enumeration;\r
+\r
+import org.w3c.tools.resources.ProtocolException;\r
+import org.w3c.tools.resources.ResourceException;\r
+\r
+import org.w3c.tools.resources.event.AttributeChangedEvent;\r
+\r
+import org.w3c.util.CountInputStream;\r
+\r
+import org.w3c.www.mime.MimeParser;\r
+import org.w3c.www.mime.MimeParserException;\r
+\r
+import org.w3c.www.http.ByteRangeOutputStream;\r
+import org.w3c.www.http.HTTP;\r
+import org.w3c.www.http.HeaderDescription;\r
+import org.w3c.www.http.HeaderValue;\r
+import org.w3c.www.http.MimeParserReplyFactory;\r
+import org.w3c.www.http.HttpContentRange;\r
+import org.w3c.www.http.HttpEntityTag;\r
+import org.w3c.www.http.HttpRange;\r
+import org.w3c.www.http.HttpReplyMessage;\r
+import org.w3c.www.http.HttpFactory;\r
+\r
+import org.w3c.jigsaw.http.Reply;\r
+import org.w3c.jigsaw.http.Request;\r
+\r
+/**\r
+ * Read the HTTP reply directly from a file. Like in Apache mod_asis\r
+ * http://httpd.apache.org/docs/mod/mod_asis.html\r
+ * \r
+ */\r
+public class AsIsFrame extends HTTPFrame {\r
+ \r
+ // the file offset\r
+ int foffset = -1;\r
+ HttpReplyMessage asisreply = null;\r
+\r
+ /**\r
+ * Listen its resource.\r
+ */\r
+ public void attributeChanged(AttributeChangedEvent evt) {\r
+ super.attributeChanged(evt);\r
+ asisreply = null;\r
+ }\r
+\r
+ /**\r
+ * shadows the call from HTTPFrame\r
+ * It updates the cached headers for the automagic reply generation\r
+ */\r
+ protected void updateCachedHeaders() {\r
+ super.updateCachedHeaders();\r
+ if (asisreply == null) {\r
+ if (fresource != null) {\r
+ // read the reply from the file stream\r
+ FileInputStream fis = null;\r
+ try {\r
+ fis = new FileInputStream(fresource.getFile());\r
+ } catch (FileNotFoundException fex) {\r
+ // should never happen\r
+ }\r
+ CountInputStream cis = new CountInputStream(fis);\r
+ MimeParserReplyFactory repfact = new MimeParserReplyFactory();\r
+ MimeParser mp = new MimeParser(cis, repfact);\r
+ try {\r
+ asisreply = (HttpReplyMessage) mp.parse();\r
+ } catch (MimeParserException mex) {\r
+ // probably a "normal" file, serve it as-is...\r
+ return;\r
+ } catch (IOException ioex) {\r
+ // silently fail, iot will fail later anyway\r
+ return;\r
+ }\r
+ // update the offset and the Content-Length\r
+ foffset = (int) cis.getBytesRead();\r
+ try {\r
+ cis.close();\r
+ } catch (IOException ioex) {};\r
+ int cl = fresource.getFileLength();\r
+ cl -= foffset;\r
+ setValue(ATTR_CONTENT_LENGTH, new Integer(cl));\r
+ contentlength = HttpFactory.makeInteger(cl);\r
+ // reset the md5, as we don't yet compute it\r
+ md5Digest = null;\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Create a reply to answer to request on this file.\r
+ * This method will create a suitable reply (matching the given request)\r
+ * and will set all its default header values to the appropriate \r
+ * values.\r
+ * The Status is ignored as it is superceded byt the Asis file\r
+ * @param request The request to make a reply for.\r
+ * @return An instance of Reply, suited to answer this request.\r
+ */\r
+ public Reply createDefaultReply(Request request, int status) {\r
+ if (asisreply == null) {\r
+ updateCachedHeaders();\r
+ }\r
+ if (asisreply == null) {\r
+ // not parsed, try to serve it as a normal file\r
+ return super.createDefaultReply(request, status);\r
+ }\r
+ // create the reply with the parsed status\r
+ Reply reply = super.createDefaultReply(request, asisreply.getStatus());\r
+ reply.setReason(asisreply.getReason());\r
+ // and update all defined headers\r
+ Enumeration e = asisreply.enumerateHeaderDescriptions();\r
+ while ( e.hasMoreElements() ) {\r
+ HeaderDescription d = (HeaderDescription) e.nextElement();\r
+ HeaderValue v = asisreply.getHeaderValue(d);\r
+ if ( v != null )\r
+ reply.setHeaderValue(d, v);\r
+ }\r
+ return reply;\r
+ }\r
+\r
+ /**\r
+ * Create the reply relative to the given file.\r
+ * @param request the incomming request.\r
+ * @return A Reply instance\r
+ * @exception ProtocolException If processsing the request failed.\r
+ * @exception ResourceException If the resource got a fatal error.\r
+ */\r
+ protected Reply createFileReply(Request request) \r
+ throws ProtocolException, ResourceException\r
+ {\r
+ File file = fresource.getFile() ;\r
+ Reply reply = null;\r
+ // Won't check for range request, as we don't control the status\r
+ // Default to full reply then\r
+ reply = createDefaultReply(request, HTTP.OK) ;\r
+ try { \r
+ FileInputStream fis = new FileInputStream(file);\r
+ // and escape the headers\r
+ fis.skip(foffset);\r
+ reply.setStream(fis);\r
+ } catch (IOException ex) {\r
+ Reply error = request.makeReply(HTTP.SERVICE_UNAVAILABLE);\r
+ error.setContent(ex.getMessage());\r
+ return error;\r
+ }\r
+ return reply ;\r
+ }\r
+}\r