+++ /dev/null
-/*
- * 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);
- }
-}
+++ /dev/null
-/*
- * 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.IOException;
-import java.security.Principal;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-/**
- * Plugin for user auth.
- *
- * This interface should support all common forms of auth,
- * including Basic, Digest, Form and various other auth
- * standards - the plugin has full control over request and
- * response.
- *
- * Container will verify the security constraints on URLs and
- * call this for all URLs that have constraints. The plugin can
- * either authenticate and return the principal, or change
- * the response - redirect, add headers, send content.
- *
- * Alternative: a simple Filter can do the same, with some conventions
- * to support it ( attributes ).
- *
- * @author Costin Manolache
- */
-public interface UserAuthentication {
-
- /**
- * If req has all the info - return the principal.
- * Otherwise set the challenge in response.
- *
- * @param requestedMethod auth method from web.xml. Spec
- * complain plugins must support it.
- * @throws IOException
- */
- public Principal authenticate(HttpServletRequest req,
- HttpServletResponse res,
- String requestedMethod) throws IOException;
-
-
- public boolean isUserInRole(HttpServletRequest req,
- Principal p,
- String role);
-}
+++ /dev/null
-/*
- * 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.IOException;
-
-import javax.servlet.ServletContext;
-import javax.servlet.http.HttpSession;
-
-/**
- * Session management plugin. No dependency on tomcat-lite, should
- * be possible to add this to tomcat-trunk or other containers.
- *
- * The container will:
- * - extract the session id from request ( via a filter or built-ins )
- * - call this interface when the user makes the related calls in the
- * servlet API.
- * - provide a context attribute 'context-listeners' with the
- * List<EventListener> from web.xml
- *
- * Implementation of this class must provide HttpSession object
- * and implement the spec.
- *
- */
-public interface UserSessionManager {
-
-
-
- HttpSession findSession(String requestedSessionId) throws IOException;
-
- HttpSession createSession(String requestedSessionId);
-
- boolean isValid(HttpSession session);
-
- void access(HttpSession session);
-
- void endAccess(HttpSession session);
-
-
- void setSessionTimeout(int to);
-
- void setContext(ServletContext ctx);
-
-
-}
+++ /dev/null
-/*
- * 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 <jsp-file> - 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
- * <servlet><class-name>.
- *
- * @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);
-}
--- /dev/null
+/*
+ */
+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;
+ }
+
+}
--- /dev/null
+/**
+ *
+ */
+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<String> fileName = new ArrayList<String>();
+ public long timestamp;
+
+ public boolean full;
+
+ public String displayName;
+
+ public HashMap<String, String> contextParam = new HashMap<String, String>();
+
+ public HashMap<String, String> mimeMapping = new HashMap<String, String>(); // extension -> mime-type
+
+ public ArrayList<String> listenerClass = new ArrayList<String>();
+
+ public ArrayList<String> welcomeFileList = new ArrayList<String>();
+
+ // code -> location
+ public HashMap<String, String> errorPageCode= new HashMap<String, String>();
+
+ // exception -> location
+ public HashMap<String, String> errorPageException= new HashMap<String, String>();
+
+ public HashMap<String, String> localeEncodingMapping= new HashMap<String, String>(); // locale -> encoding
+
+ // public HashMap tagLibs; // uri->location
+ // jsp-property-group
+
+ // securityConstraint
+ public ArrayList<SecurityConstraintData> securityConstraint = new ArrayList<SecurityConstraintData>();
+
+ // loginConfig
+ public String authMethod;
+ public String realmName;
+ public String formLoginPage;
+ public String formErrorPage;
+
+ public ArrayList<String> securityRole = new ArrayList<String>();
+
+ // envEntry
+ public ArrayList<EnvEntryData> envEntry = new ArrayList<EnvEntryData>();
+
+ // ejbRef
+ // ejbLocalRef
+ // serviceRef
+ // resourceRef
+ // resourceEnvRef
+ // message-destination
+ // message-destinationRef
+ public HashMap<String, FilterData> filters = new HashMap<String, FilterData>();
+ public HashMap<String, ServletData> servlets = new HashMap<String, ServletData>();
+
+ public int sessionTimeout;
+ public boolean distributable;
+
+ public HashMap<String, String> servletMapping = new HashMap<String, String>(); // url -> servlet
+ public ArrayList<FilterMappingData> filterMappings = new ArrayList<FilterMappingData>();
+ 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<String> dispatcher = new ArrayList<String>();
+ }
+
+ 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<String, String> initParams = new HashMap<String, String>();
+
+ 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<String, String> securityRoleRef = new HashMap<String, String>(); // roleName -> [roleLink]
+ public boolean multipartConfig = false;
+
+ public List<String> declaresRoles = new ArrayList<String>();
+
+ }
+
+ public static class WebResourceCollectionData implements Serializable {
+ public String webResourceName;
+ public ArrayList<String> urlPattern = new ArrayList<String>();
+ public ArrayList<String> httpMethod = new ArrayList<String>();
+ }
+
+ public static class SecurityConstraintData implements Serializable {
+ private static final long serialVersionUID = -4780214921810871769L;
+
+ public ArrayList<String> roleName = new ArrayList<String>(); // auth-constraint/role
+
+ public ArrayList<WebResourceCollectionData> webResourceCollection =
+ new ArrayList<WebResourceCollectionData>();
+ public String transportGuarantee;
+
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ */
+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<JarEntry> 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<String, Object> asmList2Map(List list) {
+ Map<String, Object> 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<String, AnnotationNode> annotationMap(List annL) {
+ Map<String, AnnotationNode> 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<String, AnnotationNode> 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<String, Object> 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<String, AnnotationNode> 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<String, Object> 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<String, Object> 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<String, Object> 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<String, AnnotationNode> annotations) {
+ AnnotationNode webFilterA = annotations.get("javax.servlet.annotation.WebServlet");
+ if (webFilterA != null) {
+ // TODO: validity checks (implements servlet, etc)
+
+ FilterData sd = new FilterData();
+ Map<String, Object> 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<String, Object> 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<String, Object> 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;
+ }
+
+
+}
--- /dev/null
+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<attrs.getLength(); i++ ) {
+// Node n=attrs.item(i);
+// String name=n.getNodeName();
+// String value=n.getNodeValue();
+//
+//// if( log.isTraceEnabled() )
+//// log.trace("Attribute " + parent.getNodeName() + " " +
+//// name + "=" + value);
+// try {
+// IntrospectionUtils.setProperty(o, name, value);
+// } catch( Exception ex ) {
+// ex.printStackTrace();
+// }
+// }
+// }
+
+ /** Read XML as DOM.
+ */
+ public static Document readXml(InputStream is)
+ throws SAXException, IOException, ParserConfigurationException
+ {
+ DocumentBuilderFactory dbf =
+ DocumentBuilderFactory.newInstance();
+
+ dbf.setValidating(false);
+ dbf.setIgnoringComments(false);
+ dbf.setIgnoringElementContentWhitespace(true);
+ //dbf.setCoalescing(true);
+ //dbf.setExpandEntityReferences(true);
+
+ DocumentBuilder db = null;
+ db = dbf.newDocumentBuilder();
+ db.setEntityResolver( new NullResolver() );
+
+ // db.setErrorHandler( new MyErrorHandler());
+
+ Document doc = db.parse(is);
+ return doc;
+ }
+
+}
--- /dev/null
+/*
+ */
+package org.apache.tomcat.servlets.config.deploy;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+
+import org.apache.tomcat.servlets.config.ConfigLoader;
+import org.apache.tomcat.servlets.config.ServletContextConfig;
+
+/**
+ * Independent of tomcat-lite - will read the current context config,
+ * parse classes/jars for annotations - and generate a .ser file
+ * containing all info.
+ *
+ * This can be used to display informations about the config ( in a
+ * container-independent servlet ), or by the container for faster
+ * load times.
+ *
+ * @author Costin Manolache
+ */
+public class WarDeploy extends ConfigLoader implements Runnable {
+
+ public ServletContextConfig loadConfig(String basePath) {
+ ServletContextConfig contextConfig = super.loadConfig(basePath);
+
+ boolean needsDeploy = contextConfig == null;
+
+ if (contextConfig != null) {
+ if (contextConfig.version != ServletContextConfig.CURRENT_VERSION) {
+ needsDeploy = true;
+ } else {
+ // Check web.xml and other dep file timestamp(s)
+ for (String fn : contextConfig.fileName) {
+ File f = new File(fn);
+ if (f.lastModified() > contextConfig.timestamp) {
+ needsDeploy = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (needsDeploy) {
+ setBase(basePath);
+ run();
+ contextConfig = super.loadConfig(basePath);
+ }
+
+ return contextConfig;
+ }
+
+ @Override
+ public void run() {
+ if (base == null) {
+ return; // nothing we can do
+ }
+
+ ServletContextConfig contextConfig = new ServletContextConfig();
+ contextConfig.timestamp = System.currentTimeMillis();
+
+ File webXmlF = new File(base + "/WEB-INF/web.xml");
+ boolean needsAnnotations = true;
+
+ if (webXmlF.exists()) {
+ WebXml webXml = new WebXml(contextConfig);
+ try {
+ webXml.readWebXml(base + "/WEB-INF/web.xml");
+ if (contextConfig.metadataComplete) {
+ needsAnnotations = false;
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ try {
+ if (needsAnnotations) {
+ AnnotationsProcessor ap = new AnnotationsProcessor(contextConfig);
+ ap.processWebapp(base);
+ }
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ }
+
+
+ // Save
+ try {
+ ObjectOutputStream ois =
+ new ObjectOutputStream(new FileOutputStream(base +
+ ServletContextConfig.SERIALIZED_PATH));
+ ois.writeObject(contextConfig);
+ ois.close();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ String base;
+
+
+ public static void main(String[] args) {
+ String base = args[0];
+ WarDeploy wd = new WarDeploy();
+ wd.setBase(base);
+ wd.run();
+ }
+
+ private void setBase(String base) {
+ this.base = base;
+ }
+
+}
--- /dev/null
+/*
+ */
+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.Map;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+import javax.servlet.ServletException;
+
+import org.apache.tomcat.servlets.config.ServletContextConfig;
+import org.apache.tomcat.servlets.config.ServletContextConfig.EnvEntryData;
+import org.apache.tomcat.servlets.config.ServletContextConfig.FilterData;
+import org.apache.tomcat.servlets.config.ServletContextConfig.FilterMappingData;
+import org.apache.tomcat.servlets.config.ServletContextConfig.SecurityConstraintData;
+import org.apache.tomcat.servlets.config.ServletContextConfig.ServletData;
+import org.apache.tomcat.servlets.config.ServletContextConfig.WebResourceCollectionData;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+/**
+ * General-purpose utility to process an web.xml file. Result
+ * is a tree of objects starting with WebAppData.
+ *
+ * TODO: allow writting of web.xml, allow modification ( preserving
+ * comments )
+ *
+ * @author costin
+ */
+public class WebXml {
+ ServletContextConfig d;
+
+ public WebXml(ServletContextConfig cfg) {
+ d = cfg;
+ }
+
+ public void processJar(String path) throws IOException {
+ JarFile jar = new JarFile(path);
+ Enumeration<JarEntry> 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);
+ }
+
+}
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,
// --------------------------------------------------------- Public Methods
-
- protected ObjectManager om;
protected Filesystem fs;
/**
*/
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);
&& (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()))
if (ranges.size() == 1) {
processSingleRange(response, content, resFile, contentType,
- ostream, writer, ranges);
+ ostream, writer, ranges, contentLength);
} else {
}
- 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 {
} 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();
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.
// --------------------------------------------------------- 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.
*
--- /dev/null
+/*
+ */
+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);
+ }
+
+
+}
--- /dev/null
+/*
+ */
+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);
+ }
+}
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;
--- /dev/null
+/*
+ * 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<attInfo.length; i++ ) {
+ if( attName.equals(attInfo[i].getName())) {
+ type=attInfo[i].getType();
+ return type;
+ }
+ }
+ return null;
+ }
+
+ public Object convertValue(String type, String value)
+ {
+ Object objValue=value;
+
+ if( type==null || "java.lang.String".equals( type )) {
+ // string is default
+ objValue=value;
+ } else if( "javax.management.ObjectName".equals( type ) ||
+ "ObjectName".equals( type )) {
+ try {
+ objValue=new ObjectName( value );
+ } catch (MalformedObjectNameException e) {
+ return null;
+ }
+ } else if( "java.lang.Integer".equals( type ) ||
+ "int".equals( type )) {
+ objValue=new Integer( value );
+ } else if( "java.lang.Long".equals( type ) ||
+ "long".equals( type )) {
+ objValue=new Long( value );
+ } else if( "java.lang.Boolean".equals( type ) ||
+ "boolean".equals( type )) {
+ objValue=new Boolean( value );
+ }
+ return objValue;
+ }
+
+
+ public void listBeans( PrintWriter writer, String qry )
+ {
+
+ Set<ObjectName> 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<ObjectName> 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;
+ }
+}
--- /dev/null
+/*
+ */
+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;
+ }
+
+}
--- /dev/null
+/*
+ * 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 java.util.Vector;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+
+
+/**
+ * Load a JSP generated by jasper.
+ *
+ * Requires a 'jspc' servlet.
+ *
+ * This class has no dependencies on Jasper, it uses 2 servlets to integrate.
+ */
+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, 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 (usePrecompiled) {
+ try {
+ 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
+ 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 ) {
+ t.printStackTrace();
+ }
+ 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;
+ }
+
+ 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( 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)) : "";
+ if (derivedPackageName.length() == 0) {
+ return basePackageName + "." + className;
+ }
+
+ return ver + "." + basePackageName + '.' + derivedPackageName + "." +
+ className;
+ }
+
+ // ------------- Copied from jasper ---------------------------
+
+ private static final String JSP_PACKAGE_NAME = "org.apache.jsp";
+
+ private static final String makeJavaIdentifier(String identifier) {
+ StringBuffer modifiedIdentifier =
+ new StringBuffer(identifier.length());
+ if (!Character.isJavaIdentifierStart(identifier.charAt(0))) {
+ modifiedIdentifier.append('_');
+ }
+ for (int i = 0; i < identifier.length(); i++) {
+ char ch = identifier.charAt(i);
+ if (Character.isJavaIdentifierPart(ch) && ch != '_') {
+ modifiedIdentifier.append(ch);
+ } else if (ch == '.') {
+ modifiedIdentifier.append('_');
+ } else {
+ modifiedIdentifier.append(mangleChar(ch));
+ }
+ }
+ if (isJavaKeyword(modifiedIdentifier.toString())) {
+ modifiedIdentifier.append('_');
+ }
+ return modifiedIdentifier.toString();
+ }
+
+ private static final String javaKeywords[] = {
+ "abstract", "assert", "boolean", "break", "byte", "case",
+ "catch", "char", "class", "const", "continue",
+ "default", "do", "double", "else", "enum", "extends",
+ "final", "finally", "float", "for", "goto",
+ "if", "implements", "import", "instanceof", "int",
+ "interface", "long", "native", "new", "package",
+ "private", "protected", "public", "return", "short",
+ "static", "strictfp", "super", "switch", "synchronized",
+ "this", "throws", "transient", "try", "void",
+ "volatile", "while" };
+
+ private static final String makeJavaPackage(String path) {
+ String classNameComponents[] = split(path,"/");
+ StringBuffer legalClassNames = new StringBuffer();
+ for (int i = 0; i < classNameComponents.length; i++) {
+ legalClassNames.append(makeJavaIdentifier(classNameComponents[i]));
+ if (i < classNameComponents.length - 1) {
+ legalClassNames.append('.');
+ }
+ }
+ return legalClassNames.toString();
+ }
+
+ private static final String [] split(String path, String pat) {
+ Vector comps = new Vector();
+ int pos = path.indexOf(pat);
+ int start = 0;
+ while( pos >= 0 ) {
+ if(pos > start ) {
+ String comp = path.substring(start,pos);
+ comps.add(comp);
+ }
+ start = pos + pat.length();
+ pos = path.indexOf(pat,start);
+ }
+ if( start < path.length()) {
+ comps.add(path.substring(start));
+ }
+ String [] result = new String[comps.size()];
+ for(int i=0; i < comps.size(); i++) {
+ result[i] = (String)comps.elementAt(i);
+ }
+ return result;
+ }
+
+
+ /**
+ * Test whether the argument is a Java keyword
+ */
+ private static boolean isJavaKeyword(String key) {
+ int i = 0;
+ int j = javaKeywords.length;
+ while (i < j) {
+ int k = (i+j)/2;
+ int result = javaKeywords[k].compareTo(key);
+ if (result == 0) {
+ return true;
+ }
+ if (result < 0) {
+ i = k+1;
+ } else {
+ j = k;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Mangle the specified character to create a legal Java class name.
+ */
+ private static final String mangleChar(char ch) {
+ char[] result = new char[5];
+ result[0] = '_';
+ result[1] = Character.forDigit((ch >> 12) & 0xf, 16);
+ result[2] = Character.forDigit((ch >> 8) & 0xf, 16);
+ result[3] = Character.forDigit((ch >> 4) & 0xf, 16);
+ result[4] = Character.forDigit(ch & 0xf, 16);
+ return new String(result);
+ }
+}
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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 <servlet><jsp-file> 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 <jsp-file> servlet, compile the servlet and init it.
- */
- public void init(ServletConfig config) throws ServletException {
- super.init(config);
- // Support <servlet><jsp-file>
- 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);
- }
-}
+++ /dev/null
-/*
- * 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.util.Vector;
-
-import javax.servlet.Servlet;
-import javax.servlet.ServletConfig;
-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.
- *
- * TODO: transform this to an interface, paired with UserTemplateCompiler.
- *
- * @author Costin Manolache
- */
-public class SimpleTemplateClassMapper implements UserTemplateClassMapper {
-
- /**
- * Load the proxied jsp, if any.
- * @param config
- * @throws ServletException
- */
- public Servlet loadProxy(String jspFile,
- ServletContext ctx,
- ServletConfig config) throws ServletException {
- String mangledClass = getClassName( jspFile );
-
- HttpServlet jsp = null;
- Class jspC = null;
-
- // Already created
- if( jspC == null ) {
- try {
- jspC=Class.forName( mangledClass );
- } catch( Throwable t ) {
- // Not found - first try
- }
- }
-
- if (jspC == null) {
- // Class not found - needs to be compiled
- return compileAndInitPage(ctx, jspFile, config);
- }
-
- try {
- jsp=(HttpServlet)jspC.newInstance();
- } catch( Throwable t ) {
- t.printStackTrace();
- }
- jsp.init(config);
- return jsp;
- }
-
- 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");
- }
-
- /** Convert an identifier to a class name, using jasper conventions
- *
- * @param jspUri a relative JSP file
- * @return class name that would be generated by jasper
- */
- public String getClassName( String jspUri ) {
- 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)) : "";
-
- if (derivedPackageName.length() == 0) {
- return basePackageName + "." + className;
- }
- return basePackageName + '.' + derivedPackageName + "." + className;
- }
-
- // ------------- Copied from jasper ---------------------------
-
- private static final String JSP_PACKAGE_NAME = "org.apache.jsp";
-
- private static final String makeJavaIdentifier(String identifier) {
- StringBuilder modifiedIdentifier =
- new StringBuilder(identifier.length());
- if (!Character.isJavaIdentifierStart(identifier.charAt(0))) {
- modifiedIdentifier.append('_');
- }
- for (int i = 0; i < identifier.length(); i++) {
- char ch = identifier.charAt(i);
- if (Character.isJavaIdentifierPart(ch) && ch != '_') {
- modifiedIdentifier.append(ch);
- } else if (ch == '.') {
- modifiedIdentifier.append('_');
- } else {
- modifiedIdentifier.append(mangleChar(ch));
- }
- }
- if (isJavaKeyword(modifiedIdentifier.toString())) {
- modifiedIdentifier.append('_');
- }
- return modifiedIdentifier.toString();
- }
-
- private static final String javaKeywords[] = {
- "abstract", "assert", "boolean", "break", "byte", "case",
- "catch", "char", "class", "const", "continue",
- "default", "do", "double", "else", "enum", "extends",
- "final", "finally", "float", "for", "goto",
- "if", "implements", "import", "instanceof", "int",
- "interface", "long", "native", "new", "package",
- "private", "protected", "public", "return", "short",
- "static", "strictfp", "super", "switch", "synchronized",
- "this", "throws", "transient", "try", "void",
- "volatile", "while" };
-
- private static final String makeJavaPackage(String path) {
- String classNameComponents[] = split(path,"/");
- StringBuilder legalClassNames = new StringBuilder();
- for (int i = 0; i < classNameComponents.length; i++) {
- legalClassNames.append(makeJavaIdentifier(classNameComponents[i]));
- if (i < classNameComponents.length - 1) {
- legalClassNames.append('.');
- }
- }
- return legalClassNames.toString();
- }
-
- private static final String [] split(String path, String pat) {
- Vector comps = new Vector();
- int pos = path.indexOf(pat);
- int start = 0;
- while( pos >= 0 ) {
- if(pos > start ) {
- String comp = path.substring(start,pos);
- comps.add(comp);
- }
- start = pos + pat.length();
- pos = path.indexOf(pat,start);
- }
- if( start < path.length()) {
- comps.add(path.substring(start));
- }
- String [] result = new String[comps.size()];
- for(int i=0; i < comps.size(); i++) {
- result[i] = (String)comps.elementAt(i);
- }
- return result;
- }
-
-
- /**
- * Test whether the argument is a Java keyword
- */
- private static boolean isJavaKeyword(String key) {
- int i = 0;
- int j = javaKeywords.length;
- while (i < j) {
- int k = (i+j)/2;
- int result = javaKeywords[k].compareTo(key);
- if (result == 0) {
- return true;
- }
- if (result < 0) {
- i = k+1;
- } else {
- j = k;
- }
- }
- return false;
- }
-
- /**
- * Mangle the specified character to create a legal Java class name.
- */
- private static final String mangleChar(char ch) {
- char[] result = new char[5];
- result[0] = '_';
- result[1] = Character.forDigit((ch >> 12) & 0xf, 16);
- result[2] = Character.forDigit((ch >> 8) & 0xf, 16);
- result[3] = Character.forDigit((ch >> 4) & 0xf, 16);
- result[4] = Character.forDigit(ch & 0xf, 16);
- return new String(result);
- }
-
-}
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;
-
/**
*
// for the '*.jsp' case - need to keep track of the jsps
HashMap<String, Servlet> jsps=new HashMap<String, Servlet>();
- UserTemplateClassMapper mapper;
+ BaseJspLoader mapper;
/**
* If called from a <jsp-file> 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");
}
}
--- /dev/null
+/*
+ */
+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);
+ }
+}
--- /dev/null
+/*
+ * 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
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.apache.tomcat.addons.UserAuthentication;
/**
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.apache.tomcat.addons.UserAuthentication;
/**
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.apache.tomcat.addons.UserAuthentication;
/**
--- /dev/null
+/*
+ */
+package org.apache.tomcat.servlets.sec;
+
+import java.io.IOException;
+import java.security.Principal;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Plugin for user auth.
+ *
+ * This interface should support all common forms of auth,
+ * including Basic, Digest, Form and various other auth
+ * standards - the plugin has full control over request and
+ * response.
+ *
+ * Container will verify the security constraints on URLs and
+ * call this for all URLs that have constraints. The plugin can
+ * either authenticate and return the principal, or change
+ * the response - redirect, add headers, send content.
+ *
+ * Alternative: a simple Filter can do the same, with some conventions
+ * to support it ( attributes ).
+ *
+ * @author Costin Manolache
+ */
+public interface UserAuthentication {
+
+ /**
+ * If req has all the info - return the principal.
+ * Otherwise set the challenge in response.
+ *
+ * @param requestedMethod auth method from web.xml. Spec
+ * complain plugins must support it.
+ * @throws IOException
+ */
+ public Principal authenticate(HttpServletRequest req,
+ HttpServletResponse res,
+ String requestedMethod) throws IOException;
+
+
+ public boolean isUserInRole(HttpServletRequest req,
+ Principal p,
+ String role);
+}
public void setSessionIdLength(int idLength) {
this.sessionIdLength = idLength;
}
-}
\ No newline at end of file
+}
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
--- /dev/null
+/*
+ */
+package org.apache.tomcat.servlets.session;
+
+import java.io.IOException;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpSession;
+
+/**
+ * Session management plugin. No dependency on tomcat-lite, should
+ * be possible to add this to tomcat-trunk or other containers.
+ *
+ * The container will:
+ * - extract the session id from request ( via a filter or built-ins )
+ * - call this interface when the user makes the related calls in the
+ * servlet API.
+ * - provide a context attribute 'context-listeners' with the
+ * List<EventListener> from web.xml
+ *
+ * Implementation of this class must provide HttpSession object
+ * and implement the spec.
+ *
+ */
+public interface UserSessionManager {
+
+
+
+ HttpSession findSession(String requestedSessionId) throws IOException;
+
+ HttpSession createSession(String requestedSessionId);
+
+ boolean isValid(HttpSession session);
+
+ void access(HttpSession session);
+
+ void endAccess(HttpSession session);
+
+
+ void setSessionTimeout(int to);
+
+ void setContext(ServletContext ctx);
+
+
+}
--- /dev/null
+/*
+ * 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<BASELENGTH; i++ ) {
+ base64Alphabet[i] = -1;
+ }
+ for ( int i = 'Z'; 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<numberTriplets; i++ ) {
+
+ dataIndex = i*3;
+ b1 = binaryData[dataIndex] & 0xFF;
+ b2 = binaryData[dataIndex + 1] & 0xFF;
+ b3 = binaryData[dataIndex + 2] & 0xFF;
+
+ l = (byte)(b2 & 0x0f);
+ k = (byte)(b1 & 0x03);
+
+ encodedIndex = i*4;
+ encodedData[encodedIndex] = lookUpBase64Alphabet[ b1 >>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<numberQuadruple; i++ ) {
+ dataIndex = i*4;
+ marker0 = base64Data[dataIndex +2];
+ marker1 = base64Data[dataIndex +3];
+
+ b1 = base64Alphabet[base64Data[dataIndex]];
+ b2 = base64Alphabet[base64Data[dataIndex +1]];
+
+ if ( marker0 != PAD && marker1 != PAD ) { //No PAD e.g 3cQl
+ b3 = base64Alphabet[ marker0 ];
+ b4 = base64Alphabet[ marker1 ];
+
+ decodedData[encodedIndex] = (byte)( b1 <<2 | b2>>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<chars.length; i++) {
+ int v = base64[ chars[i] & 0xFF ];
+
+ if ( v >= 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();
+ }
+
+
+}
+
--- /dev/null
+/*
+ * 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<Long, String> formatCache =
+ new ConcurrentHashMap<Long, String>(CACHE_SIZE);
+
+
+ /**
+ * Parser cache.
+ */
+ protected static final ConcurrentHashMap<String, Long> parseCache =
+ new ConcurrentHashMap<String, Long>(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);
+ }
+
+
+}
--- /dev/null
+/*
+ * 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<String,String> defaultMap =
+ new Hashtable<String,String>(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<String,String> map = new Hashtable<String,String>();
+
+ 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;
+ }
+ }
+
+}
*/
public static String encodeCookie(Cookie cookie) {
- StringBuilder buf = new StringBuilder( cookie.getName() );
+ StringBuffer buf = new StringBuffer( cookie.getName() );
buf.append("=");
buf.append(cookie.getValue());
--- /dev/null
+/*
+ * 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();
+ }
+}