/*
* Copyright (c) 2003-2008, KNOPFLERFISH project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* - Neither the name of the KNOPFLERFISH project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.knopflerfish.bundle.http;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Locale;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import java.util.TimeZone;
import javax.servlet.http.HttpServletResponse;
public class HttpUtil {
// private constants
private final static Dictionary statusCodes = new Hashtable();
// public constants
public final static String SERVLET_NAME_KEY = "org.knopflerfish.service.http.servlet.name";
// Key strings for sessions according to the servlet specification
public final static String SESSION_COOKIE_KEY = "JSESSIONID";
public final static String SESSION_PARAMETER_KEY = "jsessionid";
// Acceptable Time/Date formats according to the HTTP specification
public final static SimpleDateFormat[] DATE_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) };
static {
for (int i = 0; i < DATE_FORMATS.length; i++)
DATE_FORMATS[i].setTimeZone(TimeZone.getTimeZone("GMT"));
}
public final static Enumeration EMPTY_ENUMERATION = new Enumeration() {
public boolean hasMoreElements() {
return false;
}
public Object nextElement() {
throw new NoSuchElementException();
}
};
// private methods
private static void setupStatusCodes() {
statusCodes.put(new Integer(HttpServletResponse.SC_CONTINUE),
"Continue");
statusCodes.put(
new Integer(HttpServletResponse.SC_SWITCHING_PROTOCOLS),
"Switching Protocols");
statusCodes.put(new Integer(HttpServletResponse.SC_OK), "OK");
statusCodes.put(new Integer(HttpServletResponse.SC_CREATED), "Created");
statusCodes.put(new Integer(HttpServletResponse.SC_ACCEPTED),
"Accepted");
statusCodes.put(new Integer(
HttpServletResponse.SC_NON_AUTHORITATIVE_INFORMATION),
"Non-Authoritative Information");
statusCodes.put(new Integer(HttpServletResponse.SC_NO_CONTENT),
"No Content");
statusCodes.put(new Integer(HttpServletResponse.SC_RESET_CONTENT),
"Reset Content");
statusCodes.put(new Integer(HttpServletResponse.SC_PARTIAL_CONTENT),
"Partial Content");
statusCodes.put(new Integer(HttpServletResponse.SC_MULTIPLE_CHOICES),
"Multiple Choices");
statusCodes.put(new Integer(HttpServletResponse.SC_MOVED_PERMANENTLY),
"Moved Permanently");
statusCodes.put(new Integer(HttpServletResponse.SC_MOVED_TEMPORARILY),
"Moved Temporarily");
statusCodes.put(new Integer(HttpServletResponse.SC_SEE_OTHER),
"See Other");
statusCodes.put(new Integer(HttpServletResponse.SC_NOT_MODIFIED),
"Not Modified");
statusCodes.put(new Integer(HttpServletResponse.SC_USE_PROXY),
"Use Proxy");
statusCodes.put(new Integer(HttpServletResponse.SC_BAD_REQUEST),
"Bad Request");
statusCodes.put(new Integer(HttpServletResponse.SC_UNAUTHORIZED),
"Unauthorized");
statusCodes.put(new Integer(HttpServletResponse.SC_PAYMENT_REQUIRED),
"Payment Required");
statusCodes.put(new Integer(HttpServletResponse.SC_FORBIDDEN),
"Forbidden");
statusCodes.put(new Integer(HttpServletResponse.SC_NOT_FOUND),
"Not Found");
statusCodes.put(new Integer(HttpServletResponse.SC_METHOD_NOT_ALLOWED),
"Method Not Allowed");
statusCodes.put(new Integer(HttpServletResponse.SC_NOT_ACCEPTABLE),
"Not Acceptable");
statusCodes.put(new Integer(
HttpServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED),
"Proxy Authentication Required");
statusCodes.put(new Integer(HttpServletResponse.SC_REQUEST_TIMEOUT),
"Request Time-out");
statusCodes.put(new Integer(HttpServletResponse.SC_CONFLICT),
"Conflict");
statusCodes.put(new Integer(HttpServletResponse.SC_GONE), "Gone");
statusCodes.put(new Integer(HttpServletResponse.SC_LENGTH_REQUIRED),
"Length Required");
statusCodes.put(
new Integer(HttpServletResponse.SC_PRECONDITION_FAILED),
"Precondition Failed");
statusCodes.put(new Integer(
HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE),
"Request Entity Too Large");
statusCodes.put(
new Integer(HttpServletResponse.SC_REQUEST_URI_TOO_LONG),
"Request-URI Too Large");
statusCodes.put(new Integer(
HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE),
"Unsupported Media Type");
statusCodes.put(new Integer(
HttpServletResponse.SC_INTERNAL_SERVER_ERROR),
"Internal Server Error");
statusCodes.put(new Integer(HttpServletResponse.SC_NOT_IMPLEMENTED),
"Not Implemented");
statusCodes.put(new Integer(HttpServletResponse.SC_BAD_GATEWAY),
"Bad Gateway");
statusCodes.put(
new Integer(HttpServletResponse.SC_SERVICE_UNAVAILABLE),
"Service Unavailable");
statusCodes.put(new Integer(HttpServletResponse.SC_GATEWAY_TIMEOUT),
"Gateway Time-out");
statusCodes.put(new Integer(
HttpServletResponse.SC_HTTP_VERSION_NOT_SUPPORTED),
"HTTP Version not supported");
}
// public methods
public static String getStatusMessage(int statusCode) {
if (statusCodes.isEmpty())
setupStatusCodes();
String statusMessage = (String) statusCodes
.get(new Integer(statusCode));
if (statusMessage == null)
statusMessage = "Unknown Status Code";
return statusMessage;
}
public static String newString(byte[] ascii, int hibyte, int offset,
int count) {
char[] value = new char[count];
if (hibyte == 0) {
for (int i = count; i-- > 0;)
value[i] = (char) (ascii[i + offset] & 0xff);
} else {
hibyte <<= 8;
for (int i = count; i-- > 0;)
value[i] = (char) (hibyte | (ascii[i + offset] & 0xff));
}
return new String(value);
}
public static String encodeURLEncoding(String s) {
if (s == null)
return null;
StringBuffer sb = new StringBuffer();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == ' ')
sb.append('+');
else if (c > 127) {
sb.append('%');
if (c > 255)
throw new IllegalArgumentException("Illegal character: "
+ c);
sb.append(Integer.toHexString(c));
} else
sb.append(c);
}
return sb.toString();
}
public static String decodeURLEncoding(String s) {
if (s == null)
return null;
StringBuffer sb = new StringBuffer();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
switch (c) {
case '+':
sb.append(' ');
break;
case '%':
try {
sb.append((char) Integer.parseInt(
s.substring(i + 1, i + 3), 16));
i += 2;
} catch (NumberFormatException nfe) {
throw new IllegalArgumentException("Invalid URL encoding: "
+ s.substring(i, i + 3));
} catch (StringIndexOutOfBoundsException sioobe) {
String rest = s.substring(i);
sb.append(rest);
if (rest.length() == 2)
i++;
}
break;
default:
sb.append(c);
break;
}
}
return sb.toString();
}
public static void removeAll(Dictionary dictionary) {
Enumeration e = dictionary.keys();
while (e.hasMoreElements())
dictionary.remove(e.nextElement());
}
public static Enumeration enumeration(final Collection c) {
return new Enumeration() {
Iterator i = c.iterator();
public boolean hasMoreElements() {
return i.hasNext();
}
public Object nextElement() {
return i.next();
}
};
}
/**
* Extract the charset specification from the given content
* type string and save the content type without charset parameter
* to the given StringBuffer. The charset value is returned.
*
* @param contentType The content type string to parse.
* @param contentTypeBare The content type string without the
* charset parameter will be appended.
* @return the embedded character encoding or null.
*/
public static String parseContentType(String contentType,
StringBuffer contentTypeBare )
{
int initialSbLength = contentTypeBare.length();
String res = null;
// Only parse if there seems to be any params at all
if (-1 != contentType.indexOf(";")) {
StringTokenizer st = new StringTokenizer(contentType, ";");
int count = 0;
while (st.hasMoreTokens()) {
String param = st.nextToken().trim();
int ix = param.indexOf("=");
if (ix != -1 && count > 0) { // the first token is the mime
// type itself
String attrib = param.substring(0, ix).toLowerCase();
String token = param.substring(ix + 1);
if ("charset".equals(attrib)) {
res = token;
} else {
if (contentTypeBare.length()>initialSbLength) {
contentTypeBare.append(";");
}
contentTypeBare.append(param);
}
} else {
if (contentTypeBare.length()>initialSbLength) {
contentTypeBare.append(";");
}
contentTypeBare.append(param);
}
count++;
}
} else {
// No params present in the content type specification; retain it.
contentTypeBare.append(contentType);
}
return res;
}
/**
* Builds the content type by adding a charset
* specification to the bare content type string.
*
* @param contentTypeBare The content type specification without charset.
* @param characterEncoding The charset parameter value to add.
*
* @return the content type specification with embedded character
* encoding.
*/
public static String buildContentType(String contentTypeBare,
String characterEncoding)
{
StringBuffer sb = new StringBuffer(contentTypeBare.length()
+characterEncoding.length());
StringTokenizer st = new StringTokenizer(contentTypeBare, ";");
int count = 0;
while (st.hasMoreTokens()) {
String param = st.nextToken().trim();
if (sb.length()>0) sb.append(";");
sb.append(param);
if (0==count) {
sb.append(";charset=").append(characterEncoding);
}
count++;
}
return sb.toString();
}
} // HttpUtil