1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.cms.servlets;
35
36 import info.magnolia.cms.util.ClasspathResourcesUtil;
37
38 import java.io.IOException;
39 import java.io.InputStream;
40 import java.net.URL;
41 import java.net.URLConnection;
42 import java.util.Hashtable;
43 import java.util.Map;
44
45 import javax.servlet.ServletException;
46 import javax.servlet.ServletOutputStream;
47 import javax.servlet.http.HttpServlet;
48 import javax.servlet.http.HttpServletRequest;
49 import javax.servlet.http.HttpServletResponse;
50
51 import org.apache.commons.io.IOUtils;
52 import org.apache.commons.lang.StringUtils;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56
57
58
59
60
61
62
63
64
65
66 public class ClasspathSpool extends HttpServlet {
67
68
69
70
71 public static final String MGNL_RESOURCES_ROOT = "/mgnl-resources";
72
73
74
75
76 private static final long serialVersionUID = 222L;
77
78
79
80
81 private static Logger log = LoggerFactory.getLogger(ClasspathSpool.class);
82
83 protected long getLastModified(HttpServletRequest req) {
84 String filePath = this.getFilePath(req);
85 try {
86 URL url = ClasspathResourcesUtil.getResource(MGNL_RESOURCES_ROOT + filePath);
87 if(url != null){
88 URLConnection connection = url.openConnection();
89
90 connection.setDoInput(false);
91 connection.setDoOutput(false);
92
93 long lastModified = connection.getLastModified();
94 InputStream is = null;
95 try{
96 is = connection.getInputStream();
97 }
98 finally{
99 IOUtils.closeQuietly(is);
100 }
101 return lastModified;
102 }
103 }
104 catch (IOException e) {
105
106 }
107
108 return -1;
109 }
110
111
112
113
114
115
116
117 public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
118
119 String filePath = getFilePath(request);
120
121 if (StringUtils.contains(filePath, "*")) {
122 streamMultipleFile(response, filePath);
123 }
124 else if (StringUtils.contains(filePath, "|")) {
125 String[] paths = StringUtils.split(filePath, "|");
126 streamMultipleFile(response, paths);
127 }
128 else {
129 streamSingleFile(response, filePath);
130 }
131 }
132
133 protected String getFilePath(HttpServletRequest request) {
134
135 String filePath = (String) request.getAttribute("javax.servlet.include.path_info");
136
137
138 if (StringUtils.isEmpty(filePath)) {
139 filePath = (String) request.getAttribute("javax.servlet.forward.path_info");
140 }
141
142
143 if (StringUtils.isEmpty(filePath)) {
144 filePath = request.getPathInfo();
145 }
146 return filePath;
147 }
148
149 private Map multipleFilePathsCache;
150
151
152
153
154 public void init() throws ServletException {
155 super.init();
156 multipleFilePathsCache = new Hashtable();
157 }
158
159
160
161
162 public void destroy() {
163 super.destroy();
164 multipleFilePathsCache.clear();
165 }
166
167
168
169
170
171
172
173
174 private void streamMultipleFile(HttpServletResponse response, String filePath) throws IOException {
175 if (log.isDebugEnabled()) {
176 log.debug("aggregating files for request {}", filePath);
177 }
178
179 String[] paths = (String[]) multipleFilePathsCache.get(filePath);
180 if (paths == null) {
181 final String startsWith = MGNL_RESOURCES_ROOT + StringUtils.substringBefore(filePath, "*");
182 final String endssWith = StringUtils.substringAfterLast(filePath, "*");
183
184 paths = ClasspathResourcesUtil.findResources(new ClasspathResourcesUtil.Filter() {
185
186 public boolean accept(String name) {
187 return name.startsWith(startsWith) && name.endsWith(endssWith);
188 }
189 });
190 }
191 multipleFilePathsCache.put(filePath, paths);
192
193 if (paths.length == 0) {
194 response.sendError(HttpServletResponse.SC_NOT_FOUND);
195 return;
196 }
197
198 streamMultipleFile(response, paths);
199 }
200
201
202
203
204
205
206 private void streamMultipleFile(HttpServletResponse response, String[] paths) throws IOException {
207 ServletOutputStream out = response.getOutputStream();
208 InputStream in = null;
209
210 for (int j = 0; j < paths.length; j++) {
211 try {
212 String path = paths[j];
213 if (!path.startsWith(MGNL_RESOURCES_ROOT)) {
214 path = MGNL_RESOURCES_ROOT + path;
215 }
216 in = ClasspathResourcesUtil.getStream(path);
217 if (in != null) {
218 IOUtils.copy(in, out);
219 }
220 }
221 finally {
222 IOUtils.closeQuietly(in);
223 }
224 }
225
226 out.flush();
227 IOUtils.closeQuietly(out);
228 }
229
230
231
232
233
234
235 private void streamSingleFile(HttpServletResponse response, String filePath) throws IOException {
236 InputStream in = null;
237
238
239 try {
240 in = ClasspathResourcesUtil.getStream(MGNL_RESOURCES_ROOT + filePath);
241 }
242 catch (IOException e) {
243 IOUtils.closeQuietly(in);
244 }
245
246 if (in == null) {
247 if (!response.isCommitted()) {
248 response.sendError(HttpServletResponse.SC_NOT_FOUND);
249 }
250 return;
251 }
252
253 try {
254 ServletOutputStream out = response.getOutputStream();
255 IOUtils.copy(in, out);
256 out.flush();
257 IOUtils.closeQuietly(out);
258 }
259 catch (IOException e) {
260
261
262 if (log.isDebugEnabled()) {
263 log.debug("Unable to spool resource due to a {} exception", e.getClass().getName());
264 }
265 if (!response.isCommitted()) {
266 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
267 }
268 }
269 finally {
270 IOUtils.closeQuietly(in);
271 }
272 }
273
274 }