001: /*
002: * This file is part of PFIXCORE.
003: *
004: * PFIXCORE is free software; you can redistribute it and/or modify
005: * it under the terms of the GNU Lesser General Public License as published by
006: * the Free Software Foundation; either version 2 of the License, or
007: * (at your option) any later version.
008: *
009: * PFIXCORE is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public License
015: * along with PFIXCORE; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: */
018:
019: package de.schlund.pfixxml;
020:
021: import java.io.BufferedInputStream;
022: import java.io.BufferedOutputStream;
023: import java.io.File;
024: import java.io.FileInputStream;
025: import java.io.FileNotFoundException;
026: import java.io.IOException;
027: import java.io.InputStream;
028: import java.io.OutputStream;
029: import java.util.ArrayList;
030: import java.util.List;
031: import java.util.StringTokenizer;
032:
033: import javax.servlet.ServletException;
034: import javax.servlet.http.HttpServlet;
035: import javax.servlet.http.HttpServletRequest;
036: import javax.servlet.http.HttpServletResponse;
037:
038: import de.schlund.pfixxml.resources.ResourceUtil;
039:
040: /**
041: * In standalone mode this servlet serves the static files from the docroot.
042: * In all modes, it serves files from the webapplication directory below
043: * /xml because they would usually be masked by the files within the docroot.
044: *
045: * @author Sebastian Marsching <sebastian.marsching@1und1.de>
046: */
047: public class DocrootServlet extends HttpServlet {
048: private String base;
049:
050: private String defaultpath;
051:
052: private List<String> passthroughPaths;
053:
054: protected void doGet(HttpServletRequest req, HttpServletResponse res)
055: throws ServletException, IOException {
056:
057: boolean docrootMode;
058:
059: // Get path and determine whether to deliver files from
060: // webapplication or docroot directory
061: String path = req.getPathInfo();
062:
063: if (path != null) {
064: docrootMode = false;
065: } else {
066: path = req.getServletPath();
067: docrootMode = true;
068: }
069:
070: // Handle default (root) request
071: if (docrootMode
072: && this .defaultpath != null
073: && (path == null || path.length() == 0 || path
074: .equals("/"))) {
075: res.sendRedirect(req.getContextPath() + this .defaultpath);
076: return;
077: }
078:
079: // Avoid path traversal and access to config or source files
080: if (path.contains("..") || path.startsWith("/WEB-INF")) {
081: res.sendError(HttpServletResponse.SC_NOT_FOUND, path);
082: return;
083: }
084:
085: // Directory listing is not allowed
086: if (path.endsWith("/")) {
087: res.sendError(HttpServletResponse.SC_FORBIDDEN, path);
088: return;
089: }
090:
091: try {
092: // Docroot is set by context, so if we are in
093: // WAR mode, the docroot will not be available
094: // and we simply skip to the webapp directory
095: if (docrootMode && (base == null || base.length() == 0)) {
096: docrootMode = false;
097: }
098:
099: InputStream in = null;
100:
101: if (docrootMode) {
102: if (passthroughPaths != null) {
103: for (String prefix : this .passthroughPaths) {
104: if (path.startsWith(prefix)) {
105: in = ResourceUtil
106: .getFileResourceFromDocroot(path)
107: .getInputStream();
108: }
109: }
110: }
111:
112: if (in == null) {
113: File file = new File(base, path);
114: in = new BufferedInputStream(new FileInputStream(
115: file));
116: }
117: } else {
118: // Use getResourceAsStream() to make sure we can
119: // access the file even in packed WAR mode
120: in = getServletContext().getResourceAsStream(path);
121: if (in == null) {
122: throw new FileNotFoundException();
123: }
124: }
125:
126: String type = getServletContext().getMimeType(path);
127: if (type == null) {
128: type = "application/octet-stream";
129: }
130: res.setContentType(type);
131:
132: OutputStream out = new BufferedOutputStream(res
133: .getOutputStream());
134:
135: int bytes_read;
136: byte[] buffer = new byte[8];
137: while ((bytes_read = in.read(buffer)) != -1) {
138: out.write(buffer, 0, bytes_read);
139: }
140: out.flush();
141: in.close();
142: out.close();
143:
144: } catch (FileNotFoundException e) {
145: res.sendError(HttpServletResponse.SC_NOT_FOUND, path);
146: }
147: }
148:
149: public void init() throws ServletException {
150: // In standalone mode, the context sets a parameter
151: // containing the path to the docroot
152: this .base = this .getServletContext().getInitParameter(
153: "staticDocBase");
154:
155: this .defaultpath = null;
156: String temp = this .getInitParameter("defaultpath");
157: if (temp != null && temp.length() > 0) {
158: if (temp.charAt(0) != '/') {
159: temp = "/" + temp;
160: }
161: if (temp.length() > 1) {
162: this .defaultpath = temp;
163: }
164: }
165:
166: // Create a list of passthrough paths
167: String passthroughParam = this
168: .getInitParameter("passthroughPaths");
169: if (passthroughParam != null && passthroughParam.length() > 0) {
170: ArrayList<String> passthroughPaths = new ArrayList<String>();
171: StringTokenizer st = new StringTokenizer(passthroughParam,
172: ":");
173: while (st.hasMoreTokens()) {
174: String token = st.nextToken().trim();
175: if (token.length() > 0) {
176: if (token.charAt(0) != '/') {
177: token = "/" + token;
178: }
179: if (token.charAt(token.length() - 1) != '/') {
180: token = token + "/";
181: }
182: passthroughPaths.add(token);
183: }
184: }
185: this.passthroughPaths = passthroughPaths;
186: }
187: }
188:
189: }
|