KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > catalina > ssi > SSIServletExternalResolver


1 /*
2  * Copyright 1999,2004 The Apache Software Foundation. Licensed under the
3  * Apache License, Version 2.0 (the "License"); you may not use this file
4  * except in compliance with the License. You may obtain a copy of the License
5  * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable
6  * law or agreed to in writing, software distributed under the License is
7  * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
8  * KIND, either express or implied. See the License for the specific language
9  * governing permissions and limitations under the License.
10  */

11 package org.apache.catalina.ssi;
12
13
14 import java.io.IOException JavaDoc;
15 import java.io.UnsupportedEncodingException JavaDoc;
16 import java.net.URL JavaDoc;
17 import java.net.URLConnection JavaDoc;
18 import java.net.URLDecoder JavaDoc;
19 import java.util.Collection JavaDoc;
20 import java.util.Date JavaDoc;
21 import java.util.Enumeration JavaDoc;
22 import javax.servlet.RequestDispatcher JavaDoc;
23 import javax.servlet.ServletContext JavaDoc;
24 import javax.servlet.ServletException JavaDoc;
25 import javax.servlet.http.HttpServletRequest JavaDoc;
26 import javax.servlet.http.HttpServletResponse JavaDoc;
27 import org.apache.catalina.connector.Request;
28 import org.apache.coyote.Constants;
29
30 /**
31  * An implementation of SSIExternalResolver that is used with servlets.
32  *
33  * @author Dan Sandberg
34  * @author David Becker
35  * @version $Revision: 467222 $, $Date: 2006-10-24 05:17:11 +0200 (mar., 24 oct. 2006) $
36  */

37 public class SSIServletExternalResolver implements SSIExternalResolver {
38     protected final String JavaDoc VARIABLE_NAMES[] = {"AUTH_TYPE", "CONTENT_LENGTH",
39             "CONTENT_TYPE", "DOCUMENT_NAME", "DOCUMENT_URI",
40             "GATEWAY_INTERFACE", "HTTP_ACCEPT", "HTTP_ACCEPT_ENCODING",
41             "HTTP_ACCEPT_LANGUAGE", "HTTP_CONNECTION", "HTTP_HOST",
42             "HTTP_REFERER", "HTTP_USER_AGENT", "PATH_INFO", "PATH_TRANSLATED",
43             "QUERY_STRING", "QUERY_STRING_UNESCAPED", "REMOTE_ADDR",
44             "REMOTE_HOST", "REMOTE_PORT", "REMOTE_USER", "REQUEST_METHOD",
45             "REQUEST_URI", "SCRIPT_FILENAME", "SCRIPT_NAME", "SERVER_ADDR",
46             "SERVER_NAME", "SERVER_PORT", "SERVER_PROTOCOL", "SERVER_SOFTWARE",
47             "UNIQUE_ID"};
48     protected ServletContext JavaDoc context;
49     protected HttpServletRequest JavaDoc req;
50     protected HttpServletResponse JavaDoc res;
51     protected boolean isVirtualWebappRelative;
52     protected int debug;
53     protected String JavaDoc inputEncoding;
54
55     public SSIServletExternalResolver(ServletContext JavaDoc context,
56             HttpServletRequest JavaDoc req, HttpServletResponse JavaDoc res,
57             boolean isVirtualWebappRelative, int debug, String JavaDoc inputEncoding) {
58         this.context = context;
59         this.req = req;
60         this.res = res;
61         this.isVirtualWebappRelative = isVirtualWebappRelative;
62         this.debug = debug;
63         this.inputEncoding = inputEncoding;
64     }
65
66
67     public void log(String JavaDoc message, Throwable JavaDoc throwable) {
68         //We can't assume that Servlet.log( message, null )
69
//is the same as Servlet.log( message ), since API
70
//doesn't seem to say so.
71
if (throwable != null) {
72             context.log(message, throwable);
73         } else {
74             context.log(message);
75         }
76     }
77
78
79     public void addVariableNames(Collection JavaDoc variableNames) {
80         for (int i = 0; i < VARIABLE_NAMES.length; i++) {
81             String JavaDoc variableName = VARIABLE_NAMES[i];
82             String JavaDoc variableValue = getVariableValue(variableName);
83             if (variableValue != null) {
84                 variableNames.add(variableName);
85             }
86         }
87         Enumeration JavaDoc e = req.getAttributeNames();
88         while (e.hasMoreElements()) {
89             String JavaDoc name = (String JavaDoc)e.nextElement();
90             if (!isNameReserved(name)) {
91                 variableNames.add(name);
92             }
93         }
94     }
95
96
97     protected Object JavaDoc getReqAttributeIgnoreCase(String JavaDoc targetName) {
98         Object JavaDoc object = null;
99         if (!isNameReserved(targetName)) {
100             object = req.getAttribute(targetName);
101             if (object == null) {
102                 Enumeration JavaDoc e = req.getAttributeNames();
103                 while (e.hasMoreElements()) {
104                     String JavaDoc name = (String JavaDoc)e.nextElement();
105                     if (targetName.equalsIgnoreCase(name)
106                             && !isNameReserved(name)) {
107                         object = req.getAttribute(name);
108                         if (object != null) {
109                             break;
110                         }
111                     }
112                 }
113             }
114         }
115         return object;
116     }
117
118
119     protected boolean isNameReserved(String JavaDoc name) {
120         return name.startsWith("java.") || name.startsWith("javax.")
121                 || name.startsWith("sun.");
122     }
123
124
125     public void setVariableValue(String JavaDoc name, String JavaDoc value) {
126         if (!isNameReserved(name)) {
127             req.setAttribute(name, value);
128         }
129     }
130
131
132     public String JavaDoc getVariableValue(String JavaDoc name) {
133         String JavaDoc retVal = null;
134         Object JavaDoc object = getReqAttributeIgnoreCase(name);
135         if (object != null) {
136             retVal = object.toString();
137         } else {
138             retVal = getCGIVariable(name);
139         }
140         return retVal;
141     }
142
143
144     protected String JavaDoc getCGIVariable(String JavaDoc name) {
145         String JavaDoc retVal = null;
146         String JavaDoc[] nameParts = name.toUpperCase().split("_");
147         int requiredParts = 2;
148         if (nameParts.length == 1) {
149             if (nameParts[0].equals("PATH")) {
150                 requiredParts = 1;
151                 retVal = null; // Not implemented
152
}
153         }
154         else if (nameParts[0].equals("AUTH")) {
155             if (nameParts[1].equals("TYPE")) {
156                 retVal = req.getAuthType();
157             }
158         } else if(nameParts[0].equals("CONTENT")) {
159             if (nameParts[1].equals("LENGTH")) {
160                 int contentLength = req.getContentLength();
161                 if (contentLength >= 0) {
162                     retVal = Integer.toString(contentLength);
163                 }
164             } else if (nameParts[1].equals("TYPE")) {
165                 retVal = req.getContentType();
166             }
167         } else if (nameParts[0].equals("DOCUMENT")) {
168             if (nameParts[1].equals("NAME")) {
169                 String JavaDoc requestURI = req.getRequestURI();
170                 retVal = requestURI.substring(requestURI.lastIndexOf('/') + 1);
171             } else if (nameParts[1].equals("URI")) {
172                 retVal = req.getRequestURI();
173             }
174         } else if (name.equalsIgnoreCase("GATEWAY_INTERFACE")) {
175             retVal = "CGI/1.1";
176         } else if (nameParts[0].equals("HTTP")) {
177             if (nameParts[1].equals("ACCEPT")) {
178                 String JavaDoc accept = null;
179                 if (nameParts.length == 2) {
180                     accept = "Accept";
181                 } else if (nameParts[2].equals("ENCODING")) {
182                     requiredParts = 3;
183                     accept = "Accept-Encoding";
184                 } else if (nameParts[2].equals("LANGUAGE")) {
185                     requiredParts = 3;
186                     accept = "Accept-Language";
187                 }
188                 if (accept != null) {
189                     Enumeration JavaDoc acceptHeaders = req.getHeaders(accept);
190                     if (acceptHeaders != null)
191                         if (acceptHeaders.hasMoreElements()) {
192                             StringBuffer JavaDoc rv = new StringBuffer JavaDoc(
193                                     (String JavaDoc) acceptHeaders.nextElement());
194                             while (acceptHeaders.hasMoreElements()) {
195                                 rv.append(", ");
196                                 rv.append((String JavaDoc) acceptHeaders.nextElement());
197                             }
198                         retVal = rv.toString();
199                     }
200                 }
201             }
202             else if (nameParts[1].equals("CONNECTION")) {
203                 retVal = req.getHeader("Connection");
204             }
205             else if (nameParts[1].equals("HOST")) {
206                 retVal = req.getHeader("Host");
207             }
208             else if (nameParts[1].equals("REFERER")) {
209                 retVal = req.getHeader("Referer");
210             }
211             else if (nameParts[1].equals("USER"))
212                 if (nameParts.length == 3)
213                     if (nameParts[2].equals("AGENT")) {
214                         requiredParts = 3;
215                         retVal = req.getHeader("User-Agent");
216                     }
217
218         } else if (nameParts[0].equals("PATH")) {
219             if (nameParts[1].equals("INFO")) {
220                 retVal = req.getPathInfo();
221             } else if (nameParts[1].equals("TRANSLATED")) {
222                 retVal = req.getPathTranslated();
223             }
224         } else if (nameParts[0].equals("QUERY")) {
225             if (nameParts[1].equals("STRING")) {
226                 String JavaDoc queryString = req.getQueryString();
227                 if (nameParts.length == 2) {
228                     //apache displays this as an empty string rather than (none)
229
retVal = nullToEmptyString(queryString);
230                 } else if (nameParts[2].equals("UNESCAPED")) {
231                     requiredParts = 3;
232                     if (queryString != null) {
233                         // Use default as a last resort
234
String JavaDoc queryStringEncoding =
235                             Constants.DEFAULT_CHARACTER_ENCODING;
236                 
237                         String JavaDoc uriEncoding = null;
238                         boolean useBodyEncodingForURI = false;
239                 
240                         // Get encoding settings from request / connector if
241
// possible
242
String JavaDoc requestEncoding = req.getCharacterEncoding();
243                         if (req instanceof Request JavaDoc) {
244                             uriEncoding =
245                                 ((Request JavaDoc)req).getConnector().getURIEncoding();
246                             useBodyEncodingForURI = ((Request JavaDoc)req)
247                                     .getConnector().getUseBodyEncodingForURI();
248                         }
249                 
250                         // If valid, apply settings from request / connector
251
if (uriEncoding != null) {
252                             queryStringEncoding = uriEncoding;
253                         } else if(useBodyEncodingForURI) {
254                             if (requestEncoding != null) {
255                                 queryStringEncoding = requestEncoding;
256                             }
257                         }
258                 
259                         try {
260                             retVal = URLDecoder.decode(queryString,
261                                     queryStringEncoding);
262                         } catch (UnsupportedEncodingException JavaDoc e) {
263                             retVal = queryString;
264                         }
265                     }
266                 }
267             }
268         } else if(nameParts[0].equals("REMOTE")) {
269             if (nameParts[1].equals("ADDR")) {
270                 retVal = req.getRemoteAddr();
271             } else if (nameParts[1].equals("HOST")) {
272                 retVal = req.getRemoteHost();
273             } else if (nameParts[1].equals("IDENT")) {
274                 retVal = null; // Not implemented
275
} else if (nameParts[1].equals("PORT")) {
276                 retVal = Integer.toString( req.getRemotePort());
277             } else if (nameParts[1].equals("USER")) {
278                 retVal = req.getRemoteUser();
279             }
280         } else if(nameParts[0].equals("REQUEST")) {
281             if (nameParts[1].equals("METHOD")) {
282                 retVal = req.getMethod();
283             }
284             else if (nameParts[1].equals("URI")) {
285                 // If this is an error page, get the original URI
286
retVal = (String JavaDoc) req.getAttribute(
287                         "javax.servlet.forward.request_uri");
288                 if (retVal == null) retVal=req.getRequestURI();
289             }
290         } else if (nameParts[0].equals("SCRIPT")) {
291             String JavaDoc scriptName = req.getServletPath();
292             if (nameParts[1].equals("FILENAME")) {
293                 retVal = context.getRealPath(scriptName);
294             }
295             else if (nameParts[1].equals("NAME")) {
296                 retVal = scriptName;
297             }
298         } else if (nameParts[0].equals("SERVER")) {
299             if (nameParts[1].equals("ADDR")) {
300                 retVal = req.getLocalAddr();
301             }
302             if (nameParts[1].equals("NAME")) {
303                 retVal = req.getServerName();
304             } else if (nameParts[1].equals("PORT")) {
305                 retVal = Integer.toString(req.getServerPort());
306             } else if (nameParts[1].equals("PROTOCOL")) {
307                 retVal = req.getProtocol();
308             } else if (nameParts[1].equals("SOFTWARE")) {
309                 StringBuffer JavaDoc rv = new StringBuffer JavaDoc(context.getServerInfo());
310                 rv.append(" ");
311                 rv.append(System.getProperty("java.vm.name"));
312                 rv.append("/");
313                 rv.append(System.getProperty("java.vm.version"));
314                 rv.append(" ");
315                 rv.append(System.getProperty("os.name"));
316                 retVal = rv.toString();
317             }
318         } else if (name.equalsIgnoreCase("UNIQUE_ID")) {
319             retVal = req.getRequestedSessionId();
320         }
321         if (requiredParts != nameParts.length) return null;
322             return retVal;
323     }
324
325     public Date JavaDoc getCurrentDate() {
326         return new Date JavaDoc();
327     }
328
329
330     protected String JavaDoc nullToEmptyString(String JavaDoc string) {
331         String JavaDoc retVal = string;
332         if (retVal == null) {
333             retVal = "";
334         }
335         return retVal;
336     }
337
338
339     protected String JavaDoc getPathWithoutFileName(String JavaDoc servletPath) {
340         String JavaDoc retVal = null;
341         int lastSlash = servletPath.lastIndexOf('/');
342         if (lastSlash >= 0) {
343             //cut off file namee
344
retVal = servletPath.substring(0, lastSlash + 1);
345         }
346         return retVal;
347     }
348
349
350     protected String JavaDoc getPathWithoutContext(String JavaDoc servletPath) {
351         String JavaDoc retVal = null;
352         int secondSlash = servletPath.indexOf('/', 1);
353         if (secondSlash >= 0) {
354             //cut off context
355
retVal = servletPath.substring(secondSlash);
356         }
357         return retVal;
358     }
359
360
361     protected String JavaDoc getAbsolutePath(String JavaDoc path) throws IOException JavaDoc {
362         String JavaDoc pathWithoutContext = SSIServletRequestUtil.getRelativePath(req);
363         String JavaDoc prefix = getPathWithoutFileName(pathWithoutContext);
364         if (prefix == null) {
365             throw new IOException JavaDoc("Couldn't remove filename from path: "
366                     + pathWithoutContext);
367         }
368         String JavaDoc fullPath = prefix + path;
369         String JavaDoc retVal = SSIServletRequestUtil.normalize(fullPath);
370         if (retVal == null) {
371             throw new IOException JavaDoc("Normalization yielded null on path: "
372                     + fullPath);
373         }
374         return retVal;
375     }
376
377
378     protected ServletContextAndPath getServletContextAndPathFromNonVirtualPath(
379             String JavaDoc nonVirtualPath) throws IOException JavaDoc {
380         if (nonVirtualPath.startsWith("/") || nonVirtualPath.startsWith("\\")) {
381             throw new IOException JavaDoc("A non-virtual path can't be absolute: "
382                     + nonVirtualPath);
383         }
384         if (nonVirtualPath.indexOf("../") >= 0) {
385             throw new IOException JavaDoc("A non-virtual path can't contain '../' : "
386                     + nonVirtualPath);
387         }
388         String JavaDoc path = getAbsolutePath(nonVirtualPath);
389         ServletContextAndPath csAndP = new ServletContextAndPath(
390                 context, path);
391         return csAndP;
392     }
393
394
395     protected ServletContextAndPath getServletContextAndPathFromVirtualPath(
396             String JavaDoc virtualPath) throws IOException JavaDoc {
397
398         if (!virtualPath.startsWith("/") && !virtualPath.startsWith("\\")) {
399             return new ServletContextAndPath(context,
400                     getAbsolutePath(virtualPath));
401         } else {
402             String JavaDoc normalized = SSIServletRequestUtil.normalize(virtualPath);
403             if (isVirtualWebappRelative) {
404                 return new ServletContextAndPath(context, normalized);
405             } else {
406                 ServletContext JavaDoc normContext = context.getContext(normalized);
407                 if (normContext == null) {
408                     throw new IOException JavaDoc("Couldn't get context for path: "
409                             + normalized);
410                 }
411                 //If it's the root context, then there is no context element
412
// to remove,
413
// ie:
414
// '/file1.shtml' vs '/appName1/file1.shtml'
415
if (!isRootContext(normContext)) {
416                     String JavaDoc noContext = getPathWithoutContext(normalized);
417                     if (noContext == null) {
418                         throw new IOException JavaDoc(
419                                 "Couldn't remove context from path: "
420                                         + normalized);
421                     }
422                     return new ServletContextAndPath(normContext, noContext);
423                 } else {
424                     return new ServletContextAndPath(normContext, normalized);
425                 }
426             }
427         }
428     }
429
430
431     //Assumes servletContext is not-null
432
//Assumes that identity comparison will be true for the same context
433
//Assuming the above, getContext("/") will be non-null as long as the root
434
// context is
435
// accessible.
436
//If it isn't, then servletContext can't be the root context anyway, hence
437
// they will
438
// not match.
439
protected boolean isRootContext(ServletContext JavaDoc servletContext) {
440         return servletContext == servletContext.getContext("/");
441     }
442
443
444     protected ServletContextAndPath getServletContextAndPath(
445             String JavaDoc originalPath, boolean virtual) throws IOException JavaDoc {
446         ServletContextAndPath csAndP = null;
447         if (debug > 0) {
448             log("SSIServletExternalResolver.getServletContextAndPath( "
449                     + originalPath + ", " + virtual + ")", null);
450         }
451         if (virtual) {
452             csAndP = getServletContextAndPathFromVirtualPath(originalPath);
453         } else {
454             csAndP = getServletContextAndPathFromNonVirtualPath(originalPath);
455         }
456         return csAndP;
457     }
458
459
460     protected URLConnection JavaDoc getURLConnection(String JavaDoc originalPath,
461             boolean virtual) throws IOException JavaDoc {
462         ServletContextAndPath csAndP = getServletContextAndPath(originalPath,
463                 virtual);
464         ServletContext JavaDoc context = csAndP.getServletContext();
465         String JavaDoc path = csAndP.getPath();
466         URL JavaDoc url = context.getResource(path);
467         if (url == null) {
468             throw new IOException JavaDoc("Context did not contain resource: " + path);
469         }
470         URLConnection JavaDoc urlConnection = url.openConnection();
471         return urlConnection;
472     }
473
474
475     public long getFileLastModified(String JavaDoc path, boolean virtual)
476             throws IOException JavaDoc {
477         long lastModified = 0;
478         try {
479             URLConnection JavaDoc urlConnection = getURLConnection(path, virtual);
480             lastModified = urlConnection.getLastModified();
481         } catch (IOException JavaDoc e) {
482             // Ignore this. It will always fail for non-file based includes
483
}
484         return lastModified;
485     }
486
487
488     public long getFileSize(String JavaDoc path, boolean virtual) throws IOException JavaDoc {
489         long fileSize = -1;
490         try {
491             URLConnection JavaDoc urlConnection = getURLConnection(path, virtual);
492             fileSize = urlConnection.getContentLength();
493         } catch (IOException JavaDoc e) {
494             // Ignore this. It will always fail for non-file based includes
495
}
496         return fileSize;
497     }
498
499
500     //We are making lots of unnecessary copies of the included data here. If
501
//someone ever complains that this is slow, we should connect the included
502
// stream to the print writer that SSICommand uses.
503
public String JavaDoc getFileText(String JavaDoc originalPath, boolean virtual)
504             throws IOException JavaDoc {
505         try {
506             ServletContextAndPath csAndP = getServletContextAndPath(
507                     originalPath, virtual);
508             ServletContext JavaDoc context = csAndP.getServletContext();
509             String JavaDoc path = csAndP.getPath();
510             RequestDispatcher JavaDoc rd = context.getRequestDispatcher(path);
511             if (rd == null) {
512                 throw new IOException JavaDoc(
513                         "Couldn't get request dispatcher for path: " + path);
514             }
515             ByteArrayServletOutputStream basos =
516                 new ByteArrayServletOutputStream();
517             ResponseIncludeWrapper responseIncludeWrapper =
518                 new ResponseIncludeWrapper(context, req, res, basos);
519             rd.include(req, responseIncludeWrapper);
520             //We can't assume the included servlet flushed its output
521
responseIncludeWrapper.flushOutputStreamOrWriter();
522             byte[] bytes = basos.toByteArray();
523
524             //Assume platform default encoding unless otherwise specified
525
String JavaDoc retVal;
526             if (inputEncoding == null) {
527                 retVal = new String JavaDoc( bytes );
528             } else {
529                 retVal = new String JavaDoc (bytes, inputEncoding);
530             }
531
532             //make an assumption that an empty response is a failure. This is
533
// a problem
534
// if a truly empty file
535
//were included, but not sure how else to tell.
536
if (retVal.equals("") && !req.getMethod().equalsIgnoreCase(
537                     org.apache.coyote.http11.Constants.HEAD)) {
538                 throw new IOException JavaDoc("Couldn't find file: " + path);
539             }
540             return retVal;
541         } catch (ServletException JavaDoc e) {
542             throw new IOException JavaDoc("Couldn't include file: " + originalPath
543                     + " because of ServletException: " + e.getMessage());
544         }
545     }
546
547     protected class ServletContextAndPath {
548         protected ServletContext JavaDoc servletContext;
549         protected String JavaDoc path;
550
551
552         public ServletContextAndPath(ServletContext JavaDoc servletContext,
553                                      String JavaDoc path) {
554             this.servletContext = servletContext;
555             this.path = path;
556         }
557
558
559         public ServletContext JavaDoc getServletContext() {
560             return servletContext;
561         }
562
563
564         public String JavaDoc getPath() {
565             return path;
566         }
567     }
568 }
Popular Tags