001: /*
002: HttpdBase4J: An embeddable Java web server framework that supports HTTP, HTTPS,
003: templated content and serving content from inside a jar or archive.
004: Copyright (C) 2007 Donald Munro
005:
006: This library is free software; you can redistribute it and/or
007: modify it under the terms of the GNU Lesser General Public
008: License as published by the Free Software Foundation; either
009: version 2.1 of the License, or (at your option) any later version.
010:
011: This library is distributed in the hope that it will be useful,
012: but WITHOUT ANY WARRANTY; without even the implied warranty of
013: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: Lesser General Public License for more details.
015:
016: You should have received a copy of the GNU Lesser General Public
017: License along with this library; if not,see http://www.gnu.org/licenses/lgpl.txt
018: */
019:
020: package net.homeip.donaldm.httpdbase4j;
021:
022: import java.io.FileFilter;
023: import java.io.FileNotFoundException;
024: import java.io.IOException;
025: import java.io.InputStream;
026: import java.io.UnsupportedEncodingException;
027: import java.net.URI;
028: import java.net.URISyntaxException;
029: import java.util.Comparator;
030: import java.util.Date;
031: import java.util.TreeSet;
032:
033: import com.sun.net.httpserver.HttpExchange;
034:
035: import de.schlichtherle.io.File;
036: import de.schlichtherle.io.FileInputStream;
037:
038: /**
039: * Encapsulates an HTTP request for a resource in an archive or
040: * inside a jar in the classpath.
041: * @see net.homeip.donaldm.httpdbase4j.Request
042: * @author Donald Munro
043: */
044: public class ArchiveRequest extends Request implements
045: DirItemInterface, Cloneable
046: //============================================================================
047: {
048: /**
049: * The base directory within the archive containing the web content.
050: */
051: protected File m_homeDir = null;
052:
053: /**
054: * The full path within the archive of the resource.
055: */
056: protected File m_requestFile = null;
057:
058: /**
059: * Constructs a ArchiveRequest.
060: * @param httpd The Httpd instance within which the request occurred.
061: * @see net.homeip.donaldm.httpdbase4j.Httpd
062: * @param ex The HttpExchange instance for this request.
063: * @see com.sun.net.httpserver.HttpExchange
064: * @param archive The archive (jar, zip, tar, tar.gz or tar.bz2) containing the
065: * web content
066: * @param homeArchiveDir The base directory within the compressed file containing
067: * the web content
068: * @throws UnsupportedEncodingException
069: * @throws IOException
070: */
071: public ArchiveRequest(Httpd httpd, HttpExchange ex,
072: java.io.File archive, String homeArchiveDir)
073: throws UnsupportedEncodingException, IOException
074: //---------------------------------------------------------------------
075: {
076: super (httpd, ex);
077: if (!archive.exists())
078: throw new IOException(archive.getAbsolutePath()
079: + " not found");
080: m_homeDir = new File(archive, homeArchiveDir);
081: if (!m_homeDir.exists())
082: throw new IOException(m_homeDir.getAbsolutePath()
083: + " not found.");
084: if ((!m_homeDir.isDirectory()) && (!m_homeDir.isArchive()))
085: throw new IOException(m_homeDir.getAbsolutePath()
086: + "not a directory");
087: m_path = "";
088: m_requestFile = new File(m_homeDir, m_path);
089: }
090:
091: /**
092: * Constructs a ArchiveRequest.
093: * @param httpd The Httpd instance within which the request occurred.
094: * @see net.homeip.donaldm.httpdbase4j.Httpd
095: * @param ex The HttpExchange instance for this request.
096: * @see com.sun.net.httpserver.HttpExchange
097: * @param homeDir The base directory within the compressed file containing
098: * the web resources. Must be an instance of a TrueZip File ie
099: * de.schlichtherle.io.File
100: * @throws UnsupportedEncodingException
101: * @throws IOException
102: */
103: public ArchiveRequest(Httpd httpd, HttpExchange ex, File homeDir)
104: throws UnsupportedEncodingException, IOException
105: //---------------------------------------------------------------------
106: {
107: super (httpd, ex);
108: m_homeDir = homeDir;
109: m_requestFile = new File(m_homeDir, m_path);
110: }
111:
112: /**
113: * Constructs a ArchiveRequest.
114: * @param httpd The Httpd instance within which the request occurred.
115: * @see net.homeip.donaldm.httpdbase4j.Httpd
116: * @param ex The HttpExchange instance for this request.
117: * @see com.sun.net.httpserver.HttpExchange
118: * @param homeDir The base directory within the compressed file containing
119: * the web resources. Must be an instance of a TrueZip File ie
120: * @param fileName Name of file
121: * @throws UnsupportedEncodingException
122: * @throws IOException
123: */
124: public ArchiveRequest(Httpd httpd, HttpExchange ex, File homeDir,
125: String fileName) throws UnsupportedEncodingException,
126: IOException
127: //---------------------------------------------------------------------
128: {
129: super (httpd, ex);
130: m_homeDir = homeDir;
131: String s = homeDir.getInnerEntryName();
132: if ((fileName != null) && (fileName.indexOf('/') >= 0)) {
133: if (fileName.startsWith(s)) {
134: int p = s.length();
135: m_path = s.substring(p);
136: } else
137: m_path = fileName;
138: }
139: if (m_path.startsWith("/")) {
140: if (m_path.length() > 1)
141: m_path = m_path.substring(1);
142: else
143: m_path = "";
144: }
145: m_requestFile = new File(m_homeDir, m_path);
146: }
147:
148: /**
149: * Copy constructs a ArchiveRequest with a new file.
150: * If fileName is not null then assumes that request is a directory.
151: * @param request The ArchiveRequest instance to copy
152: * @param fileName Name of file
153: * @throws UnsupportedEncodingException
154: * @throws IOException
155: * @throws URISyntaxException
156: */
157: public ArchiveRequest(ArchiveRequest request, String fileName)
158: throws UnsupportedEncodingException, IOException,
159: URISyntaxException
160: //---------------------------------------------------------
161: {
162: super (request);
163: m_homeDir = request.m_homeDir;
164: if (fileName != null) {
165: if ((fileName.compareTo(".") == 0)
166: || (fileName.startsWith("./"))) {
167: File requestFile = request.m_requestFile;
168: if (!request.isDirectory())
169: requestFile = new File(request.getDir());
170: fileName = fileName.replaceFirst("\\.", requestFile
171: .getInnerEntryName());
172: }
173: String s = m_homeDir.getInnerEntryName();
174: if ((s != null) && (fileName.startsWith(s))) {
175: int p = s.length();
176: fileName = fileName.substring(p);
177: if (fileName.length() == 0)
178: fileName = "/";
179: }
180: } else
181: fileName = "";
182: fileName = fileName.trim();
183: if (fileName.length() == 0)
184: fileName = "/";
185: if (fileName.startsWith("/")) {
186: if (fileName.length() > 1)
187: m_path = fileName.substring(1);
188: else
189: m_path = "";
190: } else
191: m_path = m_path
192: + (((m_path.length() > 0) && (!m_path.endsWith("/"))) ? "/"
193: : "") + fileName;
194: //m_path = request.m_path;
195: m_requestFile = new File(m_homeDir, m_path);
196: m_uri = new URI(m_uri.getScheme(), m_uri.getUserInfo(), m_uri
197: .getHost(), m_uri.getPort(), m_path, m_uri.getQuery(),
198: m_uri.getFragment());
199: }
200:
201: /**
202: * @inheritDoc
203: */
204: @Override
205: public long getContentLength()
206: //----------------------------
207: {
208: if (m_cacheFile != null)
209: m_contentLength = m_cacheFile.length();
210: else
211: m_contentLength = m_requestFile.length();
212: return m_contentLength;
213: }
214:
215: /**
216: * @inheritDoc
217: */
218: @Override
219: public InputStream getStream()
220: //----------------------------
221: {
222: return getStream(true);
223: }
224:
225: /**
226: * @inheritDoc
227: */
228: @Override
229: public InputStream getStream(boolean isEncoded)
230: //---------------------------------------------
231: {
232: if ((!isEncoded) || (m_cacheFile == null)) {
233: try {
234: return new FileInputStream(m_requestFile);
235: } catch (Exception e) {
236: return null;
237: }
238: } else {
239: try {
240: return new FileInputStream(m_cacheFile);
241: } catch (Exception e) {
242: m_requestHeaders.add("Pragma", "no-cache");
243: m_encoding = null;
244: try {
245: return new FileInputStream(m_requestFile);
246: } catch (Exception ee) {
247: return null;
248: }
249: }
250: }
251: }
252:
253: /**
254: * @inheritDoc
255: */
256: @Override
257: public boolean exists()
258: //---------------------
259: {
260: return m_requestFile.exists();
261:
262: }
263:
264: /**
265: * @inheritDoc
266: */
267: @Override
268: public boolean isReadable()
269: //-------------------------
270: {
271: return m_requestFile.exists();
272: }
273:
274: /**
275: * @inheritDoc
276: */
277: @Override
278: public boolean isDirectory()
279: //-----------------------------
280: {
281: return ((m_requestFile.isDirectory()) || (m_requestFile
282: .isArchive()));
283: }
284:
285: /**
286: * @inheritDoc
287: */
288: @Override
289: public String getAbsolutePath()
290: //-----------------------------
291: {
292: return m_requestFile.getInnerEntryName();
293: }
294:
295: /**
296: * @inheritDoc
297: */
298: @Override
299: protected HttpHandleable getHandler()
300: //-----------------------------------
301: {
302: HttpHandleable handler = null;
303: String extension = Http.getExtension(m_requestFile);
304: if ((extension != null) && (extension.trim().length() > 0))
305: handler = m_httpd.getHandler(extension);
306: if (handler == null)
307: handler = m_httpd;
308: return handler;
309: }
310:
311: /**
312: * @inheritDoc
313: */
314: @Override
315: protected Postable getPostHandler()
316: //---------------------------------
317: {
318: Postable postHandler = null;
319: String extension = Http.getExtension(m_requestFile);
320: if ((extension != null) && (extension.trim().length() > 0))
321: postHandler = m_httpd.m_postHandlerMap.get(extension);
322: Postable pst = m_httpd.m_postHandlerMap.get(m_uri.getPath());
323: if (pst == null) // be nice to people who forget abouty the leading slash
324: pst = m_httpd.m_postHandlerMap.get("/" + m_uri.getPath());
325: if (pst != null) // url handler has priority over extension
326: postHandler = pst;
327: if (postHandler == null)
328: postHandler = m_httpd;
329: return postHandler;
330: }
331:
332: /**
333: * @inheritDoc
334: */
335: @Override
336: public Object clone() throws CloneNotSupportedException
337: //-----------------------------------------------------
338: {
339: ArchiveRequest klone = (ArchiveRequest) super .clone();
340: klone.m_homeDir = m_homeDir;
341: klone.m_requestFile = m_requestFile;
342: return klone;
343: }
344:
345: /**
346: * @inheritDoc
347: */
348: @Override
349: public String getName()
350: //--------------------
351: {
352: return m_requestFile.getName();
353: }
354:
355: /**
356: * @inheritDoc
357: */
358: @Override
359: public String getExtension()
360: //--------------------------
361: {
362: return Http.getExtension(m_requestFile);
363: }
364:
365: /**
366: * @inheritDoc
367: */
368: @Override
369: public String getDir()
370: //--------------------
371: {
372: File parent = new File(m_requestFile.getParent());
373: return parent.getInnerEntryName();
374: }
375:
376: /**
377: * @inheritDoc
378: */
379: @Override
380: public Request getDirRequest()
381: //----------------------------
382: {
383: try {
384: return new ArchiveRequest(this , getDir());
385: } catch (Exception e) {
386: return null;
387: }
388: }
389:
390: /**
391: * @inheritDoc
392: */
393: @Override
394: public Request getChildRequest(String name)
395: //---------------------------------------------
396: {
397: if (!this .isDirectory())
398: return null;
399: try {
400: return new ArchiveRequest(this , name);
401: } catch (Exception e) {
402: return null;
403: }
404: }
405:
406: static class DirItem implements DirItemInterface
407: //==============================================
408: {
409: File m_file;
410:
411: public DirItem(File f) {
412: m_file = f;
413: }
414:
415: public String getName() {
416: return m_file.getInnerEntryName();
417: }
418:
419: public long getSize() {
420: return m_file.length();
421: }
422:
423: public Date getDate() {
424: return new Date(m_file.lastModified());
425: }
426:
427: public boolean isDirectory() {
428: return m_file.isDirectory();
429: }
430:
431: public InputStream getStream() {
432: try {
433: return new FileInputStream(m_file);
434: } catch (FileNotFoundException ex) {
435: return null;
436: }
437: }
438: }
439:
440: /**
441: * @inheritDoc
442: */
443: @Override
444: public String getETag(boolean refresh)
445: //---------------------
446: {
447: if ((!refresh) && (m_eTag != null))
448: return m_eTag;
449: DirItemInterface f = new DirItem(m_requestFile);
450: m_eTag = Http.eTag(f);
451: return m_eTag;
452: }
453:
454: private TreeSet<DirItemInterface> _readDir(File directory,
455: final boolean isDirs, final DirItemInterface.SORTBY sortBy)
456: //------------------------------------------------------------------------
457: {
458: File[] files = (de.schlichtherle.io.File[]) directory
459: .listFiles(new FileFilter() {
460: public boolean accept(java.io.File f) {
461: if (isDirs)
462: return f.isDirectory();
463: else
464: return f.isFile();
465: }
466: });
467:
468: TreeSet<DirItemInterface> set = new TreeSet<DirItemInterface>(
469: new Comparator<DirItemInterface>()
470: //--------------------------------
471: {
472: public int compare(DirItemInterface di1,
473: DirItemInterface di2) {
474: switch (sortBy) {
475: case NAME:
476: return di1.getName().compareTo(
477: di2.getName());
478:
479: case SIZE:
480: if (di1.getSize() < di2.getSize())
481: return -1;
482: else if (di1.getSize() > di2.getSize())
483: return 1;
484: else
485: return 0;
486:
487: case DATE:
488: return (di1.getDate().compareTo(di2
489: .getDate()));
490: }
491: return 0;
492: }
493: });
494: for (int i = 0; i < files.length; i++) {
495: File f = files[i];
496: DirItem dirItem = new DirItem(f);
497: set.add(dirItem);
498: }
499: return set;
500: }
501:
502: /**
503: * @inheritDoc
504: */
505: @Override
506: public TreeSet<DirItemInterface> getDirListFiles(
507: DirItemInterface.SORTBY sortBy)
508: //----------------------------------------------------------------------------
509: {
510: if (!isDirectory())
511: return null;
512: return _readDir(m_requestFile, false, sortBy);
513: }
514:
515: /**
516: * @inheritDoc
517: */
518: @Override
519: public TreeSet<DirItemInterface> getDirListDirectories(
520: DirItemInterface.SORTBY sortBy)
521: //----------------------------------------------------------------------------
522: {
523: if (!isDirectory())
524: return null;
525: return _readDir(m_requestFile, true, sortBy);
526: }
527:
528: @Override
529: public String toString()
530: //----------------------
531: {
532: StringBuffer sb = new StringBuffer();
533: sb.append("Base :"
534: + ((m_homeDir == null) ? "Unknown" : m_homeDir));
535: sb.append(Httpd.EOL);
536: sb.append("Path :"
537: + ((m_requestFile == null) ? "Unknown" : m_requestFile
538: .getAbsolutePath()));
539: sb.append(Httpd.EOL);
540: return super .toString() + Httpd.EOL + sb.toString();
541: }
542:
543: public Date getDate()
544: //--------------------
545: {
546: return new Date(m_requestFile.lastModified());
547: }
548:
549: public long getSize()
550: //-------------------
551: {
552: return m_requestFile.length();
553: }
554: }
|