You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by co...@apache.org on 2006/08/16 08:50:46 UTC
svn commit: r431846 [5/6] - in /tomcat/sandbox/tomcat-lite: ./ bin/ java/
java/org/apache/coyote/adapters/ java/org/apache/coyote/http11/
java/org/apache/coyote/servlet/mapper/ java/org/apache/coyote/servlet/util/
java/org/apache/coyote/standalone/ jav...
Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/sec/DigestAuthServlet.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/sec/DigestAuthServlet.java?rev=431846&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/sec/DigestAuthServlet.java (added)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/sec/DigestAuthServlet.java Tue Aug 15 23:50:43 2006
@@ -0,0 +1,405 @@
+/*
+ * Copyright 1999,2004-2005 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.sec;
+
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+// TODO: the pass file should store H(A1) - for both simple and digest
+
+// TODO: stale=TRUE
+
+/**
+ * Implements Digest (and Basic) authentication protocols.
+ * You can force digest-only, or basic only.
+ *
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @author Costin Manolache
+ */
+public class DigestAuthServlet extends SimpleAuthServlet {
+
+ private static Log log = LogFactory.getLog(DigestAuthServlet.class);
+
+ // -------------------------------------------------------------- Constants
+
+ /**
+ * The MD5 helper object for this class.
+ */
+ protected static final MD5Encoder md5Encoder = new MD5Encoder();
+
+
+ /**
+ * Descriptive information about this implementation.
+ */
+ protected static final String info =
+ "org.apache.catalina.authenticator.DigestAuthenticator/1.0";
+
+ /**
+ * MD5 message digest provider.
+ */
+ MessageDigest md5Helper;
+ public static final String DIGEST_METHOD = "DIGEST";
+
+ /**
+ * Private key. - not so private unless you set it
+ */
+ protected String key = "Tomcat-Lite";
+
+
+ // ----------------------------------------------------------- Constructors
+
+ // If not set - a random one will be used.
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ public void init() throws ServletException {
+ //super.init();
+ try {
+ //
+ //if (key == null) key = Long.toString(new Random().nextLong());
+ if (md5Helper == null)
+ md5Helper = MessageDigest.getInstance("MD5");
+ users.put("test", "test");
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ throw new IllegalStateException();
+ }
+ }
+
+ // --------------------------------------------------------- Public Methods
+
+
+ public void service(HttpServletRequest request,
+ HttpServletResponse response)
+ throws IOException {
+ processRequest(request,response);
+ }
+
+ public void processRequest(HttpServletRequest request,
+ HttpServletResponse response)
+ throws IOException {
+
+ if (realm == null)
+ realm = request.getServerName() + ":" + request.getServerPort();
+
+ // Validate any credentials already included with this request
+ String authorization = request.getHeader("authorization");
+ if (authorization != null) {
+ Principal principal = processDigestHeader(request, authorization);
+ if (principal != null) {
+ request.setAttribute(AccessFilter.A_PRINCIPAL,
+ principal);
+
+ // TODO: return the result, cache auth
+ return;
+ }
+ }
+
+ String domain = request.getContextPath();
+ String authHeader = getAuthenticateHeader(domain, false);
+
+ response.setHeader("WWW-Authenticate", authHeader);
+ response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
+ }
+
+ public String authenticate(String authorization) {
+
+ return "";
+ }
+
+
+ /** Generate the auth header
+ */
+ protected String getAuthenticateHeader(String domain,
+ boolean stale) {
+
+ long currentTime = System.currentTimeMillis();
+
+ // Does't use remote addr - it may change due to proxy
+ // ( and we want to validate )
+ String opaque = Long.toString(currentTime);
+ String nOnce = opaque + ":" + key;
+
+ byte[] buffer = null;
+ synchronized (md5Helper) {
+ buffer = md5Helper.digest(nOnce.getBytes());
+ }
+ nOnce = md5Encoder.encode(buffer);
+
+ buffer = md5Helper.digest(nOnce.getBytes());
+
+ StringBuffer authSB = new StringBuffer();
+ authSB.append("Digest realm=\"").append(realm);
+ authSB.append("\", qop=\"auth\", nonce=\"").append(nOnce);
+ authSB.append("\", domain=\"").append(domain);
+ if (stale)
+ authSB.append("\", stale=\"true");
+ authSB.append("\", opaque=\"").append(opaque);
+ authSB.append("\"");
+
+ return authSB.toString();
+ }
+
+ // ------------------------------------------------------ Protected Methods
+
+
+ /**
+ * Parse the specified authorization credentials, and return the
+ * associated Principal that these credentials authenticate (if any)
+ * from the specified Realm. If there is no such Principal, return
+ * <code>null</code>.
+ *
+ * @param request HTTP servlet request
+ * @param authorization Authorization credentials from this request
+ * @param realm Realm used to authenticate Principals
+ */
+ protected Principal processDigestHeader(HttpServletRequest request,
+ String authorization) {
+
+ if (authorization == null || !authorization.startsWith("Digest "))
+ return (null);
+ authorization = authorization.substring(7).trim();
+
+ // Bugzilla 37132: http://issues.apache.org/bugzilla/show_bug.cgi?id=37132
+ String[] tokens = authorization.split(",(?=(?:[^\"]*\"[^\"]*\")+$)");
+
+ String userName = null;
+ String realmName = null;
+ String nOnce = null;
+ String nc = null;
+ String cnonce = null;
+ String qop = null;
+ String uri = null;
+ String response = null;
+ String method = request.getMethod();
+
+ for (int i = 0; i < tokens.length; i++) {
+ String currentToken = tokens[i];
+ if (currentToken.length() == 0)
+ continue;
+ int equalSign = currentToken.indexOf('=');
+ if (equalSign < 0)
+ return null;
+ String currentTokenName =
+ currentToken.substring(0, equalSign).trim();
+ String currentTokenValue =
+ currentToken.substring(equalSign + 1).trim();
+ if ("username".equals(currentTokenName))
+ userName = removeQuotes(currentTokenValue);
+ if ("realm".equals(currentTokenName))
+ realmName = removeQuotes(currentTokenValue, true);
+ if ("nonce".equals(currentTokenName))
+ nOnce = removeQuotes(currentTokenValue);
+ if ("nc".equals(currentTokenName))
+ nc = removeQuotes(currentTokenValue);
+ if ("cnonce".equals(currentTokenName))
+ cnonce = removeQuotes(currentTokenValue);
+ if ("qop".equals(currentTokenName))
+ qop = removeQuotes(currentTokenValue);
+ if ("uri".equals(currentTokenName))
+ uri = removeQuotes(currentTokenValue);
+ if ("response".equals(currentTokenName))
+ response = removeQuotes(currentTokenValue);
+ }
+
+ if ( (userName == null) || (realmName == null) || (nOnce == null)
+ || (uri == null) || (response == null) )
+ return null;
+
+ // Second MD5 digest used to calculate the digest :
+ // MD5(Method + ":" + uri)
+ String a2 = method + ":" + uri;
+ byte[] buffer = null;
+ synchronized (md5Helper) {
+ buffer = md5Helper.digest(a2.getBytes());
+ }
+ String md5a2 = md5Encoder.encode(buffer);
+
+ // TODO: verify nonce, expiration
+
+ return authenticate(userName, response, nOnce, nc, cnonce, qop,
+ realmName, md5a2);
+
+ }
+
+
+ public Principal authenticate(final String username, String clientDigest,
+ String nOnce, String nc, String cnonce,
+ String qop, String realm,
+ String md5a2) {
+
+ String md5a1 = getDigest(username, realm);
+ if (md5a1 == null) return null; // user not found
+
+ String serverDigestValue = md5a1 + ":" + nOnce + ":" + nc + ":"
+ + cnonce + ":" + qop + ":" + md5a2;
+
+ byte[] valueBytes = null;
+ if(getDigestEncoding() == null) {
+ valueBytes = serverDigestValue.getBytes();
+ } else {
+ try {
+ valueBytes = serverDigestValue.getBytes(getDigestEncoding());
+ } catch (UnsupportedEncodingException uee) {
+ log.error("Illegal digestEncoding: " + getDigestEncoding(), uee);
+ throw new IllegalArgumentException(uee.getMessage());
+ }
+ }
+
+ String serverDigest = null;
+ // Bugzilla 32137
+ synchronized(md5Helper) {
+ serverDigest = md5Encoder.encode(md5Helper.digest(valueBytes));
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("Digest : " + clientDigest + " Username:" + username
+ + " ClientSigest:" + clientDigest + " nOnce:" + nOnce
+ + " nc:" + nc + " cnonce:" + cnonce + " qop:" + qop
+ + " realm:" + realm + "md5a2:" + md5a2
+ + " Server digest:" + serverDigest);
+ }
+
+ if (serverDigest.equals(clientDigest)) {
+ return new Principal() {
+ public String getName() {
+ return username;
+ }
+ };
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Removes the quotes on a string. RFC2617 states quotes are optional for
+ * all parameters except realm.
+ */
+ protected static String removeQuotes(String quotedString,
+ boolean quotesRequired) {
+ //support both quoted and non-quoted
+ if (quotedString.length() > 0 && quotedString.charAt(0) != '"' &&
+ !quotesRequired) {
+ return quotedString;
+ } else if (quotedString.length() > 2) {
+ return quotedString.substring(1, quotedString.length() - 1);
+ } else {
+ return new String();
+ }
+ }
+
+ /**
+ * Removes the quotes on a string.
+ */
+ protected static String removeQuotes(String quotedString) {
+ return removeQuotes(quotedString, false);
+ }
+
+
+ public static class MD5Encoder {
+
+
+ // ----------------------------------------------------- Instance Variables
+
+
+ private static final char[] hexadecimal =
+ {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f'};
+
+
+ // --------------------------------------------------------- Public Methods
+
+
+ /**
+ * Encodes the 128 bit (16 bytes) MD5 into a 32 character String.
+ *
+ * @param binaryData Array containing the digest
+ * @return Encoded MD5, or null if encoding failed
+ */
+ public String encode( byte[] binaryData ) {
+
+ if (binaryData.length != 16)
+ return null;
+
+ char[] buffer = new char[32];
+
+ for (int i=0; i<16; i++) {
+ int low = (int) (binaryData[i] & 0x0f);
+ int high = (int) ((binaryData[i] & 0xf0) >> 4);
+ buffer[i*2] = hexadecimal[high];
+ buffer[i*2 + 1] = hexadecimal[low];
+ }
+
+ return new String(buffer);
+
+ }
+ }
+
+ private String getPassword(String user) {
+ return (String)users.get(user);
+ }
+
+ protected String getDigest(String username, String realmName) {
+ String secret = getPassword(username);
+ if (hasMessageDigest) {
+ return secret;
+ } else {
+ String digestValue = username + ":" + realmName + ":"
+ + secret;
+
+ byte[] valueBytes = null;
+ if(getDigestEncoding() == null) {
+ valueBytes = digestValue.getBytes();
+ } else {
+ try {
+ valueBytes = digestValue.getBytes(getDigestEncoding());
+ } catch (UnsupportedEncodingException uee) {
+ log.error("Illegal digestEncoding: " + getDigestEncoding(), uee);
+ throw new IllegalArgumentException(uee.getMessage());
+ }
+ }
+
+ byte[] digest = null;
+ // Bugzilla 32137
+ synchronized(md5Helper) {
+ digest = md5Helper.digest(valueBytes);
+ }
+ return md5Encoder.encode(digest);
+ }
+ }
+
+ protected String digestEncoding = null;
+
+ public String getDigestEncoding() {
+ return digestEncoding;
+ }
+}
Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/sec/JAASAuthServlet.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/sec/JAASAuthServlet.java?rev=431846&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/sec/JAASAuthServlet.java (added)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/sec/JAASAuthServlet.java Tue Aug 15 23:50:43 2006
@@ -0,0 +1,134 @@
+/*
+ * Copyright 1999-2001,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.sec;
+
+
+import java.io.IOException;
+import java.security.Principal;
+import java.util.Iterator;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.AccountExpiredException;
+import javax.security.auth.login.CredentialExpiredException;
+import javax.security.auth.login.FailedLoginException;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+
+/**
+ * Authentication using JAAS
+ *
+ * @author Costin Manolache
+ */
+public class JAASAuthServlet extends HttpServlet {
+ String appName = "Tomcat";
+
+ public Principal authenticate(HttpServletRequest req) {
+ LoginContext loginContext = null;
+
+ // TODO: ThreadLocal for callback ?
+ try {
+ JaasCallback jaasCallback = new JaasCallback(req);
+ loginContext = new LoginContext(appName, jaasCallback);
+
+ loginContext.login();
+
+ Subject subject = loginContext.getSubject();
+ if (subject == null) {
+ return (null);
+ }
+ final String userName = jaasCallback.getUsername();
+ Iterator principals = subject.getPrincipals().iterator();
+ Principal principal = null;
+ while (principals.hasNext()) {
+ Principal p = (Principal) principals.next();
+ if (p.getName().equals(userName)) {
+ principal = p;
+ }
+ }
+ if (principal == null) {
+ principal = new Principal() {
+ public String getName() {
+ return userName;
+ }
+ };
+ }
+ return (principal);
+ } catch (AccountExpiredException e) {
+ return (null);
+ } catch (CredentialExpiredException e) {
+ return (null);
+ } catch (FailedLoginException e) {
+ return (null);
+ } catch (LoginException e) {
+ return (null);
+ } catch (Throwable e) {
+ return (null);
+ }
+ }
+
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+
+ }
+
+
+ public void init() throws ServletException {
+ super.init();
+ }
+
+ public static class JaasCallback implements CallbackHandler {
+
+ private HttpServletRequest req;
+
+ public JaasCallback(HttpServletRequest req) {
+ this.req = req;
+ }
+
+ public String getUsername() {
+ return req.getParameter("user");
+ }
+
+ public void handle(Callback[] callbacks)
+ throws IOException, UnsupportedCallbackException {
+
+ for (int i = 0; i < callbacks.length; i++) {
+ if (callbacks[i] instanceof NameCallback) {
+ ((NameCallback) callbacks[i]).setName(getUsername());
+ } else if (callbacks[i] instanceof PasswordCallback) {
+ final char[] passwordcontents;
+ // TODO: any digest, nonce, etc
+ //passwordcontents = password.toCharArray();
+ //((PasswordCallback) callbacks[i]).setPassword(passwordcontents);
+ } else {
+ throw new UnsupportedCallbackException(callbacks[i]);
+ }
+ }
+
+ }
+ }
+}
Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/sec/SimpleAuthServlet.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/sec/SimpleAuthServlet.java?rev=431846&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/sec/SimpleAuthServlet.java (added)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/sec/SimpleAuthServlet.java Tue Aug 15 23:50:43 2006
@@ -0,0 +1,108 @@
+/*
+ * Copyright 1999-2001,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.sec;
+
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.HashMap;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+// TODO: right now only in-process auth is implemented, the protocol
+// and URLConnection calls must be defined and implemented
+
+/**
+ * Tomcat-lite uses a split model for authentication: the 'realm', i.e.
+ * user and password management module, is no longer an interface but a
+ * regular servlet, with a simple http API ( and an attribute-based substitute
+ * for faster response if it runs in the same VM ). The realm is also
+ * responsible for the entire authentication protocol - generating nonce,
+ * verify cookie or authorization headers. Other auth protocols could be
+ * implemented, and more data could be used in making the decision.
+ *
+ * See AccessFilter for the other side of the protocol and what informations
+ * it can pass.
+ *
+ * The realm can run on the same tomcat instance, or can be on a separate
+ * server, dedicated to auth. This will allow more flexibility and security.
+ *
+ * This is a simple example servlet - can be used as a base class, or replaced
+ * with something implementing the same protocol. The usernames, pass, group
+ * membership and other user options are either passed in init params or in a
+ * properties file.
+ *
+ * Protocol:
+ *
+ *
+ *
+ *
+ * @author Costin Manolache
+ */
+public class SimpleAuthServlet extends HttpServlet {
+ private static final String USER_PREFIX = "u.";
+ private static final String ROLE_PREFIX = "r.";
+
+ HashMap users = new HashMap();
+ HashMap roles = new HashMap();
+
+ boolean hasMessageDigest = false;
+ String realm = null;
+
+ public void addUser(String name, String pass) {
+ users.put(name, pass);
+ }
+
+ public void addRole(String user, String value) {
+ String[] userRoles = value.split(",");
+ roles.put(user, userRoles);
+ }
+
+ public void setFilename(String fileName) {
+
+ }
+
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+ // TODO: decode the params, dispatch
+ }
+
+ public void init() throws ServletException {
+ super.init();
+ Enumeration names = getServletConfig().getInitParameterNames();
+ while (names.hasMoreElements()) {
+ String name = (String)names.nextElement();
+ String value = getServletConfig().getInitParameter(name);
+ if (name.startsWith(USER_PREFIX)) {
+ addUser(name.substring(USER_PREFIX.length()), value);
+ }
+ if (name.startsWith(ROLE_PREFIX)) {
+ addRole(name.substring(ROLE_PREFIX.length()), value);
+ }
+ }
+ }
+
+ public void checkAuth(String method, String cookie) {
+
+ }
+
+
+}
Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/util/CopyUtils.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/util/CopyUtils.java?rev=431846&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/util/CopyUtils.java (added)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/util/CopyUtils.java Tue Aug 15 23:50:43 2006
@@ -0,0 +1,257 @@
+package org.apache.tomcat.servlets.util;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.Reader;
+
+import javax.servlet.ServletOutputStream;
+
+public class CopyUtils {
+ protected static int input = 2048;
+
+ /**
+ * Copy the contents of the specified input stream to the specified
+ * output stream, and ensure that both streams are closed before returning
+ * (even in the face of an exception).
+ *
+ * @param resourceInfo The resource info
+ * @param writer The writer to write to
+ *
+ * @exception IOException if an input/output error occurs
+ */
+ public static void copy(InputStream is,
+ PrintWriter writer,
+ String fileEncoding)
+ throws IOException {
+
+ IOException exception = null;
+
+ InputStream resourceInputStream = is;
+
+ Reader reader;
+ if (fileEncoding == null) {
+ reader = new InputStreamReader(resourceInputStream);
+ } else {
+ reader = new InputStreamReader(resourceInputStream,
+ fileEncoding);
+ }
+
+ // Copy the input stream to the output stream
+ exception = copyRange(reader, writer);
+
+ // Clean up the reader
+ try {
+ reader.close();
+ } catch (Throwable t) {
+ ;
+ }
+
+ // Rethrow any exception that has occurred
+ if (exception != null)
+ throw exception;
+
+ }
+
+ /**
+ * Copy the contents of the specified input stream to the specified
+ * output stream, and ensure that both streams are closed before returning
+ * (even in the face of an exception).
+ *
+ * @param resourceInfo The resource information
+ * @param ostream The output stream to write to
+ *
+ * @exception IOException if an input/output error occurs
+ */
+ public static void copy(InputStream is, OutputStream ostream)
+ throws IOException {
+
+ IOException exception = null;
+ InputStream resourceInputStream = null;
+
+ resourceInputStream = is;
+
+ InputStream istream = new BufferedInputStream
+ (resourceInputStream, input);
+
+ // Copy the input stream to the output stream
+ exception = CopyUtils.copyRange(istream, ostream);
+
+ // Clean up the input stream
+ try {
+ istream.close();
+ } catch (Throwable t) {
+ ;
+ }
+
+ // Rethrow any exception that has occurred
+ if (exception != null)
+ throw exception;
+ }
+
+ /**
+ * Copy the contents of the specified input stream to the specified
+ * output stream, and ensure that both streams are closed before returning
+ * (even in the face of an exception).
+ *
+ * @param istream The input stream to read from
+ * @param ostream The output stream to write to
+ * @return Exception which occurred during processing
+ */
+ public static IOException copyRange(InputStream istream,
+ OutputStream ostream) {
+
+ // Copy the input stream to the output stream
+ IOException exception = null;
+ byte buffer[] = new byte[input];
+ int len = buffer.length;
+ while (true) {
+ try {
+ len = istream.read(buffer);
+ if (len == -1)
+ break;
+ ostream.write(buffer, 0, len);
+ } catch (IOException e) {
+ exception = e;
+ len = -1;
+ break;
+ }
+ }
+ return exception;
+
+ }
+
+
+ /**
+ * Copy the contents of the specified input stream to the specified
+ * output stream, and ensure that both streams are closed before returning
+ * (even in the face of an exception).
+ *
+ * @param reader The reader to read from
+ * @param writer The writer to write to
+ * @return Exception which occurred during processing
+ */
+ public static IOException copyRange(Reader reader, PrintWriter writer) {
+
+ // Copy the input stream to the output stream
+ IOException exception = null;
+ char buffer[] = new char[input];
+ int len = buffer.length;
+ while (true) {
+ try {
+ len = reader.read(buffer);
+ if (len == -1)
+ break;
+ writer.write(buffer, 0, len);
+ } catch (IOException e) {
+ exception = e;
+ len = -1;
+ break;
+ }
+ }
+ return exception;
+
+ }
+
+
+ /**
+ * Copy the contents of the specified input stream to the specified
+ * output stream, and ensure that both streams are closed before returning
+ * (even in the face of an exception).
+ *
+ * @param istream The input stream to read from
+ * @param ostream The output stream to write to
+ * @param start Start of the range which will be copied
+ * @param end End of the range which will be copied
+ * @return Exception which occurred during processing
+ */
+ public static IOException copyRange(InputStream istream,
+ ServletOutputStream ostream,
+ long start, long end) {
+
+ try {
+ istream.skip(start);
+ } catch (IOException e) {
+ return e;
+ }
+
+ IOException exception = null;
+ long bytesToRead = end - start + 1;
+
+ byte buffer[] = new byte[input];
+ int len = buffer.length;
+ while ( (bytesToRead > 0) && (len >= buffer.length)) {
+ try {
+ len = istream.read(buffer);
+ if (bytesToRead >= len) {
+ ostream.write(buffer, 0, len);
+ bytesToRead -= len;
+ } else {
+ ostream.write(buffer, 0, (int) bytesToRead);
+ bytesToRead = 0;
+ }
+ } catch (IOException e) {
+ exception = e;
+ len = -1;
+ }
+ if (len < buffer.length)
+ break;
+ }
+
+ return exception;
+
+ }
+
+
+
+ /**
+ * Copy the contents of the specified input stream to the specified
+ * output stream, and ensure that both streams are closed before returning
+ * (even in the face of an exception).
+ *
+ * @param reader The reader to read from
+ * @param writer The writer to write to
+ * @param start Start of the range which will be copied
+ * @param end End of the range which will be copied
+ * @return Exception which occurred during processing
+ */
+ public static IOException copyRange(Reader reader, PrintWriter writer,
+ long start, long end) {
+
+ try {
+ reader.skip(start);
+ } catch (IOException e) {
+ return e;
+ }
+
+ IOException exception = null;
+ long bytesToRead = end - start + 1;
+
+ char buffer[] = new char[input];
+ int len = buffer.length;
+ while ( (bytesToRead > 0) && (len >= buffer.length)) {
+ try {
+ len = reader.read(buffer);
+ if (bytesToRead >= len) {
+ writer.write(buffer, 0, len);
+ bytesToRead -= len;
+ } else {
+ writer.write(buffer, 0, (int) bytesToRead);
+ bytesToRead = 0;
+ }
+ } catch (IOException e) {
+ exception = e;
+ len = -1;
+ }
+ if (len < buffer.length)
+ break;
+ }
+
+ return exception;
+
+ }
+
+}
Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/util/DOMWriter.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/util/DOMWriter.java?rev=431846&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/util/DOMWriter.java (added)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/util/DOMWriter.java Tue Aug 15 23:50:43 2006
@@ -0,0 +1,287 @@
+/*
+ * 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.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * A sample DOM writer. This sample program illustrates how to
+ * traverse a DOM tree in order to print a document that is parsed.
+ */
+public class DOMWriter {
+
+ /** Output qualified names */
+ private boolean qualifiedNames = true;
+
+ /** Print writer. */
+ protected PrintWriter out;
+
+ /** Canonical output. */
+ protected boolean canonical;
+
+
+ public DOMWriter(String encoding, boolean canonical)
+ throws UnsupportedEncodingException {
+ out = new PrintWriter(new OutputStreamWriter(System.out, encoding));
+ this.canonical = canonical;
+ } // <init>(String,boolean)
+
+ //
+ // Constructors
+ //
+
+ /** Default constructor. */
+ public DOMWriter(boolean canonical) throws UnsupportedEncodingException {
+ this( "UTF8", canonical);
+ }
+
+ public DOMWriter(Writer writer, boolean canonical) {
+ out = new PrintWriter(writer);
+ this.canonical = canonical;
+ }
+
+ public boolean getQualifiedNames() {
+ return this.qualifiedNames;
+ }
+
+ public void setQualifiedNames(boolean qualifiedNames) {
+ this.qualifiedNames = qualifiedNames;
+ }
+
+ /** Prints the specified node, recursively. */
+ public void print(Node node) {
+
+ // is there anything to do?
+ if ( node == null ) {
+ return;
+ }
+
+ int type = node.getNodeType();
+ switch ( type ) {
+ // print document
+ case Node.DOCUMENT_NODE: {
+ if ( !canonical ) {
+ String Encoding = "UTF-8";
+
+ out.println("<?xml version=\"1.0\" encoding=\""+
+ Encoding + "\"?>");
+ }
+ print(((Document)node).getDocumentElement());
+ out.flush();
+ break;
+ }
+
+ // print element with attributes
+ case Node.ELEMENT_NODE: {
+ out.print('<');
+ if (this.qualifiedNames) {
+ out.print(node.getNodeName());
+ } else {
+ out.print(node.getLocalName());
+ }
+ Attr attrs[] = sortAttributes(node.getAttributes());
+ for ( int i = 0; i < attrs.length; i++ ) {
+ Attr attr = attrs[i];
+ out.print(' ');
+ if (this.qualifiedNames) {
+ out.print(attr.getNodeName());
+ } else {
+ out.print(attr.getLocalName());
+ }
+
+ out.print("=\"");
+ out.print(normalize(attr.getNodeValue()));
+ out.print('"');
+ }
+ out.print('>');
+ NodeList children = node.getChildNodes();
+ if ( children != null ) {
+ int len = children.getLength();
+ for ( int i = 0; i < len; i++ ) {
+ print(children.item(i));
+ }
+ }
+ break;
+ }
+
+ // handle entity reference nodes
+ case Node.ENTITY_REFERENCE_NODE: {
+ if ( canonical ) {
+ NodeList children = node.getChildNodes();
+ if ( children != null ) {
+ int len = children.getLength();
+ for ( int i = 0; i < len; i++ ) {
+ print(children.item(i));
+ }
+ }
+ } else {
+ out.print('&');
+ if (this.qualifiedNames) {
+ out.print(node.getNodeName());
+ } else {
+ out.print(node.getLocalName());
+ }
+ out.print(';');
+ }
+ break;
+ }
+
+ // print cdata sections
+ case Node.CDATA_SECTION_NODE: {
+ if ( canonical ) {
+ out.print(normalize(node.getNodeValue()));
+ } else {
+ out.print("<![CDATA[");
+ out.print(node.getNodeValue());
+ out.print("]]>");
+ }
+ break;
+ }
+
+ // print text
+ case Node.TEXT_NODE: {
+ out.print(normalize(node.getNodeValue()));
+ break;
+ }
+
+ // print processing instruction
+ case Node.PROCESSING_INSTRUCTION_NODE: {
+ out.print("<?");
+ if (this.qualifiedNames) {
+ out.print(node.getNodeName());
+ } else {
+ out.print(node.getLocalName());
+ }
+
+ String data = node.getNodeValue();
+ if ( data != null && data.length() > 0 ) {
+ out.print(' ');
+ out.print(data);
+ }
+ out.print("?>");
+ break;
+ }
+ }
+
+ if ( type == Node.ELEMENT_NODE ) {
+ out.print("</");
+ if (this.qualifiedNames) {
+ out.print(node.getNodeName());
+ } else {
+ out.print(node.getLocalName());
+ }
+ out.print('>');
+ }
+
+ out.flush();
+
+ } // print(Node)
+
+ /** Returns a sorted list of attributes. */
+ protected Attr[] sortAttributes(NamedNodeMap attrs) {
+
+ int len = (attrs != null) ? attrs.getLength() : 0;
+ Attr array[] = new Attr[len];
+ for ( int i = 0; i < len; i++ ) {
+ array[i] = (Attr)attrs.item(i);
+ }
+ for ( int i = 0; i < len - 1; i++ ) {
+ String name = null;
+ if (this.qualifiedNames) {
+ name = array[i].getNodeName();
+ } else {
+ name = array[i].getLocalName();
+ }
+ int index = i;
+ for ( int j = i + 1; j < len; j++ ) {
+ String curName = null;
+ if (this.qualifiedNames) {
+ curName = array[j].getNodeName();
+ } else {
+ curName = array[j].getLocalName();
+ }
+ if ( curName.compareTo(name) < 0 ) {
+ name = curName;
+ index = j;
+ }
+ }
+ if ( index != i ) {
+ Attr temp = array[i];
+ array[i] = array[index];
+ array[index] = temp;
+ }
+ }
+
+ return (array);
+
+ } // sortAttributes(NamedNodeMap):Attr[]
+
+
+ /** Normalizes the given string. */
+ protected String normalize(String s) {
+ StringBuffer str = new StringBuffer();
+
+ int len = (s != null) ? s.length() : 0;
+ for ( int i = 0; i < len; i++ ) {
+ char ch = s.charAt(i);
+ switch ( ch ) {
+ case '<': {
+ str.append("<");
+ break;
+ }
+ case '>': {
+ str.append(">");
+ break;
+ }
+ case '&': {
+ str.append("&");
+ break;
+ }
+ case '"': {
+ str.append(""");
+ break;
+ }
+ case '\r':
+ case '\n': {
+ if ( canonical ) {
+ str.append("&#");
+ str.append(Integer.toString(ch));
+ str.append(';');
+ break;
+ }
+ // else, default append char
+ }
+ default: {
+ str.append(ch);
+ }
+ }
+ }
+
+ return (str.toString());
+
+ } // normalize(String):String
+
+}
Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/util/Enumerator.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/util/Enumerator.java?rev=431846&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/util/Enumerator.java (added)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/util/Enumerator.java Tue Aug 15 23:50:43 2006
@@ -0,0 +1,173 @@
+/*
+ * 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.util.Collection;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+
+/**
+ * Adapter class that wraps an <code>Enumeration</code> around a Java2
+ * collection classes object <code>Iterator</code> so that existing APIs
+ * returning Enumerations can easily run on top of the new collections.
+ * Constructors are provided to easliy create such wrappers.
+ *
+ * @author Craig R. McClanahan
+ */
+public final class Enumerator implements Enumeration {
+
+
+ // ----------------------------------------------------------- Constructors
+
+
+ /**
+ * Return an Enumeration over the values of the specified Collection.
+ *
+ * @param collection Collection whose values should be enumerated
+ */
+ public Enumerator(Collection collection) {
+
+ this(collection.iterator());
+
+ }
+
+
+ /**
+ * Return an Enumeration over the values of the specified Collection.
+ *
+ * @param collection Collection whose values should be enumerated
+ * @param clone true to clone iterator
+ */
+ public Enumerator(Collection collection, boolean clone) {
+
+ this(collection.iterator(), clone);
+
+ }
+
+
+ /**
+ * Return an Enumeration over the values returned by the
+ * specified Iterator.
+ *
+ * @param iterator Iterator to be wrapped
+ */
+ public Enumerator(Iterator iterator) {
+
+ super();
+ this.iterator = iterator;
+
+ }
+
+
+ /**
+ * Return an Enumeration over the values returned by the
+ * specified Iterator.
+ *
+ * @param iterator Iterator to be wrapped
+ * @param clone true to clone iterator
+ */
+ public Enumerator(Iterator iterator, boolean clone) {
+
+ super();
+ if (!clone) {
+ this.iterator = iterator;
+ } else {
+ List list = new ArrayList();
+ while (iterator.hasNext()) {
+ list.add(iterator.next());
+ }
+ this.iterator = list.iterator();
+ }
+
+ }
+
+
+ /**
+ * Return an Enumeration over the values of the specified Map.
+ *
+ * @param map Map whose values should be enumerated
+ */
+ public Enumerator(Map map) {
+
+ this(map.values().iterator());
+
+ }
+
+
+ /**
+ * Return an Enumeration over the values of the specified Map.
+ *
+ * @param map Map whose values should be enumerated
+ * @param clone true to clone iterator
+ */
+ public Enumerator(Map map, boolean clone) {
+
+ this(map.values().iterator(), clone);
+
+ }
+
+
+ // ----------------------------------------------------- Instance Variables
+
+
+ /**
+ * The <code>Iterator</code> over which the <code>Enumeration</code>
+ * represented by this class actually operates.
+ */
+ private Iterator iterator = null;
+
+
+ // --------------------------------------------------------- Public Methods
+
+
+ /**
+ * Tests if this enumeration contains more elements.
+ *
+ * @return <code>true</code> if and only if this enumeration object
+ * contains at least one more element to provide, <code>false</code>
+ * otherwise
+ */
+ public boolean hasMoreElements() {
+
+ return (iterator.hasNext());
+
+ }
+
+
+ /**
+ * Returns the next element of this enumeration if this enumeration
+ * has at least one more element to provide.
+ *
+ * @return the next element of this enumeration
+ *
+ * @exception NoSuchElementException if no more elements exist
+ */
+ public Object nextElement() throws NoSuchElementException {
+
+ return (iterator.next());
+
+ }
+
+
+}
Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/util/FileCopyUtils.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/util/FileCopyUtils.java?rev=431846&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/util/FileCopyUtils.java (added)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/util/FileCopyUtils.java Tue Aug 15 23:50:43 2006
@@ -0,0 +1,110 @@
+package org.apache.tomcat.servlets.util;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.Reader;
+
+import javax.servlet.ServletOutputStream;
+
+
+/** Like CopyUtils, but with File as source.
+ *
+ * This has the potential to be optimized with JNI
+ */
+public class FileCopyUtils {
+ protected static int input = 2048;
+
+ public static void copy(File f, OutputStream ostream)
+ throws IOException {
+ CopyUtils.copy(new FileInputStream(f), ostream);
+ }
+
+
+ public static void copy(File cacheEntry,
+ PrintWriter writer,
+ String fileEncoding)
+ throws IOException {
+ CopyUtils.copy(new FileInputStream(cacheEntry), writer, fileEncoding);
+ }
+
+ /**
+ * Copy the contents of the specified input stream to the specified
+ * output stream, and ensure that both streams are closed before returning
+ * (even in the face of an exception).
+ *
+ * @param resourceInfo The ResourceInfo object
+ * @param ostream The output stream to write to
+ * @param range Range the client wanted to retrieve
+ * @exception IOException if an input/output error occurs
+ */
+ public static void copy(File cacheEntry, ServletOutputStream ostream,
+ Range range)
+ throws IOException {
+
+ IOException exception = null;
+
+ InputStream resourceInputStream = new FileInputStream(cacheEntry);
+ InputStream istream =
+ new BufferedInputStream(resourceInputStream, input);
+ exception = CopyUtils.copyRange(istream, ostream, range.start, range.end);
+
+ // Clean up the input stream
+ try {
+ istream.close();
+ } catch (Throwable t) {
+ ;
+ }
+
+ // Rethrow any exception that has occurred
+ if (exception != null)
+ throw exception;
+
+ }
+
+ /**
+ * Copy the contents of the specified input stream to the specified
+ * output stream, and ensure that both streams are closed before returning
+ * (even in the face of an exception).
+ *
+ * @param resourceInfo The ResourceInfo object
+ * @param writer The writer to write to
+ * @param range Range the client wanted to retrieve
+ * @exception IOException if an input/output error occurs
+ */
+ public static void copy(File cacheEntry, PrintWriter writer,
+ Range range, String fileEncoding)
+ throws IOException {
+
+ IOException exception = null;
+
+ InputStream resourceInputStream = new FileInputStream(cacheEntry);
+
+ Reader reader;
+ if (fileEncoding == null) {
+ reader = new InputStreamReader(resourceInputStream);
+ } else {
+ reader = new InputStreamReader(resourceInputStream,
+ fileEncoding);
+ }
+
+ exception = CopyUtils.copyRange(reader, writer, range.start, range.end);
+
+ // Clean up the input stream
+ try {
+ reader.close();
+ } catch (Throwable t) {
+ ;
+ }
+
+ // Rethrow any exception that has occurred
+ if (exception != null)
+ throw exception;
+
+ }
+}
Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/util/MD5Encoder.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/util/MD5Encoder.java?rev=431846&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/util/MD5Encoder.java (added)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/util/MD5Encoder.java Tue Aug 15 23:50:43 2006
@@ -0,0 +1,71 @@
+/*
+ * 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;
+
+
+/**
+ * Encode an MD5 digest into a String.
+ * <p>
+ * The 128 bit MD5 hash is converted into a 32 character long String.
+ * Each character of the String is the hexadecimal representation of 4 bits
+ * of the digest.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $
+ */
+
+public final class MD5Encoder {
+
+
+ // ----------------------------------------------------- Instance Variables
+
+
+ private static final char[] hexadecimal =
+ {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f'};
+
+
+ // --------------------------------------------------------- Public Methods
+
+
+ /**
+ * Encodes the 128 bit (16 bytes) MD5 into a 32 character String.
+ *
+ * @param binaryData Array containing the digest
+ * @return Encoded MD5, or null if encoding failed
+ */
+ public String encode( byte[] binaryData ) {
+
+ if (binaryData.length != 16)
+ return null;
+
+ char[] buffer = new char[32];
+
+ for (int i=0; i<16; i++) {
+ int low = (int) (binaryData[i] & 0x0f);
+ int high = (int) ((binaryData[i] & 0xf0) >> 4);
+ buffer[i*2] = hexadecimal[high];
+ buffer[i*2 + 1] = hexadecimal[low];
+ }
+
+ return new String(buffer);
+
+ }
+
+
+}
+
Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/util/MIME2Java.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/util/MIME2Java.java?rev=431846&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/util/MIME2Java.java (added)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/util/MIME2Java.java Tue Aug 15 23:50:43 2006
@@ -0,0 +1,602 @@
+/*
+ * 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.util.*;
+
+/**
+ * MIME2Java is a convenience class which handles conversions between MIME charset names
+ * and Java encoding names.
+ * <p>The supported XML encodings are the intersection of XML-supported code sets and those
+ * supported in JDK 1.1.
+ * <p>MIME charset names are used on <var>xmlEncoding</var> parameters to methods such
+ * as <code>TXDocument#setEncoding</code> and <code>DTD#setEncoding</code>.
+ * <p>Java encoding names are used on <var>encoding</var> parameters to
+ * methods such as <code>TXDocument#printWithFormat</code> and <code>DTD#printExternal</code>.
+ * <P>
+ * <TABLE BORDER="0" WIDTH="100%">
+ * <TR>
+ * <TD WIDTH="33%">
+ * <P ALIGN="CENTER"><B>Common Name</B>
+ * </TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER"><B>Use this name in XML files</B>
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER"><B>Name Type</B>
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER"><B>Xerces converts to this Java Encoder Name</B>
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">8 bit Unicode</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">UTF-8
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">IANA
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">UTF8
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">ISO Latin 1</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">ISO-8859-1
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">MIME
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">ISO-8859-1
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">ISO Latin 2</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">ISO-8859-2
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">MIME
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">ISO-8859-2
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">ISO Latin 3</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">ISO-8859-3
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">MIME
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">ISO-8859-3
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">ISO Latin 4</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">ISO-8859-4
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">MIME
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">ISO-8859-4
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">ISO Latin Cyrillic</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">ISO-8859-5
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">MIME
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">ISO-8859-5
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">ISO Latin Arabic</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">ISO-8859-6
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">MIME
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">ISO-8859-6
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">ISO Latin Greek</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">ISO-8859-7
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">MIME
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">ISO-8859-7
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">ISO Latin Hebrew</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">ISO-8859-8
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">MIME
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">ISO-8859-8
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">ISO Latin 5</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">ISO-8859-9
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">MIME
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">ISO-8859-9
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">EBCDIC: US</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">ebcdic-cp-us
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">IANA
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">cp037
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">EBCDIC: Canada</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">ebcdic-cp-ca
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">IANA
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">cp037
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">EBCDIC: Netherlands</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">ebcdic-cp-nl
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">IANA
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">cp037
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">EBCDIC: Denmark</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">ebcdic-cp-dk
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">IANA
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">cp277
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">EBCDIC: Norway</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">ebcdic-cp-no
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">IANA
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">cp277
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">EBCDIC: Finland</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">ebcdic-cp-fi
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">IANA
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">cp278
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">EBCDIC: Sweden</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">ebcdic-cp-se
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">IANA
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">cp278
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">EBCDIC: Italy</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">ebcdic-cp-it
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">IANA
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">cp280
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">EBCDIC: Spain, Latin America</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">ebcdic-cp-es
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">IANA
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">cp284
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">EBCDIC: Great Britain</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">ebcdic-cp-gb
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">IANA
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">cp285
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">EBCDIC: France</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">ebcdic-cp-fr
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">IANA
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">cp297
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">EBCDIC: Arabic</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">ebcdic-cp-ar1
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">IANA
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">cp420
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">EBCDIC: Hebrew</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">ebcdic-cp-he
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">IANA
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">cp424
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">EBCDIC: Switzerland</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">ebcdic-cp-ch
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">IANA
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">cp500
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">EBCDIC: Roece</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">ebcdic-cp-roece
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">IANA
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">cp870
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">EBCDIC: Yogoslavia</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">ebcdic-cp-yu
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">IANA
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">cp870
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">EBCDIC: Iceland</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">ebcdic-cp-is
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">IANA
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">cp871
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">EBCDIC: Urdu</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">ebcdic-cp-ar2
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">IANA
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">cp918
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">Chinese for PRC, mixed 1/2 byte</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">gb2312
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">MIME
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">GB2312
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">Extended Unix Code, packed for Japanese</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">euc-jp
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">MIME
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">eucjis
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">Japanese: iso-2022-jp</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">iso-2020-jp
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">MIME
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">JIS
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">Japanese: Shift JIS</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">Shift_JIS
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">MIME
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">SJIS
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">Chinese: Big5</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">Big5
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">MIME
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">Big5
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">Extended Unix Code, packed for Korean</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">euc-kr
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">MIME
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">iso2022kr
+ * </TD>
+ * </TR>
+ * <TR>
+ * <TD WIDTH="33%">Cyrillic</TD>
+ * <TD WIDTH="15%">
+ * <P ALIGN="CENTER">koi8-r
+ * </TD>
+ * <TD WIDTH="12%">
+ * <P ALIGN="CENTER">MIME
+ * </TD>
+ * <TD WIDTH="31%">
+ * <P ALIGN="CENTER">koi8-r
+ * </TD>
+ * </TR>
+ * </TABLE>
+ *
+ * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $
+ * @author TAMURA Kent <kent@trl.ibm.co.jp>
+ */
+public class MIME2Java {
+
+ static private Hashtable s_enchash;
+ static private Hashtable s_revhash;
+
+ static {
+ s_enchash = new Hashtable();
+ // <preferred MIME name>, <Java encoding name>
+ s_enchash.put("UTF-8", "UTF8");
+ s_enchash.put("US-ASCII", "8859_1"); // ?
+ s_enchash.put("ISO-8859-1", "8859_1");
+ s_enchash.put("ISO-8859-2", "8859_2");
+ s_enchash.put("ISO-8859-3", "8859_3");
+ s_enchash.put("ISO-8859-4", "8859_4");
+ s_enchash.put("ISO-8859-5", "8859_5");
+ s_enchash.put("ISO-8859-6", "8859_6");
+ s_enchash.put("ISO-8859-7", "8859_7");
+ s_enchash.put("ISO-8859-8", "8859_8");
+ s_enchash.put("ISO-8859-9", "8859_9");
+ s_enchash.put("ISO-2022-JP", "JIS");
+ s_enchash.put("SHIFT_JIS", "SJIS");
+ s_enchash.put("EUC-JP", "EUCJIS");
+ s_enchash.put("GB2312", "GB2312");
+ s_enchash.put("BIG5", "Big5");
+ s_enchash.put("EUC-KR", "KSC5601");
+ s_enchash.put("ISO-2022-KR", "ISO2022KR");
+ s_enchash.put("KOI8-R", "KOI8_R");
+
+ s_enchash.put("EBCDIC-CP-US", "CP037");
+ s_enchash.put("EBCDIC-CP-CA", "CP037");
+ s_enchash.put("EBCDIC-CP-NL", "CP037");
+ s_enchash.put("EBCDIC-CP-DK", "CP277");
+ s_enchash.put("EBCDIC-CP-NO", "CP277");
+ s_enchash.put("EBCDIC-CP-FI", "CP278");
+ s_enchash.put("EBCDIC-CP-SE", "CP278");
+ s_enchash.put("EBCDIC-CP-IT", "CP280");
+ s_enchash.put("EBCDIC-CP-ES", "CP284");
+ s_enchash.put("EBCDIC-CP-GB", "CP285");
+ s_enchash.put("EBCDIC-CP-FR", "CP297");
+ s_enchash.put("EBCDIC-CP-AR1", "CP420");
+ s_enchash.put("EBCDIC-CP-HE", "CP424");
+ s_enchash.put("EBCDIC-CP-CH", "CP500");
+ s_enchash.put("EBCDIC-CP-ROECE", "CP870");
+ s_enchash.put("EBCDIC-CP-YU", "CP870");
+ s_enchash.put("EBCDIC-CP-IS", "CP871");
+ s_enchash.put("EBCDIC-CP-AR2", "CP918");
+
+ // j:CNS11643 -> EUC-TW?
+ // ISO-2022-CN? ISO-2022-CN-EXT?
+
+ s_revhash = new Hashtable();
+ // <Java encoding name>, <preferred MIME name>
+ s_revhash.put("UTF8", "UTF-8");
+ //s_revhash.put("8859_1", "US-ASCII"); // ?
+ s_revhash.put("8859_1", "ISO-8859-1");
+ s_revhash.put("8859_2", "ISO-8859-2");
+ s_revhash.put("8859_3", "ISO-8859-3");
+ s_revhash.put("8859_4", "ISO-8859-4");
+ s_revhash.put("8859_5", "ISO-8859-5");
+ s_revhash.put("8859_6", "ISO-8859-6");
+ s_revhash.put("8859_7", "ISO-8859-7");
+ s_revhash.put("8859_8", "ISO-8859-8");
+ s_revhash.put("8859_9", "ISO-8859-9");
+ s_revhash.put("JIS", "ISO-2022-JP");
+ s_revhash.put("SJIS", "Shift_JIS");
+ s_revhash.put("EUCJIS", "EUC-JP");
+ s_revhash.put("GB2312", "GB2312");
+ s_revhash.put("BIG5", "Big5");
+ s_revhash.put("KSC5601", "EUC-KR");
+ s_revhash.put("ISO2022KR", "ISO-2022-KR");
+ s_revhash.put("KOI8_R", "KOI8-R");
+
+ s_revhash.put("CP037", "EBCDIC-CP-US");
+ s_revhash.put("CP037", "EBCDIC-CP-CA");
+ s_revhash.put("CP037", "EBCDIC-CP-NL");
+ s_revhash.put("CP277", "EBCDIC-CP-DK");
+ s_revhash.put("CP277", "EBCDIC-CP-NO");
+ s_revhash.put("CP278", "EBCDIC-CP-FI");
+ s_revhash.put("CP278", "EBCDIC-CP-SE");
+ s_revhash.put("CP280", "EBCDIC-CP-IT");
+ s_revhash.put("CP284", "EBCDIC-CP-ES");
+ s_revhash.put("CP285", "EBCDIC-CP-GB");
+ s_revhash.put("CP297", "EBCDIC-CP-FR");
+ s_revhash.put("CP420", "EBCDIC-CP-AR1");
+ s_revhash.put("CP424", "EBCDIC-CP-HE");
+ s_revhash.put("CP500", "EBCDIC-CP-CH");
+ s_revhash.put("CP870", "EBCDIC-CP-ROECE");
+ s_revhash.put("CP870", "EBCDIC-CP-YU");
+ s_revhash.put("CP871", "EBCDIC-CP-IS");
+ s_revhash.put("CP918", "EBCDIC-CP-AR2");
+ }
+
+ private MIME2Java() {
+ }
+
+ /**
+ * Convert a MIME charset name, also known as an XML encoding name, to a Java encoding name.
+ * @param mimeCharsetName Case insensitive MIME charset name: <code>UTF-8, US-ASCII, ISO-8859-1,
+ * ISO-8859-2, ISO-8859-3, ISO-8859-4, ISO-8859-5, ISO-8859-6,
+ * ISO-8859-7, ISO-8859-8, ISO-8859-9, ISO-2022-JP, Shift_JIS,
+ * EUC-JP, GB2312, Big5, EUC-KR, ISO-2022-KR, KOI8-R,
+ * EBCDIC-CP-US, EBCDIC-CP-CA, EBCDIC-CP-NL, EBCDIC-CP-DK,
+ * EBCDIC-CP-NO, EBCDIC-CP-FI, EBCDIC-CP-SE, EBCDIC-CP-IT,
+ * EBCDIC-CP-ES, EBCDIC-CP-GB, EBCDIC-CP-FR, EBCDIC-CP-AR1,
+ * EBCDIC-CP-HE, EBCDIC-CP-CH, EBCDIC-CP-ROECE, EBCDIC-CP-YU,
+ * EBCDIC-CP-IS and EBCDIC-CP-AR2</code>.
+ * @return Java encoding name, or <var>null</var> if <var>mimeCharsetName</var>
+ * is unknown.
+ * @see #reverse
+ */
+ public static String convert(String mimeCharsetName) {
+ return (String)s_enchash.get(mimeCharsetName.toUpperCase());
+ }
+
+ /**
+ * Convert a Java encoding name to MIME charset name.
+ * Available values of <i>encoding</i> are "UTF8", "8859_1", "8859_2", "8859_3", "8859_4",
+ * "8859_5", "8859_6", "8859_7", "8859_8", "8859_9", "JIS", "SJIS", "EUCJIS",
+ * "GB2312", "BIG5", "KSC5601", "ISO2022KR", "KOI8_R", "CP037", "CP277", "CP278",
+ * "CP280", "CP284", "CP285", "CP297", "CP420", "CP424", "CP500", "CP870", "CP871" and "CP918".
+ * @param encoding Case insensitive Java encoding name: <code>UTF8, 8859_1, 8859_2, 8859_3,
+ * 8859_4, 8859_5, 8859_6, 8859_7, 8859_8, 8859_9, JIS, SJIS, EUCJIS,
+ * GB2312, BIG5, KSC5601, ISO2022KR, KOI8_R, CP037, CP277, CP278,
+ * CP280, CP284, CP285, CP297, CP420, CP424, CP500, CP870, CP871
+ * and CP918</code>.
+ * @return MIME charset name, or <var>null</var> if <var>encoding</var> is unknown.
+ * @see #convert
+ */
+ public static String reverse(String encoding) {
+ return (String)s_revhash.get(encoding.toUpperCase());
+ }
+}
Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/util/Range.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/util/Range.java?rev=431846&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/util/Range.java (added)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/util/Range.java Tue Aug 15 23:50:43 2006
@@ -0,0 +1,146 @@
+/**
+ *
+ */
+package org.apache.tomcat.servlets.util;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+
+/**
+ * Utils to process HTTP/1.1 ranges. Used by default servlet, could
+ * be used by any servlet that needs to deal with ranges.
+ *
+ * It is very good to support ranges if you have large content. In most
+ * cases supporting one range is enough - getting multiple ranges doesn't
+ * seem very common, and it's complex (multipart response).
+ *
+ * @author Costin Manolache
+ * @author Remy Maucherat
+ * @author - see DefaultServlet in Catalin for other contributors
+ */
+public class Range {
+
+ public long start;
+ public long end;
+ public long length;
+
+ /**
+ * Validate range.
+ */
+ public boolean validate() {
+ if (end >= length)
+ end = length - 1;
+ return ( (start >= 0) && (end >= 0) && (start <= end)
+ && (length > 0) );
+ }
+
+ public void recycle() {
+ start = 0;
+ end = 0;
+ length = 0;
+ }
+
+ /** Parse ranges.
+ *
+ * @return null if the range is invalid or can't be parsed
+ */
+ public static ArrayList parseRanges(long fileLength,
+ String rangeHeader) throws IOException {
+ ArrayList result = new ArrayList();
+ StringTokenizer commaTokenizer = new StringTokenizer(rangeHeader, ",");
+
+ // Parsing the range list
+ while (commaTokenizer.hasMoreTokens()) {
+ String rangeDefinition = commaTokenizer.nextToken().trim();
+
+ Range currentRange = new Range();
+ currentRange.length = fileLength;
+
+ int dashPos = rangeDefinition.indexOf('-');
+
+ if (dashPos == -1) {
+ return null;
+ }
+
+ if (dashPos == 0) {
+ try {
+ long offset = Long.parseLong(rangeDefinition);
+ currentRange.start = fileLength + offset;
+ currentRange.end = fileLength - 1;
+ } catch (NumberFormatException e) {
+ return null;
+ }
+ } else {
+
+ try {
+ currentRange.start = Long.parseLong
+ (rangeDefinition.substring(0, dashPos));
+ if (dashPos < rangeDefinition.length() - 1)
+ currentRange.end = Long.parseLong
+ (rangeDefinition.substring
+ (dashPos + 1, rangeDefinition.length()));
+ else
+ currentRange.end = fileLength - 1;
+ } catch (NumberFormatException e) {
+ return null;
+ }
+
+ }
+ if (!currentRange.validate()) {
+ return null;
+ }
+ result.add(currentRange);
+ }
+ return result;
+ }
+
+
+ /**
+ * Parse the Content-Range header. Used with PUT or in response.
+ *
+ * @return Range
+ */
+ public static Range parseContentRange(String rangeHeader)
+ throws IOException {
+ if (rangeHeader == null)
+ return null;
+
+ // bytes is the only range unit supported
+ if (!rangeHeader.startsWith("bytes")) {
+ return null;
+ }
+
+ rangeHeader = rangeHeader.substring(6).trim();
+
+ int dashPos = rangeHeader.indexOf('-');
+ int slashPos = rangeHeader.indexOf('/');
+
+ if (dashPos == -1) {
+ return null;
+ }
+
+ if (slashPos == -1) {
+ return null;
+ }
+
+ Range range = new Range();
+
+ try {
+ range.start = Long.parseLong(rangeHeader.substring(0, dashPos));
+ range.end =
+ Long.parseLong(rangeHeader.substring(dashPos + 1, slashPos));
+ range.length = Long.parseLong
+ (rangeHeader.substring(slashPos + 1, rangeHeader.length()));
+ } catch (NumberFormatException e) {
+ return null;
+ }
+
+ if (!range.validate()) {
+ return null;
+ }
+
+ return range;
+ }
+
+}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org