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