From 6a3bde7769181ea54d433e7d819b2242414284da Mon Sep 17 00:00:00 2001 From: costin Date: Thu, 26 Nov 2009 06:47:03 +0000 Subject: [PATCH] Removed the 'addons' package, moved the interfaces close to the packages that define them, also some code move around. The web.xml parsing ( and some incipient 3.0 annotation processing ) is independent of tomcat, indended as a user-library. git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@884416 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/tomcat/addons/Filesystem.java | 41 --- .../tomcat/addons/UserTemplateClassMapper.java | 54 --- .../tomcat/servlets/config/ConfigLoader.java | 32 ++ .../servlets/config/ServletContextConfig.java | 164 +++++++++ .../config/deploy/AnnotationsProcessor.java | 339 ++++++++++++++++++ .../tomcat/servlets/config/deploy/DomUtil.java | 240 +++++++++++++ .../tomcat/servlets/config/deploy/WarDeploy.java | 116 ++++++ .../tomcat/servlets/config/deploy/WebXml.java | 397 +++++++++++++++++++++ .../tomcat/servlets/file/DefaultServlet.java | 100 +++--- .../org/apache/tomcat/servlets/file/Dir2Html.java | 49 +-- .../apache/tomcat/servlets/file/Filesystem.java | 29 ++ .../tomcat/servlets/file/LocalFilesystem.java | 15 + .../apache/tomcat/servlets/file/WebdavServlet.java | 3 +- .../tomcat/servlets/jmx/JMXProxyServlet.java | 281 +++++++++++++++ .../tomcat/servlets/jmx/JmxObjectManagerSpi.java | 41 +++ ...TemplateClassMapper.java => BaseJspLoader.java} | 142 ++++++-- .../jsp/JasperCompilerTemplateClassMapper.java | 173 --------- .../servlets/jsp/JspFileTemplateServlet.java | 90 ----- .../servlets/jsp/WildcardTemplateServlet.java | 22 +- .../apache/tomcat/servlets/jspc/JasperRuntime.java | 188 ++++++++++ .../apache/tomcat/servlets/jspc/JspcServlet.java | 87 +++++ .../apache/tomcat/servlets/sec/AccessFilter.java | 1 - .../tomcat/servlets/sec/BasicAuthentication.java | 1 - .../tomcat/servlets/sec/FormAuthentication.java | 1 - .../sec}/UserAuthentication.java | 17 +- .../tomcat/servlets/session/RandomGenerator.java | 2 +- .../servlets/session/SimpleSessionManager.java | 1 - .../session}/UserSessionManager.java | 17 +- .../org/apache/tomcat/servlets/util/Base64.java | 269 ++++++++++++++ .../tomcat/servlets/util/FastHttpDateFormat.java | 231 ++++++++++++ .../org/apache/tomcat/servlets/util/MimeMap.java | 195 ++++++++++ .../apache/tomcat/servlets/util/RequestUtil.java | 2 +- .../apache/tomcat/servlets/util/URLEncoder.java | 100 ++++++ 33 files changed, 2903 insertions(+), 537 deletions(-) delete mode 100644 modules/tomcat-lite/java/org/apache/tomcat/addons/Filesystem.java delete mode 100644 modules/tomcat-lite/java/org/apache/tomcat/addons/UserTemplateClassMapper.java create mode 100644 modules/tomcat-lite/java/org/apache/tomcat/servlets/config/ConfigLoader.java create mode 100644 modules/tomcat-lite/java/org/apache/tomcat/servlets/config/ServletContextConfig.java create mode 100644 modules/tomcat-lite/java/org/apache/tomcat/servlets/config/deploy/AnnotationsProcessor.java create mode 100644 modules/tomcat-lite/java/org/apache/tomcat/servlets/config/deploy/DomUtil.java create mode 100644 modules/tomcat-lite/java/org/apache/tomcat/servlets/config/deploy/WarDeploy.java create mode 100644 modules/tomcat-lite/java/org/apache/tomcat/servlets/config/deploy/WebXml.java create mode 100644 modules/tomcat-lite/java/org/apache/tomcat/servlets/file/Filesystem.java create mode 100644 modules/tomcat-lite/java/org/apache/tomcat/servlets/file/LocalFilesystem.java create mode 100644 modules/tomcat-lite/java/org/apache/tomcat/servlets/jmx/JMXProxyServlet.java create mode 100644 modules/tomcat-lite/java/org/apache/tomcat/servlets/jmx/JmxObjectManagerSpi.java rename modules/tomcat-lite/java/org/apache/tomcat/servlets/jsp/{SimpleTemplateClassMapper.java => BaseJspLoader.java} (60%) delete mode 100644 modules/tomcat-lite/java/org/apache/tomcat/servlets/jsp/JasperCompilerTemplateClassMapper.java delete mode 100644 modules/tomcat-lite/java/org/apache/tomcat/servlets/jsp/JspFileTemplateServlet.java create mode 100644 modules/tomcat-lite/java/org/apache/tomcat/servlets/jspc/JasperRuntime.java create mode 100644 modules/tomcat-lite/java/org/apache/tomcat/servlets/jspc/JspcServlet.java rename modules/tomcat-lite/java/org/apache/tomcat/{addons => servlets/sec}/UserAuthentication.java (62%) rename modules/tomcat-lite/java/org/apache/tomcat/{addons => servlets/session}/UserSessionManager.java (55%) create mode 100644 modules/tomcat-lite/java/org/apache/tomcat/servlets/util/Base64.java create mode 100644 modules/tomcat-lite/java/org/apache/tomcat/servlets/util/FastHttpDateFormat.java create mode 100644 modules/tomcat-lite/java/org/apache/tomcat/servlets/util/MimeMap.java create mode 100644 modules/tomcat-lite/java/org/apache/tomcat/servlets/util/URLEncoder.java diff --git a/modules/tomcat-lite/java/org/apache/tomcat/addons/Filesystem.java b/modules/tomcat-lite/java/org/apache/tomcat/addons/Filesystem.java deleted file mode 100644 index 85c06a3f0..000000000 --- a/modules/tomcat-lite/java/org/apache/tomcat/addons/Filesystem.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.addons; - -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * Abstract the filesystem - lighter than the JNDI used in catalina. - * - * This can be used to port the File/Dav servlets to environments that - * don't have a file system access, or in servlet engines with class-based - * sandboxing. - */ -public class Filesystem { - - public OutputStream getOutputStream(String name) throws IOException { - return null; - } - - public InputStream getInputStream(String name) throws IOException { - return new FileInputStream(name); - } -} diff --git a/modules/tomcat-lite/java/org/apache/tomcat/addons/UserTemplateClassMapper.java b/modules/tomcat-lite/java/org/apache/tomcat/addons/UserTemplateClassMapper.java deleted file mode 100644 index 1a37cc779..000000000 --- a/modules/tomcat-lite/java/org/apache/tomcat/addons/UserTemplateClassMapper.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.addons; - -import javax.servlet.Servlet; -import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; - -/** - * Mapps a templating name ( like a jsp file ) to a class name - * generated by the template compiler. - * - * This class is needed at runtime to support *.jsp mappings - * or - can be used to support other formats. - * - * The UserTemplateCompiler is only needed to support run-time - * compilation - if ahead-of-time compilation is used - * all generated files can be mapped explicitly with - * . - * - * @author Costin Manolache - */ -public interface UserTemplateClassMapper { - - /** - * Generate and load the proxy corresponding to the template file. - * - */ - public Servlet loadProxy(String jspFile, - ServletContext ctx, - ServletConfig config) throws ServletException; - - /** - * Quick check if the template ( or deps ) has been modified - * and the servlet needs to be regenerated; - */ - public boolean needsReload(String jspFile, Servlet s); -} diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/config/ConfigLoader.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/config/ConfigLoader.java new file mode 100644 index 000000000..b35666878 --- /dev/null +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/config/ConfigLoader.java @@ -0,0 +1,32 @@ +/* + */ +package org.apache.tomcat.servlets.config; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.ObjectInputStream; + +public class ConfigLoader { + + public ServletContextConfig loadConfig(String basePath) { + + + String fileName = basePath + ServletContextConfig.SERIALIZED_PATH; + File f = new File(fileName); + if (f.exists()) { + ServletContextConfig contextConfig = new ServletContextConfig(); + try { + ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f)); + contextConfig = (ServletContextConfig) ois.readObject(); + return contextConfig; + } catch (Throwable e) { + System.err.println("Ignoring invalid .ser config " + e); + // ignore + } + } + + return null; + } + +} diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/config/ServletContextConfig.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/config/ServletContextConfig.java new file mode 100644 index 000000000..3b056e275 --- /dev/null +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/config/ServletContextConfig.java @@ -0,0 +1,164 @@ +/** + * + */ +package org.apache.tomcat.servlets.config; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Struct representation of webapp configuration. + * + * All the data in web.xml, annotations, etc should be represented + * here. This class is serializable - but can be saved/loaded as + * json or any 'pojo' persistence. + * + * + * Public fields to make it easy to access it, we can add accessors. + * Naming should match the web.xml element name. + * + * @author Costin Manolache + */ +public class ServletContextConfig implements Serializable { + + public static final String SERIALIZED_PATH = "/WEB-INF/deploy_web.ser"; + private static final long serialVersionUID = 1728492145981883124L; + + public static final int CURRENT_VERSION = 1; + + public int version = CURRENT_VERSION; + + /** + * Main config ( web.xml ) path and timestamp - touch it to reload. + */ + public List fileName = new ArrayList(); + public long timestamp; + + public boolean full; + + public String displayName; + + public HashMap contextParam = new HashMap(); + + public HashMap mimeMapping = new HashMap(); // extension -> mime-type + + public ArrayList listenerClass = new ArrayList(); + + public ArrayList welcomeFileList = new ArrayList(); + + // code -> location + public HashMap errorPageCode= new HashMap(); + + // exception -> location + public HashMap errorPageException= new HashMap(); + + public HashMap localeEncodingMapping= new HashMap(); // locale -> encoding + + // public HashMap tagLibs; // uri->location + // jsp-property-group + + // securityConstraint + public ArrayList securityConstraint = new ArrayList(); + + // loginConfig + public String authMethod; + public String realmName; + public String formLoginPage; + public String formErrorPage; + + public ArrayList securityRole = new ArrayList(); + + // envEntry + public ArrayList envEntry = new ArrayList(); + + // ejbRef + // ejbLocalRef + // serviceRef + // resourceRef + // resourceEnvRef + // message-destination + // message-destinationRef + public HashMap filters = new HashMap(); + public HashMap servlets = new HashMap(); + + public int sessionTimeout; + public boolean distributable; + + public HashMap servletMapping = new HashMap(); // url -> servlet + public ArrayList filterMappings = new ArrayList(); + public boolean metadataComplete = false; + + + // Normalized + public static class FilterMappingData implements Serializable { + private static final long serialVersionUID = -4533568066713041994L; + public String filterName; + + // Only one of the 2 + public String urlPattern; + public String servletName; + + // REQUEST, FORWARD, INCLUDE, ERROR, ASYNC + public List dispatcher = new ArrayList(); + } + + public static class EnvEntryData implements Serializable { + private static final long serialVersionUID = 7023847615343715257L; + public String envEntryName; + public String envEntryType; + public String envEntryValue; + } + + public static class ServiceData implements Serializable { + public String name; + public String className; + + public Map initParams = new HashMap(); + + public boolean asyncSupported = false; + } + + public static class FilterData extends ServiceData implements Serializable { + private static final long serialVersionUID = -535820271746973166L; + } + + public static class ServletData extends ServiceData implements Serializable { + private static final long serialVersionUID = -3216904178501185930L; + + public ServletData() { + } + public ServletData(String servletName, String servletClass) { + this.className = servletClass; + this.name = servletName; + } + + public String jspFile; + public int loadOnStartup = -1; + public String runAs; + public Map securityRoleRef = new HashMap(); // roleName -> [roleLink] + public boolean multipartConfig = false; + + public List declaresRoles = new ArrayList(); + + } + + public static class WebResourceCollectionData implements Serializable { + public String webResourceName; + public ArrayList urlPattern = new ArrayList(); + public ArrayList httpMethod = new ArrayList(); + } + + public static class SecurityConstraintData implements Serializable { + private static final long serialVersionUID = -4780214921810871769L; + + public ArrayList roleName = new ArrayList(); // auth-constraint/role + + public ArrayList webResourceCollection = + new ArrayList(); + public String transportGuarantee; + + } +} \ No newline at end of file diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/config/deploy/AnnotationsProcessor.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/config/deploy/AnnotationsProcessor.java new file mode 100644 index 000000000..86b0e4dce --- /dev/null +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/config/deploy/AnnotationsProcessor.java @@ -0,0 +1,339 @@ +/* + */ +package org.apache.tomcat.servlets.config.deploy; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +import org.apache.tomcat.servlets.config.ServletContextConfig; +import org.apache.tomcat.servlets.config.ServletContextConfig.FilterData; +import org.apache.tomcat.servlets.config.ServletContextConfig.FilterMappingData; +import org.apache.tomcat.servlets.config.ServletContextConfig.ServiceData; +import org.apache.tomcat.servlets.config.ServletContextConfig.ServletData; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.AnnotationNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodNode; + + +// TODO: move to 'tools' dir, don't include in runtime +// ( same for xml processor ) - use binary +// + +// TODO: stupid ordering rules - probably will require merging configs +// and other ugliness. + +// TODO: the even more brain-damaged ServletContextInitializer and +// HandlesTypes - which requires recording all annotations for all classes, +// and worse - all the hierarchy to detect annotations on super. + +/** + * Post-compile or deploy tool: will scan classes and jars and + * generate an annotation file. + * + * Will process: + * - annotations - for each class + * - find tld descriptors + * - web.xml and fragments + * + * Output: a .ser file, for faster tomcat startup and a 'compete' + * web.xml file. + * + * Tomcat should not read all classes each time it starts, or + * depend on bcel at runtime. + * + * Servlet spec makes the worst use of annotations by requiring + * scanning all classes. This should be a compile-time tool only ! + * + * @author Costin Manolache + */ +public class AnnotationsProcessor { + + String baseDir; + ServletContextConfig cfg; + + + + public AnnotationsProcessor(ServletContextConfig cfg2) { + this.cfg = cfg2; + } + + public void processWebapp(String baseN) throws IOException { + if (!baseN.endsWith("/")) { + baseN = baseN + "/"; + } + processDir(baseN + "classes"); + + File lib = new File(baseN + "lib"); + if (!lib.isDirectory()) { + return; + } + File[] files = lib.listFiles(); + if (files == null) { + return; + } + + for (File f: files) { + if (!f.isDirectory() && f.getName().endsWith(".jar")) { + processJar(f.getCanonicalPath()); + } + } + } + + public void processJar(String path) throws IOException { + JarFile jar = new JarFile(path); + Enumeration entries = jar.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + String name = entry.getName(); + if (name.endsWith(".class")) { + processClass(jar.getInputStream(entry), + "", name); + } else if (name.equals("META-INF/services/javax.servlet.ServletContainerInitializer")) { + + } + + } + } + + public void processDir(String base) throws IOException { + // TODO: keep track of files to avoid loops + processDir(new File(base)); + } + + public void processDir(File base) throws IOException { + if (!base.isDirectory()) { + return; + } + String baseN = base.getCanonicalPath(); + if (!baseN.endsWith("/")) { + baseN = baseN + "/"; + } + + File[] files = base.listFiles(); + if (files != null) { + for (File f: files) { + if (f.isDirectory()) { + System.err.println(f); + processDir(f); + } else if (f.getName().endsWith(".class")) { + try { + processClass(new FileInputStream(f), base.getCanonicalPath(), + f.getCanonicalPath()); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + } + + } + + private static Map asmList2Map(List list) { + Map values = new HashMap(); + for (int i = 0; i < list.size(); i+= 2) { + String name = (String) list.get(i); + Object val = list.get(i + 1); + values.put(name, val); + } + return values; + } + + private static Map annotationMap(List annL) { + Map values = new HashMap(); + if (annL != null) { + for (Object annO: annL) { + AnnotationNode ann = (AnnotationNode) annO; + String name = Type.getType(ann.desc).toString(); + values.put(name, ann); + } + } + return values; + } + + + + public void processClass(InputStream classStream, + String base, + String classFile) throws IOException { + String classPath = classFile.substring(base.length() + 1); + classPath = classPath.substring(0, classPath.length() - ".class".length()); + classPath = classPath.replace("/", "."); + + ClassReader classReader = new ClassReader(classStream); + ClassNode cN = new ClassNode(); + classReader.accept(cN, + ClassReader.SKIP_CODE + ClassReader.SKIP_DEBUG + ClassReader.SKIP_FRAMES); + + String className = cN.name; + + Map annotations = annotationMap(cN.visibleAnnotations); + + processServlets(className, annotations, cN); + processWebFilter(className, annotations); + + AnnotationNode listenerA = annotations.get("javax.servlet.annotation.WebListener"); + if (listenerA != null) { + // TODO: checks + cfg.listenerClass.add(className); + } + + +// for (AnnotationNode mN : annotations.values()) { +// String ann = Type.getType(mN.desc).toString(); +// Map values = asmList2Map(mN.values); +// +// if ("javax.servlet.annotation.HandlesTypes".equals(ann)) { +// } else if ("javax.servlet.annotation.MultipartConfig".equals(ann)) { +// } else if ("javax.annotation.security.RunAs".equals(ann)) { +// } else if ("javax.annotation.security.DeclareRoles".equals(ann)) { +// } else if ("javax.annotation.security.RolesAllowed".equals(ann)) { +// } else if ("javax.annotation.security.DenyAll".equals(ann)) { +// } else if ("javax.annotation.security.PermitAll".equals(ann)) { +// } else if ("javax.servlet.annotation.WebFilter".equals(ann)) { +// } else if ("javax.servlet.annotation.WebServlet".equals(ann)) { +// // in WebServlet +// } else if ("javax.servlet.annotation.WebListener".equals(ann)) { +// } else if ("javax.servlet.annotation.WebInitParam".equals(ann)) { +// // In WebServlet, (WebFilter) +// } else { +// System.err.println("\n" + className + " " + Type.getType(mN.desc)); +// } +// } + + } + + private void processServlets(String className, + Map annotations, ClassNode cn) { + + AnnotationNode webServletA = + annotations.get("javax.servlet.annotation.WebServlet"); + if (webServletA != null) { + ServletData sd = new ServletData(); + // TODO: validity checks (implements servlet, etc) + Map params = asmList2Map(webServletA.values); + + processService(className, webServletA, + sd, params); + + if (params.containsKey("loadOnStartup")) { + sd.loadOnStartup = (Integer)params.get("loadOnStartup"); + } + if (annotations.get("javax.servlet.annotation.MultipartConfig") != null) { + sd.multipartConfig = true; + } + + AnnotationNode declareA = annotations.get("javax.annotation.security.DeclareRoles"); + if (declareA != null) { + Map runAsParams = asmList2Map(declareA.values); + ArrayList roles = (ArrayList) runAsParams.get("value"); + for (Object r: roles) { + sd.declaresRoles.add((String) r); + } + } + + AnnotationNode runAsA = annotations.get("javax.annotation.security.RunAs"); + if (runAsA != null) { + Map runAsParams = asmList2Map(runAsA.values); + + sd.runAs = (String) runAsParams.get("value"); + } + + cfg.servlets.put(sd.name, sd); + + ArrayList urls = (ArrayList) params.get("urlPatterns"); + if (urls == null) { + urls = (ArrayList) params.get("value"); + } + + for (Object urlO: urls) { + cfg.servletMapping.put((String) urlO, + sd.name); + } + + // TODO: collect them, add on each of the URLs + // TODO: also on methods + AnnotationNode rolesA = annotations.get("javax.annotation.security.RolesAllowed"); + if (rolesA != null) { + + } + for (Object o: cn.methods) { + MethodNode methodNode = (MethodNode) o; + System.err.println(methodNode.desc); + } + + + + } + } + + private void processWebFilter(String className, + Map annotations) { + AnnotationNode webFilterA = annotations.get("javax.servlet.annotation.WebServlet"); + if (webFilterA != null) { + // TODO: validity checks (implements servlet, etc) + + FilterData sd = new FilterData(); + Map params = asmList2Map(webFilterA.values); + + processService(className, webFilterA, sd, params); + + if (params.containsKey("asyncSupported")) { + sd.asyncSupported = (Boolean) params.get("asyncSupported"); + } + + cfg.filters.put(sd.name, sd); + + ArrayList urls = (ArrayList) params.get("urlPatterns"); + if (urls == null) { + urls = (ArrayList) params.get("value"); + } + for (Object urlO: urls) { + FilterMappingData fmap = new FilterMappingData(); + fmap.filterName = sd.name; + fmap.urlPattern = (String) urlO; + + cfg.filterMappings.add(fmap); + } + } + } + + private ServiceData processService(String className, + AnnotationNode webServletA, ServiceData sd, Map params) { + + sd.name = (String) params.get("name"); + if (sd.name == null) { + sd.name = className; + } + sd.className = className; + + if (params.containsKey("initParams")) { + ArrayList initParamL = (ArrayList) params.get("initParams"); + for (Object initParamO: initParamL) { + AnnotationNode initParamA = (AnnotationNode) initParamO; + + Map initParams = asmList2Map(initParamA.values); + sd.initParams.put((String) initParams.get("name"), + (String) initParams.get("value")); + } + } + + if (params.containsKey("asyncSupported")) { + sd.asyncSupported = (Boolean) params.get("asyncSupported"); + } + return sd; + } + + +} diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/config/deploy/DomUtil.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/config/deploy/DomUtil.java new file mode 100644 index 000000000..64e287033 --- /dev/null +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/config/deploy/DomUtil.java @@ -0,0 +1,240 @@ +package org.apache.tomcat.servlets.config.deploy; + + +import java.io.IOException; +import java.io.InputStream; +import java.io.StringReader; +import java.util.logging.Logger; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + + +/** + * Few simple utils to read DOM + * + * @author Costin Manolache + */ +public class DomUtil { + private static Logger log= + Logger.getLogger( DomUtil.class.getName() ); + + // -------------------- DOM utils -------------------- + + /** Get the trimed text content of a node or null if there is no text + */ + public static String getContent(Node n ) { + if( n==null ) return null; + Node n1=DomUtil.getChild(n, Node.TEXT_NODE); + + if( n1==null ) return null; + + String s1=n1.getNodeValue(); + return s1.trim(); + } + + /** Get the first element child. + * @param parent lookup direct childs + * @param name name of the element. If null return the first element. + */ + public static Node getChild( Node parent, String name ) { + if( parent==null ) return null; + Node first=parent.getFirstChild(); + if( first==null ) return null; + + for (Node node = first; node != null; + node = node.getNextSibling()) { + //System.out.println("getNode: " + name + " " + node.getNodeName()); + if( node.getNodeType()!=Node.ELEMENT_NODE) + continue; + if( name != null && + name.equals( node.getNodeName() ) ) { + return node; + } + if( name == null ) { + return node; + } + } + return null; + } + + public static String getAttribute(Node element, String attName ) { + NamedNodeMap attrs=element.getAttributes(); + if( attrs==null ) return null; + Node attN=attrs.getNamedItem(attName); + if( attN==null ) return null; + return attN.getNodeValue(); + } + + public static void setAttribute(Node node, String attName, String val) { + NamedNodeMap attributes=node.getAttributes(); + Node attNode=node.getOwnerDocument().createAttribute(attName); + attNode.setNodeValue( val ); + attributes.setNamedItem(attNode); + } + + public static void removeAttribute( Node node, String attName ) { + NamedNodeMap attributes=node.getAttributes(); + attributes.removeNamedItem(attName); + } + + + /** Set or replace the text value + */ + public static void setText(Node node, String val) { + Node chld=DomUtil.getChild(node, Node.TEXT_NODE); + if( chld == null ) { + Node textN=node.getOwnerDocument().createTextNode(val); + node.appendChild(textN); + return; + } + // change the value + chld.setNodeValue(val); + } + + /** Find the first direct child with a given attribute. + * @param parent + * @param elemName name of the element, or null for any + * @param attName attribute we're looking for + * @param attVal attribute value or null if we just want any + */ + public static Node findChildWithAtt(Node parent, String elemName, + String attName, String attVal) { + + Node child=DomUtil.getChild(parent, Node.ELEMENT_NODE); + if( attVal== null ) { + while( child!= null && + ( elemName==null || elemName.equals( child.getNodeName())) && + DomUtil.getAttribute(child, attName) != null ) { + child=getNext(child, elemName, Node.ELEMENT_NODE ); + } + } else { + while( child!= null && + ( elemName==null || elemName.equals( child.getNodeName())) && + ! attVal.equals( DomUtil.getAttribute(child, attName)) ) { + child=getNext(child, elemName, Node.ELEMENT_NODE ); + } + } + return child; + } + + + /** Get the first child's content ( ie it's included TEXT node ). + */ + public static String getChildContent( Node parent, String name ) { + Node first=parent.getFirstChild(); + if( first==null ) return null; + for (Node node = first; node != null; + node = node.getNextSibling()) { + //System.out.println("getNode: " + name + " " + node.getNodeName()); + if( name.equals( node.getNodeName() ) ) { + return getContent( node ); + } + } + return null; + } + + /** Get the first direct child with a given type + */ + public static Node getChild( Node parent, int type ) { + Node n=parent.getFirstChild(); + while( n!=null && type != n.getNodeType() ) { + n=n.getNextSibling(); + } + if( n==null ) return null; + return n; + } + + /** Get the next sibling with the same name and type + */ + public static Node getNext( Node current ) { + String name=current.getNodeName(); + int type=current.getNodeType(); + return getNext( current, name, type); + } + + /** Return the next sibling with a given name and type + */ + public static Node getNext( Node current, String name, int type) { + Node first=current.getNextSibling(); + if( first==null ) return null; + + for (Node node = first; node != null; + node = node.getNextSibling()) { + + if( type >= 0 && node.getNodeType() != type ) continue; + //System.out.println("getNode: " + name + " " + node.getNodeName()); + if( name==null ) + return node; + if( name.equals( node.getNodeName() ) ) { + return node; + } + } + return null; + } + + public static class NullResolver implements EntityResolver { + public InputSource resolveEntity (String publicId, + String systemId) + throws SAXException, IOException + { +// if( log.isTraceEnabled()) +// log.trace("ResolveEntity: " + publicId + " " + systemId); + return new InputSource(new StringReader("")); + } + } + +// public static void setAttributes( Object o, Node parent) +// { +// NamedNodeMap attrs=parent.getAttributes(); +// if( attrs==null ) return; +// +// for (int i=0; i entries = jar.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + String name = entry.getName(); + if (name.equals("META-INF/web-fragment.xml")) { + processFragment(jar.getInputStream(entry)); + } + } + } + + private void processFragment(InputStream inputStream) throws IOException { + readWebXml(inputStream, "web-fragment"); + + } + + public void readWebXml(String baseDir) throws IOException { + readWebXml(baseDir, "web-app"); + } + + public void readWebXml(String baseDir, String topName) throws IOException { + try { + File webXmlFile = new File(baseDir); + if (!webXmlFile.exists()) { + return; + } + d.fileName.add(webXmlFile.getCanonicalPath()); + + FileInputStream fileInputStream = new FileInputStream(webXmlFile); + readWebXml(fileInputStream, topName); + } catch (Exception e) { + e.printStackTrace(); + throw new IOException(e.getMessage()); + } + } + + public void readWebXml(InputStream fileInputStream, String topName) + throws IOException { + try { + + Document document = DomUtil.readXml(fileInputStream); + Node webappNode = DomUtil.getChild(document, topName); + + String fullS = DomUtil.getAttribute(webappNode, "full"); + if (fullS != null && fullS.equalsIgnoreCase("true")) { + d.full = true; + } + String metaCompleteS = DomUtil.getAttribute(webappNode, "full"); + if ("true".equalsIgnoreCase(metaCompleteS)) { + d.metadataComplete = true; + } + + d.displayName = DomUtil.getAttribute(webappNode, "display-name"); + + // Process each child of web-app + Node confNode = DomUtil.getChild(webappNode, "filter"); + while (confNode != null ) { + processFilter(confNode); + confNode = DomUtil.getNext(confNode); + } + + confNode = DomUtil.getChild(webappNode, "filter-mapping"); + while (confNode != null ) { + processFilterMapping(confNode); + confNode = DomUtil.getNext(confNode); + } + + confNode = DomUtil.getChild(webappNode, "context-param"); + while (confNode != null ) { + String n = DomUtil.getChildContent(confNode, "param-name").trim(); + String v = DomUtil.getChildContent(confNode, "param-value").trim(); + d.contextParam.put(n, v); + confNode = DomUtil.getNext(confNode); + } + + confNode = DomUtil.getChild(webappNode, "mime-mapping"); + while (confNode != null ) { + String n = DomUtil.getChildContent(confNode, "extension"); + String t = DomUtil.getChildContent(confNode, "mime-type"); + d.mimeMapping.put(n, t); + confNode = DomUtil.getNext(confNode); + } + + confNode = DomUtil.getChild(webappNode, "error-page"); + while (confNode != null ) { + processErrorPage(confNode); + confNode = DomUtil.getNext(confNode); + } + + confNode = DomUtil.getChild(webappNode, "jsp-config"); + while (confNode != null ) { + processJspConfig(confNode); + confNode = DomUtil.getNext(confNode); + } + + confNode = DomUtil.getChild(webappNode, "servlet"); + while (confNode != null ) { + processServlet(confNode); + confNode = DomUtil.getNext(confNode); + } + + confNode = DomUtil.getChild(webappNode, "servlet-mapping"); + while (confNode != null ) { + processServletMapping(confNode); + confNode = DomUtil.getNext(confNode); + } + + confNode = DomUtil.getChild(webappNode, "listener"); + while (confNode != null ) { + String lClass = DomUtil.getChildContent(confNode, "listener-class"); + d.listenerClass.add(lClass); + confNode = DomUtil.getNext(confNode); + } + + confNode = DomUtil.getChild(webappNode, "security-constraint"); + while (confNode != null ) { + processSecurityConstraint(confNode); + confNode = DomUtil.getNext(confNode); + } + + confNode = DomUtil.getChild(webappNode, "login-config"); + while (confNode != null ) { + processLoginConfig(confNode); + confNode = DomUtil.getNext(confNode); + if (confNode != null) + throw new ServletException("Multiple login-config"); + } + + confNode = DomUtil.getChild(webappNode, "session-config"); + while (confNode != null ) { + String n = DomUtil.getChildContent(confNode, "session-timeout"); + int stout = Integer.parseInt(n); + d.sessionTimeout = stout; + confNode = DomUtil.getNext(confNode); + if (confNode != null) + throw new ServletException("Multiple session-config"); + } + + confNode = DomUtil.getChild(webappNode, "welcome-file-list"); + while (confNode != null ) { + Node wf = DomUtil.getChild(confNode, "welcome-file"); + while (wf != null) { + String file = DomUtil.getContent(wf); + d.welcomeFileList.add(file); + wf = DomUtil.getNext(wf); + } + // more sections ? + confNode = DomUtil.getNext(confNode); + } + + // Not supported right now - TODO: collect, have jndi plugin + confNode = DomUtil.getChild(webappNode, "env-entry"); + while (confNode != null ) { + processEnvEntry(confNode); + confNode = DomUtil.getNext(confNode); + } + + confNode = DomUtil.getChild(webappNode, "locale-encoding-mapping-list"); + while (confNode != null ) { + confNode = DomUtil.getNext(confNode); + String n = DomUtil.getChildContent(confNode, "locale"); + String t = DomUtil.getChildContent(confNode, "encoding"); + d.localeEncodingMapping.put(n, t); + } + + confNode = DomUtil.getChild(webappNode, "distributable"); + while (confNode != null ) { + d.distributable = true; + confNode = DomUtil.getNext(confNode); + } + + confNode = DomUtil.getChild(confNode, "security-role"); + while (confNode != null ) { + String n = DomUtil.getChildContent(confNode, "role-name"); + d.securityRole.add(n); + confNode = DomUtil.getNext(confNode); + } + + } catch (Exception e) { + e.printStackTrace(); + throw new IOException(e.getMessage()); + } + } + + private void processJspConfig(Node confNode) { + Node tagLib = DomUtil.getChild(confNode, "taglib"); + while (tagLib != null) { + String uri = DomUtil.getChildContent(tagLib, "taglib-uri"); + String l = DomUtil.getChildContent(tagLib, "taglib-location"); + //d.tagLibs.put(uri, l); + tagLib = DomUtil.getNext(tagLib); + } + + tagLib = DomUtil.getChild(confNode, "jsp-property-group"); + while (tagLib != null) { + // That would be the job of the JSP servlet to process. + tagLib = DomUtil.getNext(tagLib); + } + } + + private void processEnvEntry(Node confNode) { + EnvEntryData ed = new EnvEntryData(); + ed.envEntryName = DomUtil.getChildContent(confNode,"env-entry-name"); + ed.envEntryType = DomUtil.getChildContent(confNode,"env-entry-type"); + ed.envEntryValue = DomUtil.getChildContent(confNode,"env-entry-value"); + d.envEntry.add(ed); + } + + private void processLoginConfig(Node confNode) { + d.authMethod = DomUtil.getChildContent(confNode,"auth-method"); + d.realmName = DomUtil.getChildContent(confNode,"auth-method"); + Node formNode = DomUtil.getChild(confNode, "form-login-config"); + if (formNode != null) { + d.formLoginPage = DomUtil.getChildContent(formNode,"form-login-page"); + d.formErrorPage = DomUtil.getChildContent(formNode,"form-error-page"); + } + } + + private void processSecurityConstraint(Node confNode) { + SecurityConstraintData sd = new SecurityConstraintData(); + Node cn = DomUtil.getChild(confNode, "web-resource-collection"); + while (cn != null) { + WebResourceCollectionData wrd = new WebResourceCollectionData(); + wrd.webResourceName = DomUtil.getChildContent(cn, "web-resource-name"); + Node scn = DomUtil.getChild(cn,"url-pattern"); + while (scn != null) { + wrd.urlPattern.add(DomUtil.getContent(scn)); + scn = DomUtil.getNext(scn); + } + scn = DomUtil.getChild(cn,"http-method"); + while (scn != null) { + wrd.httpMethod.add(DomUtil.getContent(scn)); + scn = DomUtil.getNext(scn); + } + cn = DomUtil.getNext(cn); + sd.webResourceCollection.add(wrd); + } + + d.securityConstraint.add(sd); + } + + private void processErrorPage(Node confNode) { + String name = DomUtil.getChildContent(confNode,"location"); + String c = DomUtil.getChildContent(confNode,"error-code"); + String t = DomUtil.getChildContent(confNode,"exception-type"); + if (c != null) { + d.errorPageCode.put(c, name); + } + if (t != null) { + d.errorPageException.put(t, name); + } + } + + private void processServlet(Node confNode) throws ServletException { + ServletData sd = new ServletData(); + + sd.name = DomUtil.getChildContent(confNode,"servlet-name"); + sd.className = DomUtil.getChildContent(confNode,"servlet-class"); + sd.jspFile = DomUtil.getChildContent(confNode,"jsp-file"); + + processInitParams(confNode, sd.initParams); + + d.servlets.put( sd.name, sd ); + + String los = DomUtil.getChildContent(confNode, "load-on-startup"); + if (los != null ) { + sd.loadOnStartup = Integer.parseInt(los); + } + + Node sn = DomUtil.getChild(confNode, "security-role-ref"); + while (sn != null ) { + String roleName = DomUtil.getChildContent(sn, "role-name"); + String roleLink = DomUtil.getChildContent(sn, "role-link"); + if (roleLink == null) { + sd.securityRoleRef.put(roleName, ""); + } else { + sd.securityRoleRef.put(roleName, roleLink); + } + sn = DomUtil.getNext(sn); + } + } + + private void processInitParams(Node confNode, Map initParams) { + Node initN = DomUtil.getChild(confNode, "init-param"); + while (initN != null ) { + String n = DomUtil.getChildContent(initN, "param-name"); + String v = DomUtil.getChildContent(initN, "param-value"); + initParams.put(n, v); + initN = DomUtil.getNext(initN); + } + } + + private void processServletMapping(Node confNode) { + String name = DomUtil.getChildContent(confNode,"servlet-name"); + Node dataN = DomUtil.getChild(confNode, "url-pattern"); + while (dataN != null) { + String path = DomUtil.getContent(dataN).trim(); + dataN = DomUtil.getNext(dataN); + + if (! (path.startsWith("/") || path.startsWith("*"))) { + // backward compat + path = "/" + path; + } + d.servletMapping.put(path, name); + } + } + + private void processFilterMapping(Node confNode) { + String filterName = DomUtil.getChildContent(confNode,"filter-name"); + // multiple + ArrayList dispatchers = new ArrayList(); + Node dataN = DomUtil.getChild(confNode, "dispatcher"); + while (dataN != null ) { + String d = DomUtil.getContent(dataN); + dispatchers.add(d); + dataN = DomUtil.getNext(dataN); + } + + // Multiple url-pattern and servlet-name in one + // mapping rule. Need to be applied in order. + dataN = DomUtil.getChild(confNode, "url-pattern"); + while (dataN != null ) { + FilterMappingData fm = new FilterMappingData(); + fm.filterName = filterName; + fm.dispatcher = dispatchers; + String path = DomUtil.getContent(dataN); + dataN = DomUtil.getNext(dataN); + fm.urlPattern = path; + d.filterMappings.add(fm); + } + dataN = DomUtil.getChild(confNode, "servlet-name"); + while (dataN != null ) { + FilterMappingData fm = new FilterMappingData(); + fm.filterName = filterName; + fm.dispatcher = dispatchers; + String sn = DomUtil.getContent(dataN); + dataN = DomUtil.getNext(dataN); + fm.servletName = sn; + d.filterMappings.add(fm); + } + } + + private void processFilter(Node confNode) { + String name = DomUtil.getChildContent(confNode,"filter-name"); + String sclass = DomUtil.getChildContent(confNode,"filter-class"); + + FilterData fd = new FilterData(); + processInitParams(confNode, fd.initParams); + fd.name = name; + fd.className = sclass; + d.filters.put(name, fd); + } + +} diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/file/DefaultServlet.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/file/DefaultServlet.java index 220069456..e2ed86594 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/servlets/file/DefaultServlet.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/file/DefaultServlet.java @@ -40,11 +40,8 @@ import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; - -import org.apache.tomcat.addons.Filesystem; -import org.apache.tomcat.integration.ObjectManager; -import org.apache.tomcat.integration.simple.ServletHelper; import org.apache.tomcat.servlets.util.Range; +import org.apache.tomcat.servlets.util.URLEncoder; /** * The default resource-serving servlet for most web applications, @@ -126,8 +123,6 @@ public class DefaultServlet extends HttpServlet { // --------------------------------------------------------- Public Methods - - protected ObjectManager om; protected Filesystem fs; /** @@ -135,14 +130,15 @@ public class DefaultServlet extends HttpServlet { */ public void destroy() { } - - + /** * Initialize this servlet. */ public void init() throws ServletException { - om = ServletHelper.getObjectManager(getServletContext()); - fs = (Filesystem) om.get(Filesystem.class.getName()); + if (fs == null) { + // R/O - no write + fs = new Filesystem(); + } String realPath = getServletContext().getRealPath("/"); basePath = new File(realPath); @@ -517,9 +513,8 @@ public class DefaultServlet extends HttpServlet { && (request.getHeader("Range") == null) ) || (ranges == FULL) ) { - processFullFile(response, content, resFile, contentType, - contentLength, ostream, writer); - + processSingleRange(response, content, resFile, contentType, + ostream, writer, ranges, contentLength); } else { if ((ranges == null) || (ranges.isEmpty())) @@ -531,7 +526,7 @@ public class DefaultServlet extends HttpServlet { if (ranges.size() == 1) { processSingleRange(response, content, resFile, contentType, - ostream, writer, ranges); + ostream, writer, ranges, contentLength); } else { @@ -572,13 +567,19 @@ public class DefaultServlet extends HttpServlet { } - private void processSingleRange(HttpServletResponse response, boolean content, File resFile, String contentType, ServletOutputStream ostream, PrintWriter writer, ArrayList ranges) throws IOException { - Range range = (Range) ranges.get(0); - response.addHeader("Content-Range", "bytes " - + range.start - + "-" + range.end + "/" - + range.length); - long length = range.end - range.start + 1; + private void processSingleRange(HttpServletResponse response, boolean content, File resFile, String contentType, ServletOutputStream ostream, PrintWriter writer, ArrayList ranges, + long contentLength) throws IOException { + Range range = null; + long length = contentLength; + + if (ranges != null && ranges.size() > 0) { + range = (Range) ranges.get(0); + response.addHeader("Content-Range", "bytes " + + range.start + + "-" + range.end + "/" + + range.length); + length = range.end - range.start + 1; + } if (length < Integer.MAX_VALUE) { response.setContentLength((int) length); } else { @@ -596,44 +597,35 @@ public class DefaultServlet extends HttpServlet { } catch (IllegalStateException e) { // Silent catch } - if (ostream != null) { - FileCopyUtils.copy(resFile, ostream, range); - } else { - FileCopyUtils.copy(resFile, writer, range, fileEncoding); - } - } - } - - - private void processFullFile(HttpServletResponse response, boolean content, File resFile, String contentType, long contentLength, ServletOutputStream ostream, PrintWriter writer) throws IOException { - // Set the appropriate output headers - if (contentType != null) { - response.setContentType(contentType); - } - if ((contentLength >= 0)) { - if (contentLength < Integer.MAX_VALUE) { - response.setContentLength((int) contentLength); - } else { - // Set the content-length as String to be able to use a long - response.setHeader("content-length", "" + contentLength); - } - } - - // Copy the input stream to our output stream (if requested) - if (content) { + InputStream is = null; try { - response.setBufferSize(output); - } catch (IllegalStateException e) { - // Silent catch - } - if (ostream != null) { - FileCopyUtils.copy(resFile, ostream); - } else { - FileCopyUtils.copy(resFile, writer, fileEncoding); + is = new FileInputStream(resFile); + if (ostream != null) { + if (range == null) { + CopyUtils.copy(is, ostream); + } else { + CopyUtils.copyRange(is, ostream, range.start, range.end); + } + } else {Reader reader; + if (fileEncoding == null) { + reader = new InputStreamReader(is); + } else { + reader = new InputStreamReader(is, + fileEncoding); + } + if (range == null) { + CopyUtils.copyRange(reader, writer); + } else { + CopyUtils.copyRange(reader, writer, range.start, range.end); + } + } + } finally { + is.close(); } } } + public static String lastModifiedHttp(File resFile) { String lastModifiedHttp = null; SimpleDateFormat format = (SimpleDateFormat)formatTL.get(); diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/file/Dir2Html.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/file/Dir2Html.java index f67b16fbe..fa6856cf3 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/servlets/file/Dir2Html.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/file/Dir2Html.java @@ -31,14 +31,15 @@ import java.util.ArrayList; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.tomcat.servlets.util.URLEncoder; + /** * Handles directory listing */ -public class Dir2Html extends HttpServlet { +public class Dir2Html { /** * Array containing the safe characters set. @@ -113,50 +114,6 @@ public class Dir2Html extends HttpServlet { // --------------------------------------------------------- Public Methods - - /** - * Finalize this servlet. - */ - public void destroy() { - } - - - /** - * Initialize this servlet. - */ - public void init() throws ServletException { - } - - protected void doGet(HttpServletRequest request, - HttpServletResponse response) - throws IOException, ServletException { - - // Serve the requested resource, including the data content - //serveResource(request, response, true); - - } - - - protected void doHead(HttpServletRequest request, - HttpServletResponse response) - throws IOException, ServletException { - - // Serve the requested resource, without the data content - //serveResource(request, response, false); - - } - - - protected void doPost(HttpServletRequest request, - HttpServletResponse response) - throws IOException, ServletException { - doGet(request, response); - } - - - - - /** * Serve the specified resource, optionally including the data content. * diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/file/Filesystem.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/file/Filesystem.java new file mode 100644 index 000000000..8af49f44e --- /dev/null +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/file/Filesystem.java @@ -0,0 +1,29 @@ +/* + */ +package org.apache.tomcat.servlets.file; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * Abstract the filesystem - lighter than the JNDI used in catalina. + * + * This can be used to port the File/Dav servlets to environments that + * don't have a file system access, or in servlet engines with class-based + * sandboxing. + */ +public class Filesystem { + + + public OutputStream getOutputStream(String name) throws IOException { + return null; + } + + public InputStream getInputStream(String name) throws IOException { + return new FileInputStream(name); + } + + +} diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/file/LocalFilesystem.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/file/LocalFilesystem.java new file mode 100644 index 000000000..8c9dbd360 --- /dev/null +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/file/LocalFilesystem.java @@ -0,0 +1,15 @@ +/* + */ +package org.apache.tomcat.servlets.file; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; + + +public class LocalFilesystem extends Filesystem { + + public OutputStream getOutputStream(String name) throws IOException { + return new FileOutputStream(name); + } +} diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/file/WebdavServlet.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/file/WebdavServlet.java index 31ed4025e..19a54f177 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/servlets/file/WebdavServlet.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/file/WebdavServlet.java @@ -37,10 +37,11 @@ import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; +import org.apache.tomcat.servlets.util.FastHttpDateFormat; import org.apache.tomcat.servlets.util.Range; import org.apache.tomcat.servlets.util.RequestUtil; import org.apache.tomcat.servlets.util.UrlUtils; -import org.apache.tomcat.util.http.FastHttpDateFormat; + import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/jmx/JMXProxyServlet.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/jmx/JMXProxyServlet.java new file mode 100644 index 000000000..9eb2d8431 --- /dev/null +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/jmx/JMXProxyServlet.java @@ -0,0 +1,281 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.servlets.jmx; + + +import java.io.IOException; +import java.io.PrintWriter; +import java.lang.management.ManagementFactory; +import java.util.Iterator; +import java.util.Set; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.MBeanInfo; +import javax.management.MBeanAttributeInfo; +import javax.management.Attribute; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * This servlet will dump JMX attributes in a simple format + * and implement proxy services for modeler. + * + * @author Costin Manolache + */ +public class JMXProxyServlet extends HttpServlet { + protected MBeanServer server = null; + + /** + * Initialize this servlet. + */ + public void init() throws ServletException { + // Retrieve the MBean serverif (server == null) { + if( MBeanServerFactory.findMBeanServer(null).size() > 0 ) { + server = MBeanServerFactory.findMBeanServer(null).get(0); + } else { + server = ManagementFactory.getPlatformMBeanServer(); + } + } + + + /** + * Process a GET request for the specified resource. + * + * @param request The servlet request we are processing + * @param response The servlet response we are creating + * + * @exception IOException if an input/output error occurs + * @exception ServletException if a servlet-specified error occurs + */ + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException + { + + response.setContentType("text/plain"); + + PrintWriter writer = response.getWriter(); + + if( server==null ) { + writer.println("Error - No mbean server"); + return; + } + + String qry=request.getParameter("set"); + if( qry!= null ) { + String name=request.getParameter("att"); + String val=request.getParameter("val"); + + setAttribute( writer, qry, name, val ); + return; + } + qry=request.getParameter("get"); + if( qry!= null ) { + String name=request.getParameter("att"); + getAttribute( writer, qry, name ); + return; + } + qry=request.getParameter("qry"); + if( qry == null ) { + qry = "*:*"; + } + + listBeans( writer, qry ); + + } + + public void getAttribute(PrintWriter writer, String onameStr, String att) { + try { + ObjectName oname = new ObjectName(onameStr); + Object value = server.getAttribute(oname, att); + writer.println("OK - Attribute get '" + onameStr + "' - " + att + + "= " + escape(value.toString())); + } catch (Exception ex) { + writer.println("Error - " + ex.toString()); + } + } + + public void setAttribute( PrintWriter writer, + String onameStr, String att, String val ) + { + try { + ObjectName oname=new ObjectName( onameStr ); + String type = getType(oname, att); + if (type == null) { + writer.println("Not found"); + return; + } + Object valueObj = convertValue(type, val ); + server.setAttribute( oname, new Attribute(att, valueObj)); + writer.println("OK - Attribute set"); + } catch( Exception ex ) { + writer.println("Error - " + ex.toString()); + } + } + + public String getType( ObjectName oname, String attName ) + { + String type=null; + MBeanInfo info=null; + try { + info=server.getMBeanInfo(oname); + } catch (Exception e) { + return null; + } + + MBeanAttributeInfo attInfo[]=info.getAttributes(); + for( int i=0; i names = null; + try { + names=server.queryNames(new ObjectName(qry), null); + writer.println("OK - Number of results: " + names.size()); + writer.println(); + } catch (Exception e) { + writer.println("Error - " + e.toString()); + return; + } + + Iterator it=names.iterator(); + while( it.hasNext()) { + ObjectName oname=it.next(); + writer.println( "Name: " + oname.toString()); + + try { + MBeanInfo minfo=server.getMBeanInfo(oname); + // can't be null - I thinl + String code=minfo.getClassName(); + if ("org.apache.commons.modeler.BaseModelMBean".equals(code)) { + code=(String)server.getAttribute(oname, "modelerType"); + } + writer.println("modelerType: " + code); + + MBeanAttributeInfo attrs[]=minfo.getAttributes(); + Object value=null; + + for( int i=0; i< attrs.length; i++ ) { + if( ! attrs[i].isReadable() ) continue; + if( ! isSupported( attrs[i].getType() )) continue; + String attName=attrs[i].getName(); + if( attName.indexOf( "=") >=0 || + attName.indexOf( ":") >=0 || + attName.indexOf( " ") >=0 ) { + continue; + } + + try { + value=server.getAttribute(oname, attName); + } catch( Throwable t) { + log("Error getting attribute " + oname + + " " + attName + " " + t.toString()); + continue; + } + if( value==null ) continue; + if( "modelerType".equals( attName)) continue; + String valueString=value.toString(); + writer.println( attName + ": " + escape(valueString)); + } + } catch (Exception e) { + // Ignore + } + writer.println(); + } + + } + + public String escape(String value) { + // The only invalid char is \n + // We also need to keep the string short and split it with \nSPACE + // XXX TODO + int idx=value.indexOf( "\n" ); + if( idx < 0 ) return value; + + int prev=0; + StringBuffer sb=new StringBuffer(); + while( idx >= 0 ) { + appendHead(sb, value, prev, idx); + + sb.append( "\\n\n "); + prev=idx+1; + if( idx==value.length() -1 ) break; + idx=value.indexOf('\n', idx+1); + } + if( prev < value.length() ) + appendHead( sb, value, prev, value.length()); + return sb.toString(); + } + + private void appendHead( StringBuffer sb, String value, int start, int end) { + if (end < 1) return; + + int pos=start; + while( end-pos > 78 ) { + sb.append( value.substring(pos, pos+78)); + sb.append( "\n "); + pos=pos+78; + } + sb.append( value.substring(pos,end)); + } + + public boolean isSupported( String type ) { + return true; + } +} diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/jmx/JmxObjectManagerSpi.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/jmx/JmxObjectManagerSpi.java new file mode 100644 index 000000000..47578ccd1 --- /dev/null +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/jmx/JmxObjectManagerSpi.java @@ -0,0 +1,41 @@ +/* + */ +package org.apache.tomcat.servlets.jmx; + +import java.util.logging.Logger; + +import org.apache.tomcat.integration.ObjectManager; +import org.apache.tomcat.util.modeler.Registry; + +/** + * Plugin for integration with JMX. + * + * All objects of interest are registered automatically. + */ +public class JmxObjectManagerSpi extends ObjectManager { + Registry registry; + Logger log = Logger.getLogger("JmxObjectManager"); + + public JmxObjectManagerSpi() { + registry = Registry.getRegistry(null, null); + } + + public void bind(String name, Object o) { + try { + registry.registerComponent(o, + ":name=\"" + name + "\"", null); + } catch (Exception e) { + log.severe("Error registering" + e); + } + } + + public void unbind(String name) { + registry.unregisterComponent(":name=\"" + name + "\""); + } + + @Override + public Object get(String key) { + return null; + } + +} diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/jsp/SimpleTemplateClassMapper.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/jsp/BaseJspLoader.java similarity index 60% rename from modules/tomcat-lite/java/org/apache/tomcat/servlets/jsp/SimpleTemplateClassMapper.java rename to modules/tomcat-lite/java/org/apache/tomcat/servlets/jsp/BaseJspLoader.java index d37db8886..87dc0a845 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/servlets/jsp/SimpleTemplateClassMapper.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/jsp/BaseJspLoader.java @@ -16,6 +16,7 @@ */ package org.apache.tomcat.servlets.jsp; +import java.io.IOException; import java.util.Vector; import javax.servlet.Servlet; @@ -24,45 +25,91 @@ import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; -import org.apache.tomcat.addons.UserTemplateClassMapper; /** - * Extracted from Jasper - maps a template file ( foo/my.jsp ) to a classname - * that is generated by the UserTemplateCompiler. + * Load a JSP generated by jasper. * - * TODO: transform this to an interface, paired with UserTemplateCompiler. + * Requires a 'jspc' servlet. * - * @author Costin Manolache + * This class has no dependencies on Jasper, it uses 2 servlets to integrate. */ -public class SimpleTemplateClassMapper implements UserTemplateClassMapper { +public abstract class BaseJspLoader { + boolean usePrecompiled = false; + + public static interface JspRuntime { + public void init(ServletContext ctx); + } + public static interface JspCompiler { + public void compileAndInit(ServletContext ctx, String jspUri, + ServletConfig cfg, + String classPath, String pkg); + } + /** * Load the proxied jsp, if any. * @param config * @throws ServletException + * @throws IOException */ public Servlet loadProxy(String jspFile, - ServletContext ctx, - ServletConfig config) throws ServletException { - String mangledClass = getClassName( jspFile ); + ServletContext ctx, + ServletConfig config) throws ServletException, IOException { + synchronized(this.getClass()) { + // So we don't have a direct dep on jasper... + Object attribute = ctx.getAttribute("jasper.jspRuntimeContext"); + if (attribute == null) { + try { + Class jsprt = Class.forName("org.apache.tomcat.servlets.jspc.JasperRuntime"); + JspRuntime rt = (JspRuntime)jsprt.newInstance(); + rt.init(ctx); + } catch (Throwable t) { + t.printStackTrace(); + return null; + } + } + } + String mangledClass = getClassName(ctx, jspFile ); + + // TODO: reloading filter: get the class file, + // compare with jsp file, use dependants + HttpServlet jsp = null; Class jspC = null; - + + String cp = getClassPath(ctx); + ClassLoader cl = getClassLoader(ctx); + // Already created - if( jspC == null ) { + if (usePrecompiled) { try { - jspC=Class.forName( mangledClass ); + jspC = cl.loadClass(mangledClass); } catch( Throwable t ) { + //t.printStackTrace(); // Not found - first try } } - + if (jspC == null) { + System.err.println("Recompile " + jspFile); // Class not found - needs to be compiled - return compileAndInitPage(ctx, jspFile, config); + compileAndInitPage(ctx, jspFile, config, cp); + } else { + System.err.println("Pre-compiled " + jspFile); } - + + if( jspC == null ) { + try { + jspC = cl.loadClass(mangledClass); + } catch( Throwable t ) { + //t.printStackTrace(); + } + } + if (jspC == null) { + throw new ServletException("Class not found " + mangledClass); + } + try { jsp=(HttpServlet)jspC.newInstance(); } catch( Throwable t ) { @@ -71,37 +118,75 @@ public class SimpleTemplateClassMapper implements UserTemplateClassMapper { jsp.init(config); return jsp; } + + public ClassLoader getClassLoader(ServletContext ctx) { + return null; + } + + public String getClassPath(ServletContext ctx) { + return null; + } + protected void compileAndInitPage(ServletContext ctx, + String jspUri, + ServletConfig cfg, + String classPath) + throws ServletException, IOException { + try { + Class jsprt = Class.forName("org.apache.tomcat.servlets.jspc.JspcServlet"); + JspCompiler rt = (JspCompiler) jsprt.newInstance(); + rt.compileAndInit(ctx, jspUri, cfg, classPath, getPackage(ctx, jspUri)); + } catch (Throwable t) { + t.printStackTrace(); + } + } + public boolean needsReload(String jspFile, Servlet s) { return false; } - protected Servlet compileAndInitPage(ServletContext ctx, - String jspUri, - ServletConfig cfg) - throws ServletException { - throw new ServletException("Pre-compiled page not found, please " + - "add a compiler addon to compile at runtime"); + public String getPackage(ServletContext ctx, String jspUri) { + String ver = "v" + ctx.getMajorVersion() + + ctx.getMinorVersion(); + + int iSep = jspUri.lastIndexOf('/') + 1; + String className = makeJavaIdentifier(jspUri.substring(iSep)); + String basePackageName = JSP_PACKAGE_NAME; + + iSep--; + String derivedPackageName = (iSep > 0) ? + makeJavaPackage(jspUri.substring(1,iSep)) : ""; + + return ver + "." + basePackageName; + } /** Convert an identifier to a class name, using jasper conventions + * @param ctx * * @param jspUri a relative JSP file * @return class name that would be generated by jasper */ - public String getClassName( String jspUri ) { + public String getClassName( ServletContext ctx, String jspUri ) { + // Generated code is different for different servlet API versions + // We could have a context running in both 2.5 and 3.0 with precompiled + // jsps + String ver = "v" + ctx.getMajorVersion() + + ctx.getMinorVersion(); + int iSep = jspUri.lastIndexOf('/') + 1; String className = makeJavaIdentifier(jspUri.substring(iSep)); String basePackageName = JSP_PACKAGE_NAME; iSep--; String derivedPackageName = (iSep > 0) ? - makeJavaPackage(jspUri.substring(1,iSep)) : ""; - + makeJavaPackage(jspUri.substring(1,iSep)) : ""; if (derivedPackageName.length() == 0) { return basePackageName + "." + className; } - return basePackageName + '.' + derivedPackageName + "." + className; + + return ver + "." + basePackageName + '.' + derivedPackageName + "." + + className; } // ------------- Copied from jasper --------------------------- @@ -109,8 +194,8 @@ public class SimpleTemplateClassMapper implements UserTemplateClassMapper { private static final String JSP_PACKAGE_NAME = "org.apache.jsp"; private static final String makeJavaIdentifier(String identifier) { - StringBuilder modifiedIdentifier = - new StringBuilder(identifier.length()); + StringBuffer modifiedIdentifier = + new StringBuffer(identifier.length()); if (!Character.isJavaIdentifierStart(identifier.charAt(0))) { modifiedIdentifier.append('_'); } @@ -144,7 +229,7 @@ public class SimpleTemplateClassMapper implements UserTemplateClassMapper { private static final String makeJavaPackage(String path) { String classNameComponents[] = split(path,"/"); - StringBuilder legalClassNames = new StringBuilder(); + StringBuffer legalClassNames = new StringBuffer(); for (int i = 0; i < classNameComponents.length; i++) { legalClassNames.append(makeJavaIdentifier(classNameComponents[i])); if (i < classNameComponents.length - 1) { @@ -210,5 +295,4 @@ public class SimpleTemplateClassMapper implements UserTemplateClassMapper { result[4] = Character.forDigit(ch & 0xf, 16); return new String(result); } - } diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/jsp/JasperCompilerTemplateClassMapper.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/jsp/JasperCompilerTemplateClassMapper.java deleted file mode 100644 index 4c744054c..000000000 --- a/modules/tomcat-lite/java/org/apache/tomcat/servlets/jsp/JasperCompilerTemplateClassMapper.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.servlets.jsp; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; - -import javax.naming.NamingException; -import javax.servlet.Servlet; -import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; - -import org.apache.jasper.EmbeddedServletOptions; -import org.apache.jasper.JasperException; -import org.apache.jasper.JspC; -import org.apache.jasper.Options; -import org.apache.jasper.compiler.JspRuntimeContext; -import org.apache.jasper.servlet.JspServletWrapper; -import org.apache.tomcat.InstanceManager; - -/** - * The actual compiler. Maps and compile a jsp-file to a class. - */ -public class JasperCompilerTemplateClassMapper - extends SimpleTemplateClassMapper { - - public void init(ServletConfig config) { - this.config = config; - ServletContext context = config.getServletContext(); - context.setAttribute(InstanceManager.class.getName(), - new InstanceManager() { - - public void destroyInstance(Object arg0) - throws IllegalAccessException, - InvocationTargetException { - } - - public Object newInstance(String arg0) - throws IllegalAccessException, - InvocationTargetException, NamingException, - InstantiationException, ClassNotFoundException { - return newInstance(arg0, - this.getClass().getClassLoader()); - } - - public void newInstance(Object o) - throws IllegalAccessException, - InvocationTargetException, NamingException { - } - - public Object newInstance(String className, - ClassLoader classLoader) - throws IllegalAccessException, - InvocationTargetException, NamingException, - InstantiationException, ClassNotFoundException { - Class clazz = classLoader.loadClass(className); - return clazz.newInstance(); - } - - }); - // Initialize the JSP Runtime Context - options = new EmbeddedServletOptions(config, context); - - rctxt = new JspRuntimeContext(context, options); - String basePath = context.getRealPath("/"); - File f = new File(basePath + "/WEB-INF/classes"); - f.mkdirs(); - //fileS.initParams.put("scratchdir", f.getAbsolutePath()); - // if load-on-startup: allow other servlets to find us - - - } - - private Options options; - private JspRuntimeContext rctxt; - private ServletConfig config; - - public boolean needsReload(String jspFile, Servlet s) { - JspServletWrapper wrapper = - (JspServletWrapper) rctxt.getWrapper(jspFile); - // TODO: extract outdate info, compilation date, etc - return false; - } - - protected Servlet compileAndInitPage(ServletContext ctx, - String jspUri, - ServletConfig cfg) - throws ServletException { - try { - if (config == null) { - init(cfg); - } - JspServletWrapper wrapper = - (JspServletWrapper) rctxt.getWrapper(jspUri); - if (wrapper == null) { - synchronized(this) { - wrapper = (JspServletWrapper) rctxt.getWrapper(jspUri); - if (wrapper == null) { - // Check if the requested JSP page exists, to avoid - // creating unnecessary directories and files. - if (null == ctx.getResource(jspUri)) { - return null; - } - //boolean isErrorPage = exception != null; - wrapper = new JspServletWrapper(cfg, options, jspUri, - false, rctxt); - rctxt.addWrapper(jspUri,wrapper); - } - } - } - - wrapper.getJspEngineContext().compile(); - return wrapper.getServlet(); - } catch (IOException ex) { - throw new ServletException(ex); - } - } - - /** - * - * Do the compilation - without JspServletWrapper - * - * Options: - * - jasper.jar in classpath, we do Class.forName for main() - * - TODO: exec jasper.sh ( or any other script set in params ) - * - TODO: redirect to a different servlet - * - * Not used right - see previous method for a safer approach - * - * @param ctx - * @param jspPath - */ - public void compileJspDirect(ServletContext ctx, String jspPath) { - //ServletContextImpl ctx = (ServletContextImpl)sctx; - // Params to pass to jspc: - // classpath - // webapp base dir - String baseDir = ctx.getRealPath("/"); - // jsp path ( rel. base dir ) - - JspC jspc = new JspC(); - jspc.setUriroot(baseDir); - jspc.setTrimSpaces(false); - jspc.setPoolingEnabled(true); - jspc.setErrorOnUseBeanInvalidClassAttribute(false); - jspc.setClassDebugInfo(true); - jspc.setCaching(true); - jspc.setSmapDumped(true); - - try { - jspc.execute(); - } catch (JasperException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } -} \ No newline at end of file diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/jsp/JspFileTemplateServlet.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/jsp/JspFileTemplateServlet.java deleted file mode 100644 index 85c1cc023..000000000 --- a/modules/tomcat-lite/java/org/apache/tomcat/servlets/jsp/JspFileTemplateServlet.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.servlets.jsp; - -import java.io.IOException; - -import javax.servlet.Servlet; -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.tomcat.addons.UserTemplateClassMapper; -import org.apache.tomcat.integration.ObjectManager; - -/** - * Support for config. - * - * A servlet can be configured with a jsp-file instead of a class. This can - * be translated into a regular servlet, with JspFileTemplateServlet class and - * the jsp-file as init parameter. - * - * This servlet is not jsp specific - you can put any templating file in the - * jsp-file config ( if you can ignore the jsp in the name of the attribute ). - * The file will be converted to a servlet by a custom addon ( jasper in most - * cases ) - * - * @author Costin Manolache - */ -public class JspFileTemplateServlet extends HttpServlet { - - String jspFile; - Servlet realJspServlet; - - UserTemplateClassMapper mapper; - - /** - * If called from a servlet, compile the servlet and init it. - */ - public void init(ServletConfig config) throws ServletException { - super.init(config); - // Support - String jspFileParam = config.getInitParameter("jsp-file"); - // TODO: use extension to find the right UserTemplateClassMapper. - ObjectManager om = - (ObjectManager) config.getServletContext().getAttribute(ObjectManager.ATTRIBUTE); - mapper = - (UserTemplateClassMapper) om.get( - UserTemplateClassMapper.class); - if (mapper == null) { - mapper = new SimpleTemplateClassMapper(); - } - - if (jspFile == null && jspFileParam != null) { - jspFile = jspFileParam; - } - // exception will be thrown if not set properly - realJspServlet = mapper.loadProxy(jspFile, getServletContext(), - config); - realJspServlet.init(config); - } - - public void setJspFile(String jspFile) { - this.jspFile = jspFile; - } - - protected void service(HttpServletRequest req, HttpServletResponse res) - throws ServletException, IOException - { - // TODO: support reload - - // realJspServlet will be set - init will fail otherwise. - realJspServlet.service(req, res); - } -} diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/jsp/WildcardTemplateServlet.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/jsp/WildcardTemplateServlet.java index 609dbc203..41a98e515 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/servlets/jsp/WildcardTemplateServlet.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/jsp/WildcardTemplateServlet.java @@ -22,13 +22,11 @@ import java.util.HashMap; import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletException; +import javax.servlet.UnavailableException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.apache.tomcat.addons.UserTemplateClassMapper; -import org.apache.tomcat.integration.ObjectManager; - /** * @@ -39,20 +37,22 @@ public class WildcardTemplateServlet extends HttpServlet { // for the '*.jsp' case - need to keep track of the jsps HashMap jsps=new HashMap(); - UserTemplateClassMapper mapper; + BaseJspLoader mapper; /** * If called from a servlet, compile the servlet and init it. */ public void init(ServletConfig config) throws ServletException { super.init(config); - ObjectManager om = - (ObjectManager) config.getServletContext().getAttribute(ObjectManager.ATTRIBUTE); - mapper = - (UserTemplateClassMapper) om.get( - UserTemplateClassMapper.class); - if (mapper == null) { - mapper = new SimpleTemplateClassMapper(); + String mapperCN = config.getInitParameter("mapper"); + if (mapperCN == null) { + throw new UnavailableException("can't create mapper"); + } + try { + Class c = Class.forName(mapperCN); + mapper = (BaseJspLoader) c.newInstance(); + } catch (Throwable t) { + throw new UnavailableException("can't create mapper"); } } diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/jspc/JasperRuntime.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/jspc/JasperRuntime.java new file mode 100644 index 000000000..df8e8028f --- /dev/null +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/jspc/JasperRuntime.java @@ -0,0 +1,188 @@ +/* + */ +package org.apache.tomcat.servlets.jspc; + +import java.io.File; +import java.util.Map; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.jasper.Options; +import org.apache.jasper.compiler.JspConfig; +import org.apache.jasper.compiler.JspRuntimeContext; +import org.apache.jasper.compiler.TagPluginManager; +import org.apache.jasper.compiler.TldLocationsCache; +import org.apache.tomcat.servlets.jsp.BaseJspLoader; + +public class JasperRuntime extends HttpServlet implements BaseJspLoader.JspRuntime { + + // TODO: add DefaultAnnotationProcessor + // TODO: implement the options + private JspRuntimeContext jspRuntimeContext; + + public void init(ServletConfig cfg) throws ServletException { + super.init(cfg); + ServletContext ctx = cfg.getServletContext(); + init(ctx); + } + + public void doGet(HttpServletRequest req, HttpServletResponse res) { + + } + + @Override + public void init(ServletContext ctx) { + jspRuntimeContext = new JspRuntimeContext(ctx, new Options() { + @Override + public boolean genStringAsCharArray() { + return false; + } + + @Override + public Map getCache() { + return null; + } + + @Override + public int getCheckInterval() { + return 0; + } + + @Override + public boolean getClassDebugInfo() { + return false; + } + + @Override + public String getClassPath() { + return null; + } + + @Override + public String getCompiler() { + return null; + } + + @Override + public String getCompilerClassName() { + return null; + } + + @Override + public String getCompilerSourceVM() { + return null; + } + + @Override + public String getCompilerTargetVM() { + return null; + } + + @Override + public boolean getDevelopment() { + return false; + } + + @Override + public boolean getDisplaySourceFragment() { + return false; + } + + @Override + public boolean getErrorOnUseBeanInvalidClassAttribute() { + return false; + } + + @Override + public boolean getFork() { + return false; + } + + @Override + public String getIeClassId() { + return null; + } + + @Override + public String getJavaEncoding() { + return null; + } + + @Override + public JspConfig getJspConfig() { + return null; + } + + @Override + public boolean getKeepGenerated() { + return false; + } + + @Override + public boolean getMappedFile() { + return false; + } + + @Override + public int getModificationTestInterval() { + return 0; + } + + @Override + public File getScratchDir() { + return null; + } + + public boolean getSendErrorToClient() { + return false; + } + + @Override + public TagPluginManager getTagPluginManager() { + return null; + } + + @Override + public TldLocationsCache getTldLocationsCache() { + return null; + } + + @Override + public boolean getTrimSpaces() { + return false; + } + + @Override + public boolean isCaching() { + return false; + } + + @Override + public boolean isPoolingEnabled() { + return false; + } + + @Override + public boolean isSmapDumped() { + return false; + } + + @Override + public boolean isSmapSuppressed() { + return false; + } + + @Override + public boolean isXpoweredBy() { + return false; + } + }); + + ctx.setAttribute("jasper.jspRuntimeContext", jspRuntimeContext); + } +} diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/jspc/JspcServlet.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/jspc/JspcServlet.java new file mode 100644 index 000000000..f2b710568 --- /dev/null +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/jspc/JspcServlet.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tomcat.servlets.jspc; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.jasper.JasperException; +import org.apache.jasper.JspC; +import org.apache.tomcat.servlets.jsp.BaseJspLoader; + +/** + * The actual compiler. Maps and compile a jsp-file to a class. + */ +public class JspcServlet extends HttpServlet implements BaseJspLoader.JspCompiler { + + public void doGet(HttpServletRequest req, HttpServletResponse res) + throws ServletException { + + // TODO: allow only local calls ? + + // relative to context + String jspFiles = req.getParameter("jspFiles"); + String classPath = req.getParameter("classPath"); + String pkg = req.getParameter("pkg"); + + compileAndInit(getServletContext(), + jspFiles, getServletConfig(), classPath, pkg); + } + + @Override + public void compileAndInit(ServletContext ctx, String jspFiles, + ServletConfig cfg, String classPath, String pkg) { + + if (jspFiles.startsWith("/")) { + jspFiles = jspFiles.substring(1); + } + String baseDir = ctx.getRealPath("/"); + + JspC jspc = new JspC(); + + jspc.setUriroot(baseDir); + jspc.setTrimSpaces(false); + jspc.setPoolingEnabled(true); + jspc.setErrorOnUseBeanInvalidClassAttribute(false); + jspc.setClassDebugInfo(true); + jspc.setCaching(true); + jspc.setSmapDumped(true); + jspc.setGenStringAsCharArray(true); + + jspc.setJspFiles(jspFiles); + + jspc.setVerbose(10); + + jspc.setPackage(pkg); + + jspc.setOutputDir(baseDir + "WEB-INF/tmp"); + jspc.setCompile(true); + //jspc.setCompiler("jdt"); + jspc.setClassPath(classPath); + + try { + jspc.execute(); + } catch (JasperException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/sec/AccessFilter.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/sec/AccessFilter.java index 5af1e7f52..2120c4434 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/servlets/sec/AccessFilter.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/sec/AccessFilter.java @@ -32,7 +32,6 @@ import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.apache.tomcat.addons.UserAuthentication; /** diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/sec/BasicAuthentication.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/sec/BasicAuthentication.java index c17c8296b..cfcb212cf 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/servlets/sec/BasicAuthentication.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/sec/BasicAuthentication.java @@ -23,7 +23,6 @@ import java.security.Principal; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.apache.tomcat.addons.UserAuthentication; /** diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/sec/FormAuthentication.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/sec/FormAuthentication.java index 5535790d5..f17c6a07b 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/servlets/sec/FormAuthentication.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/sec/FormAuthentication.java @@ -23,7 +23,6 @@ import java.security.Principal; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.apache.tomcat.addons.UserAuthentication; /** diff --git a/modules/tomcat-lite/java/org/apache/tomcat/addons/UserAuthentication.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/sec/UserAuthentication.java similarity index 62% rename from modules/tomcat-lite/java/org/apache/tomcat/addons/UserAuthentication.java rename to modules/tomcat-lite/java/org/apache/tomcat/servlets/sec/UserAuthentication.java index 88a0adc85..62b4b9799 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/addons/UserAuthentication.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/sec/UserAuthentication.java @@ -1,21 +1,6 @@ /* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ - -package org.apache.tomcat.addons; +package org.apache.tomcat.servlets.sec; import java.io.IOException; import java.security.Principal; diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/session/RandomGenerator.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/session/RandomGenerator.java index 22e86de74..6bd1a338e 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/servlets/session/RandomGenerator.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/session/RandomGenerator.java @@ -363,4 +363,4 @@ public class RandomGenerator { public void setSessionIdLength(int idLength) { this.sessionIdLength = idLength; } -} \ No newline at end of file +} diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/session/SimpleSessionManager.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/session/SimpleSessionManager.java index ceedb5ded..64555a637 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/servlets/session/SimpleSessionManager.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/session/SimpleSessionManager.java @@ -33,7 +33,6 @@ import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; -import org.apache.tomcat.addons.UserSessionManager; // TODO: move 'expiring objects' to a separate utility class // TODO: hook the background thread diff --git a/modules/tomcat-lite/java/org/apache/tomcat/addons/UserSessionManager.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/session/UserSessionManager.java similarity index 55% rename from modules/tomcat-lite/java/org/apache/tomcat/addons/UserSessionManager.java rename to modules/tomcat-lite/java/org/apache/tomcat/servlets/session/UserSessionManager.java index c450b5f8e..82c30c07c 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/addons/UserSessionManager.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/session/UserSessionManager.java @@ -1,21 +1,6 @@ /* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ - -package org.apache.tomcat.addons; +package org.apache.tomcat.servlets.session; import java.io.IOException; diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/util/Base64.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/util/Base64.java new file mode 100644 index 000000000..1f4228644 --- /dev/null +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/util/Base64.java @@ -0,0 +1,269 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.servlets.util; + +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * This class provides encode/decode for RFC 2045 Base64 as + * defined by RFC 2045, N. Freed and N. Borenstein. + * RFC 2045: Multipurpose Internet Mail Extensions (MIME) + * Part One: Format of Internet Message Bodies. Reference + * 1996 Available at: http://www.ietf.org/rfc/rfc2045.txt + * This class is used by XML Schema binary format validation + * + * @author Jeffrey Rodriguez + * @version $Revision: 467222 $ $Date: 2006-10-23 20:17:11 -0700 (Mon, 23 Oct 2006) $ + */ + +public final class Base64 { + + + private static Logger log= + Logger.getLogger( Base64.class.getName() ); + + static private final int BASELENGTH = 255; + static private final int LOOKUPLENGTH = 63; + static private final int TWENTYFOURBITGROUP = 24; + static private final int EIGHTBIT = 8; + static private final int SIXTEENBIT = 16; + static private final int SIXBIT = 6; + static private final int FOURBYTE = 4; + + + static private final byte PAD = ( byte ) '='; + static private byte [] base64Alphabet = new byte[BASELENGTH]; + static private byte [] lookUpBase64Alphabet = new byte[LOOKUPLENGTH + 1]; + + static { + + for (int i = 0; i= 'A'; i-- ) { + base64Alphabet[i] = (byte) (i-'A'); + } + for ( int i = 'z'; i>= 'a'; i--) { + base64Alphabet[i] = (byte) ( i-'a' + 26); + } + + for ( int i = '9'; i >= '0'; i--) { + base64Alphabet[i] = (byte) (i-'0' + 52); + } + + base64Alphabet['+'] = 62; + base64Alphabet['/'] = 63; + String lookupString = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + + "0123456789+/"; + + for (int i = 0; i < lookupString.length(); i++ ) { + lookUpBase64Alphabet[i] = (byte) lookupString.charAt(i); + } + } + + + static boolean isBase64( byte octect ) { + //shall we ignore white space? JEFF?? + return(octect == PAD || base64Alphabet[octect] != -1 ); + } + + + static boolean isArrayByteBase64( byte[] arrayOctect ) { + int length = arrayOctect.length; + if ( length == 0 ) + return false; + for ( int i=0; i < length; i++ ) { + if ( Base64.isBase64( arrayOctect[i] ) == false) + return false; + } + return true; + } + + /** + * Encodes hex octects into Base64 + * + * @param binaryData Array containing binaryData + * @return Encoded Base64 array + */ + public static byte[] encode( byte[] binaryData ) { + int lengthDataBits = binaryData.length*EIGHTBIT; + int fewerThan24bits = lengthDataBits%TWENTYFOURBITGROUP; + int numberTriplets = lengthDataBits/TWENTYFOURBITGROUP; + byte encodedData[] = null; + + + if ( fewerThan24bits != 0 ) //data not divisible by 24 bit + encodedData = new byte[ (numberTriplets + 1 )*4 ]; + else // 16 or 8 bit + encodedData = new byte[ numberTriplets*4 ]; + + int k=0, l=0, b1=0,b2=0,b3=0; + + int encodedIndex = 0; + int dataIndex = 0; + int i = 0; + for ( i = 0; i>2 ]; + encodedData[encodedIndex+1] = lookUpBase64Alphabet[(b2 >>4 ) | +( k<<4 )]; + encodedData[encodedIndex+2] = lookUpBase64Alphabet[ (l <<2 ) | +( b3>>6)]; + encodedData[encodedIndex+3] = lookUpBase64Alphabet[ b3 & 0x3f ]; + } + + // form integral number of 6-bit groups + dataIndex = i*3; + encodedIndex = i*4; + if (fewerThan24bits == EIGHTBIT ) { + b1 = binaryData[dataIndex]; + k = (byte) ( b1 &0x03 ); + encodedData[encodedIndex] = lookUpBase64Alphabet[ b1 >>2 ]; + encodedData[encodedIndex + 1] = lookUpBase64Alphabet[ k<<4 ]; + encodedData[encodedIndex + 2] = PAD; + encodedData[encodedIndex + 3] = PAD; + } else if ( fewerThan24bits == SIXTEENBIT ) { + + b1 = binaryData[dataIndex]; + b2 = binaryData[dataIndex +1 ]; + l = ( byte ) ( b2 &0x0f ); + k = ( byte ) ( b1 &0x03 ); + encodedData[encodedIndex] = lookUpBase64Alphabet[ b1 >>2 ]; + encodedData[encodedIndex + 1] = lookUpBase64Alphabet[ (b2 >>4 ) +| ( k<<4 )]; + encodedData[encodedIndex + 2] = lookUpBase64Alphabet[ l<<2 ]; + encodedData[encodedIndex + 3] = PAD; + } + return encodedData; + } + + + /** + * Decodes Base64 data into octects + * + * @param base64Data Byte array containing Base64 data + * @return Array containind decoded data. + */ + public static byte[] decode( byte[] base64Data ) { + int numberQuadruple = base64Data.length/FOURBYTE; + byte decodedData[] = null; + byte b1=0,b2=0,b3=0, b4=0, marker0=0, marker1=0; + + // Throw away anything not in base64Data + // Adjust size + + int encodedIndex = 0; + int dataIndex = 0; + decodedData = new byte[ numberQuadruple*3 + 1 ]; + + for (int i = 0; i>4 ) ; + decodedData[encodedIndex+1] = (byte)(((b2 & 0xf)<<4 ) |( +(b3>>2) & 0xf) ); + decodedData[encodedIndex+2] = (byte)( b3<<6 | b4 ); + } else if ( marker0 == PAD ) { //Two PAD e.g. 3c[Pad][Pad] + decodedData[encodedIndex] = (byte)( b1 <<2 | b2>>4 ) ; + decodedData[encodedIndex+1] = (byte)((b2 & 0xf)<<4 ); + decodedData[encodedIndex+2] = (byte) 0; + } else if ( marker1 == PAD ) { //One PAD e.g. 3cQ[Pad] + b3 = base64Alphabet[ marker0 ]; + + decodedData[encodedIndex] = (byte)( b1 <<2 | b2>>4 ); + decodedData[encodedIndex+1] = (byte)(((b2 & 0xf)<<4 ) |( +(b3>>2) & 0xf) ); + decodedData[encodedIndex+2] = (byte)( b3<<6); + } + encodedIndex += 3; + } + return decodedData; + + } + + static final int base64[]= { + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, + 64, 0, 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, 64, 64, 64, 64, 64, + 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 + }; + + public static String base64Decode( String orig ) { + char chars[]=orig.toCharArray(); + StringBuffer sb=new StringBuffer(); + int i=0; + + int shift = 0; // # of excess bits stored in accum + int acc = 0; + + for (i=0; i= 64 ) { + if( chars[i] != '=' ) + if (log.isLoggable(Level.INFO)) + log.info("Wrong char in base64: " + chars[i]); + } else { + acc= ( acc << 6 ) | v; + shift += 6; + if ( shift >= 8 ) { + shift -= 8; + sb.append( (char) ((acc >> shift) & 0xff)); + } + } + } + return sb.toString(); + } + + +} + diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/util/FastHttpDateFormat.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/util/FastHttpDateFormat.java new file mode 100644 index 000000000..7c2f905d6 --- /dev/null +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/util/FastHttpDateFormat.java @@ -0,0 +1,231 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.servlets.util; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Utility class to generate HTTP dates. + * + * @author Remy Maucherat + */ +public final class FastHttpDateFormat { + + + // -------------------------------------------------------------- Variables + + + protected static final int CACHE_SIZE = + Integer.parseInt(System.getProperty("org.apache.tomcat.util.http.FastHttpDateFormat.CACHE_SIZE", "1000")); + + + /** + * HTTP date format. + */ + protected static final SimpleDateFormat format = + new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); + + + /** + * The set of SimpleDateFormat formats to use in getDateHeader(). + */ + protected static final SimpleDateFormat formats[] = { + new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US), + new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US), + new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US) + }; + + + protected final static TimeZone gmtZone = TimeZone.getTimeZone("GMT"); + + + /** + * GMT timezone - all HTTP dates are on GMT + */ + static { + + format.setTimeZone(gmtZone); + + formats[0].setTimeZone(gmtZone); + formats[1].setTimeZone(gmtZone); + formats[2].setTimeZone(gmtZone); + + } + + + /** + * Instant on which the currentDate object was generated. + */ + protected static long currentDateGenerated = 0L; + + + /** + * Current formatted date. + */ + protected static String currentDate = null; + + + /** + * Formatter cache. + */ + protected static final ConcurrentHashMap formatCache = + new ConcurrentHashMap(CACHE_SIZE); + + + /** + * Parser cache. + */ + protected static final ConcurrentHashMap parseCache = + new ConcurrentHashMap(CACHE_SIZE); + + + // --------------------------------------------------------- Public Methods + + + /** + * Get the current date in HTTP format. + */ + public static final String getCurrentDate() { + + long now = System.currentTimeMillis(); + if ((now - currentDateGenerated) > 1000) { + synchronized (format) { + if ((now - currentDateGenerated) > 1000) { + currentDateGenerated = now; + currentDate = format.format(new Date(now)); + } + } + } + return currentDate; + + } + + + /** + * Get the HTTP format of the specified date. + */ + public static final String formatDate + (long value, DateFormat threadLocalformat) { + + Long longValue = new Long(value); + String cachedDate = formatCache.get(longValue); + if (cachedDate != null) + return cachedDate; + + String newDate = null; + Date dateValue = new Date(value); + if (threadLocalformat != null) { + newDate = threadLocalformat.format(dateValue); + updateFormatCache(longValue, newDate); + } else { + synchronized (formatCache) { + synchronized (format) { + newDate = format.format(dateValue); + } + updateFormatCache(longValue, newDate); + } + } + return newDate; + + } + + + /** + * Try to parse the given date as a HTTP date. + */ + public static final long parseDate(String value, + DateFormat[] threadLocalformats) { + + Long cachedDate = parseCache.get(value); + if (cachedDate != null) + return cachedDate.longValue(); + + Long date = null; + if (threadLocalformats != null) { + date = internalParseDate(value, threadLocalformats); + updateParseCache(value, date); + } else { + synchronized (parseCache) { + date = internalParseDate(value, formats); + updateParseCache(value, date); + } + } + if (date == null) { + return (-1L); + } else { + return date.longValue(); + } + + } + + + /** + * Parse date with given formatters. + */ + private static final Long internalParseDate + (String value, DateFormat[] formats) { + Date date = null; + for (int i = 0; (date == null) && (i < formats.length); i++) { + try { + date = formats[i].parse(value); + } catch (ParseException e) { + ; + } + } + if (date == null) { + return null; + } + return new Long(date.getTime()); + } + + + /** + * Update cache. + */ + private static void updateFormatCache(Long key, String value) { + if (value == null) { + return; + } + if (formatCache.size() > CACHE_SIZE) { + formatCache.clear(); + } + formatCache.put(key, value); + } + + + /** + * Update cache. + */ + private static void updateParseCache(String key, Long value) { + if (value == null) { + return; + } + if (parseCache.size() > CACHE_SIZE) { + parseCache.clear(); + } + parseCache.put(key, value); + } + + +} diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/util/MimeMap.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/util/MimeMap.java new file mode 100644 index 000000000..a1731955c --- /dev/null +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/util/MimeMap.java @@ -0,0 +1,195 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.servlets.util; + +import java.net.FileNameMap; +import java.util.Enumeration; +import java.util.Hashtable; + + +/** + * A mime type map that implements the java.net.FileNameMap interface. + * + * @author James Duncan Davidson [duncan@eng.sun.com] + * @author Jason Hunter [jch@eng.sun.com] + */ +public class MimeMap implements FileNameMap { + + // Defaults - all of them are "well-known" types, + // you can add using normal web.xml. + + public static Hashtable defaultMap = + new Hashtable(101); + static { + defaultMap.put("txt", "text/plain"); + defaultMap.put("css", "text/css"); + defaultMap.put("html","text/html"); + defaultMap.put("htm", "text/html"); + defaultMap.put("gif", "image/gif"); + defaultMap.put("jpg", "image/jpeg"); + defaultMap.put("jpe", "image/jpeg"); + defaultMap.put("jpeg", "image/jpeg"); + defaultMap.put("png", "image/png"); + defaultMap.put("java", "text/plain"); + defaultMap.put("body", "text/html"); + defaultMap.put("rtx", "text/richtext"); + defaultMap.put("tsv", "text/tab-separated-values"); + defaultMap.put("etx", "text/x-setext"); + defaultMap.put("ps", "application/x-postscript"); + defaultMap.put("class", "application/java"); + defaultMap.put("csh", "application/x-csh"); + defaultMap.put("sh", "application/x-sh"); + defaultMap.put("tcl", "application/x-tcl"); + defaultMap.put("tex", "application/x-tex"); + defaultMap.put("texinfo", "application/x-texinfo"); + defaultMap.put("texi", "application/x-texinfo"); + defaultMap.put("t", "application/x-troff"); + defaultMap.put("tr", "application/x-troff"); + defaultMap.put("roff", "application/x-troff"); + defaultMap.put("man", "application/x-troff-man"); + defaultMap.put("me", "application/x-troff-me"); + defaultMap.put("ms", "application/x-wais-source"); + defaultMap.put("src", "application/x-wais-source"); + defaultMap.put("zip", "application/zip"); + defaultMap.put("bcpio", "application/x-bcpio"); + defaultMap.put("cpio", "application/x-cpio"); + defaultMap.put("gtar", "application/x-gtar"); + defaultMap.put("shar", "application/x-shar"); + defaultMap.put("sv4cpio", "application/x-sv4cpio"); + defaultMap.put("sv4crc", "application/x-sv4crc"); + defaultMap.put("tar", "application/x-tar"); + defaultMap.put("ustar", "application/x-ustar"); + defaultMap.put("dvi", "application/x-dvi"); + defaultMap.put("hdf", "application/x-hdf"); + defaultMap.put("latex", "application/x-latex"); + defaultMap.put("bin", "application/octet-stream"); + defaultMap.put("oda", "application/oda"); + defaultMap.put("pdf", "application/pdf"); + defaultMap.put("ps", "application/postscript"); + defaultMap.put("eps", "application/postscript"); + defaultMap.put("ai", "application/postscript"); + defaultMap.put("rtf", "application/rtf"); + defaultMap.put("nc", "application/x-netcdf"); + defaultMap.put("cdf", "application/x-netcdf"); + defaultMap.put("cer", "application/x-x509-ca-cert"); + defaultMap.put("exe", "application/octet-stream"); + defaultMap.put("gz", "application/x-gzip"); + defaultMap.put("Z", "application/x-compress"); + defaultMap.put("z", "application/x-compress"); + defaultMap.put("hqx", "application/mac-binhex40"); + defaultMap.put("mif", "application/x-mif"); + defaultMap.put("ief", "image/ief"); + defaultMap.put("tiff", "image/tiff"); + defaultMap.put("tif", "image/tiff"); + defaultMap.put("ras", "image/x-cmu-raster"); + defaultMap.put("pnm", "image/x-portable-anymap"); + defaultMap.put("pbm", "image/x-portable-bitmap"); + defaultMap.put("pgm", "image/x-portable-graymap"); + defaultMap.put("ppm", "image/x-portable-pixmap"); + defaultMap.put("rgb", "image/x-rgb"); + defaultMap.put("xbm", "image/x-xbitmap"); + defaultMap.put("xpm", "image/x-xpixmap"); + defaultMap.put("xwd", "image/x-xwindowdump"); + defaultMap.put("au", "audio/basic"); + defaultMap.put("snd", "audio/basic"); + defaultMap.put("aif", "audio/x-aiff"); + defaultMap.put("aiff", "audio/x-aiff"); + defaultMap.put("aifc", "audio/x-aiff"); + defaultMap.put("wav", "audio/x-wav"); + defaultMap.put("mpeg", "video/mpeg"); + defaultMap.put("mpg", "video/mpeg"); + defaultMap.put("mpe", "video/mpeg"); + defaultMap.put("qt", "video/quicktime"); + defaultMap.put("mov", "video/quicktime"); + defaultMap.put("avi", "video/x-msvideo"); + defaultMap.put("movie", "video/x-sgi-movie"); + defaultMap.put("avx", "video/x-rad-screenplay"); + defaultMap.put("wrl", "x-world/x-vrml"); + defaultMap.put("mpv2", "video/mpeg2"); + + /* Add XML related MIMEs */ + + defaultMap.put("xml", "text/xml"); + defaultMap.put("xsl", "text/xml"); + defaultMap.put("svg", "image/svg+xml"); + defaultMap.put("svgz", "image/svg+xml"); + defaultMap.put("wbmp", "image/vnd.wap.wbmp"); + defaultMap.put("wml", "text/vnd.wap.wml"); + defaultMap.put("wmlc", "application/vnd.wap.wmlc"); + defaultMap.put("wmls", "text/vnd.wap.wmlscript"); + defaultMap.put("wmlscriptc", "application/vnd.wap.wmlscriptc"); + } + + + private Hashtable map = new Hashtable(); + + public void addContentType(String extn, String type) { + map.put(extn, type.toLowerCase()); + } + + public Enumeration getExtensions() { + return map.keys(); + } + + public String getMimeType(String ext) { + return getContentTypeFor(ext); + } + + public String getContentType(String extn) { + String type = (String)map.get(extn.toLowerCase()); + if( type == null ) type=(String)defaultMap.get( extn ); + return type; + } + + public void removeContentType(String extn) { + map.remove(extn.toLowerCase()); + } + + /** Get extension of file, without fragment id + */ + public static String getExtension( String fileName ) { + // play it safe and get rid of any fragment id + // that might be there + int length=fileName.length(); + + int newEnd = fileName.lastIndexOf('#'); + if( newEnd== -1 ) newEnd=length; + // Instead of creating a new string. + // if (i != -1) { + // fileName = fileName.substring(0, i); + // } + int i = fileName.lastIndexOf('.', newEnd ); + if (i != -1) { + return fileName.substring(i + 1, newEnd ); + } else { + // no extension, no content type + return null; + } + } + + public String getContentTypeFor(String fileName) { + String extn=getExtension( fileName ); + if (extn!=null) { + return getContentType(extn); + } else { + // no extension, no content type + return null; + } + } + +} diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/util/RequestUtil.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/util/RequestUtil.java index df789c804..fba1b9681 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/servlets/util/RequestUtil.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/util/RequestUtil.java @@ -57,7 +57,7 @@ public final class RequestUtil { */ public static String encodeCookie(Cookie cookie) { - StringBuilder buf = new StringBuilder( cookie.getName() ); + StringBuffer buf = new StringBuffer( cookie.getName() ); buf.append("="); buf.append(cookie.getValue()); diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/util/URLEncoder.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/util/URLEncoder.java new file mode 100644 index 000000000..0d52219cd --- /dev/null +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/util/URLEncoder.java @@ -0,0 +1,100 @@ +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tomcat.servlets.util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.util.BitSet; + +/** + * + * This class is very similar to the java.net.URLEncoder class. + * + * Unfortunately, with java.net.URLEncoder there is no way to specify to the + * java.net.URLEncoder which characters should NOT be encoded. + * + * This code was moved from DefaultServlet.java + * + * @author Craig R. McClanahan + * @author Remy Maucherat + */ +public class URLEncoder { + protected static final char[] hexadecimal = + {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F'}; + + //Array containing the safe characters set. + protected BitSet safeCharacters = new BitSet(256); + + public URLEncoder() { + for (char i = 'a'; i <= 'z'; i++) { + addSafeCharacter(i); + } + for (char i = 'A'; i <= 'Z'; i++) { + addSafeCharacter(i); + } + for (char i = '0'; i <= '9'; i++) { + addSafeCharacter(i); + } + } + + public void addSafeCharacter( char c ) { + safeCharacters.set( c ); + } + + public String encode( String path ) { + int maxBytesPerChar = 10; + int caseDiff = ('a' - 'A'); + StringBuffer rewrittenPath = new StringBuffer(path.length()); + ByteArrayOutputStream buf = new ByteArrayOutputStream(maxBytesPerChar); + OutputStreamWriter writer = null; + try { + writer = new OutputStreamWriter(buf, "UTF8"); + } catch (Exception e) { + e.printStackTrace(); + writer = new OutputStreamWriter(buf); + } + + for (int i = 0; i < path.length(); i++) { + int c = (int) path.charAt(i); + if (safeCharacters.get(c)) { + rewrittenPath.append((char)c); + } else { + // convert to external encoding before hex conversion + try { + writer.write((char)c); + writer.flush(); + } catch(IOException e) { + buf.reset(); + continue; + } + byte[] ba = buf.toByteArray(); + for (int j = 0; j < ba.length; j++) { + // Converting each byte in the buffer + byte toEncode = ba[j]; + rewrittenPath.append('%'); + int low = (int) (toEncode & 0x0f); + int high = (int) ((toEncode & 0xf0) >> 4); + rewrittenPath.append(hexadecimal[high]); + rewrittenPath.append(hexadecimal[low]); + } + buf.reset(); + } + } + return rewrittenPath.toString(); + } +} -- 2.11.0