001: package pygmy.core;
002:
003: import java.util.*;
004: import java.text.SimpleDateFormat;
005: import java.text.ParseException;
006: import java.io.File;
007: import java.io.UnsupportedEncodingException;
008: import java.io.IOException;
009: import java.io.FilePermission;
010: import java.net.*;
011: import java.security.PermissionCollection;
012:
013: /**
014: * Utility class for HTTP error codes, and other command HTTP tasks.
015: */
016: public class Http {
017:
018: private static HashMap codesMap = new HashMap();
019:
020: private static HashMap htmlCharacterEncodings = new HashMap();
021:
022: private static SimpleDateFormat dateFormat;
023:
024: public static final String CRLF = "\r\n";
025:
026: static {
027: dateFormat = new SimpleDateFormat(
028: "EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
029: dateFormat.setTimeZone(new SimpleTimeZone(0, "GMT"));
030: dateFormat.setLenient(true);
031: }
032:
033: static {
034: htmlCharacterEncodings.put("&", "amp");
035: htmlCharacterEncodings.put("<", "lt");
036: htmlCharacterEncodings.put(">", "gt");
037: htmlCharacterEncodings.put("\"", "quot");
038: htmlCharacterEncodings.put("'", "apos");
039: }
040:
041: static {
042: codesMap.put(new Integer(100), "Continue");
043: codesMap.put(new Integer(101), "Switching Protocols");
044: codesMap.put(new Integer(200), "OK");
045: codesMap.put(new Integer(201), "Created");
046: codesMap.put(new Integer(202), "Accepted");
047: codesMap.put(new Integer(203), "Non-Authoritative Information");
048: codesMap.put(new Integer(204), "No Content");
049: codesMap.put(new Integer(205), "Reset Content");
050: codesMap.put(new Integer(206), "Partial Content");
051: codesMap.put(new Integer(300), "Multiple Choices");
052: codesMap.put(new Integer(301), "Moved Permanently");
053: codesMap.put(new Integer(302), "Moved Temporarily");
054: codesMap.put(new Integer(303), "See Other");
055: codesMap.put(new Integer(304), "Not Modified");
056: codesMap.put(new Integer(305), "Use Proxy");
057: codesMap.put(new Integer(400), "Bad Request");
058: codesMap.put(new Integer(401), "Unauthorized");
059: codesMap.put(new Integer(402), "Payment Required");
060: codesMap.put(new Integer(403), "Forbidden");
061: codesMap.put(new Integer(404), "Not Found");
062: codesMap.put(new Integer(405), "Method Not Allowed");
063: codesMap.put(new Integer(406), "Not Acceptable");
064: codesMap.put(new Integer(407), "Proxy Authentication Required");
065: codesMap.put(new Integer(408), "Request Time-out");
066: codesMap.put(new Integer(409), "Conflict");
067: codesMap.put(new Integer(410), "Gone");
068: codesMap.put(new Integer(411), "Length Required");
069: codesMap.put(new Integer(412), "Precondition Failed");
070: codesMap.put(new Integer(413), "Request Entity Too Large");
071: codesMap.put(new Integer(414), "Request-URI Too Large");
072: codesMap.put(new Integer(415), "Unsupported Media Type");
073: codesMap.put(new Integer(500), "Server Error");
074: codesMap.put(new Integer(501), "Not Implemented");
075: codesMap.put(new Integer(502), "Bad Gateway");
076: codesMap.put(new Integer(503), "Service Unavailable");
077: codesMap.put(new Integer(504), "Gateway Time-out");
078: codesMap.put(new Integer(505), "HTTP Version not supported");
079: }
080:
081: /**
082: * Given a HTTP response code, this method will return the english phrase.
083: *
084: * @param code the HTTP response code to look up.
085: * @return A string describing what the HTTP response code is.
086: */
087: public static String getStatusPhrase(int code) {
088: String phrase = (String) codesMap.get(new Integer(code));
089: if (phrase == null) {
090: return "Error";
091: }
092:
093: return phrase;
094: }
095:
096: /**
097: * This encodes the message into Html. It encodes characters '&', ''', '<', '>', and '"' into &, ',
098: * <, >, and ".
099: *
100: * @param message the message to encode.
101: * @return the encoded message.
102: */
103: public static String encodeHtml(String message) {
104: StringBuffer result = new StringBuffer();
105:
106: for (int i = 0; i < message.length(); i++) {
107: String tmp = Character.toString(message.charAt(i));
108: if (htmlCharacterEncodings.containsKey(tmp)) {
109: result.append("&");
110: result.append(htmlCharacterEncodings.get(tmp));
111: result.append(";");
112: } else {
113: result.append(tmp);
114: }
115: }
116: return result.toString();
117: }
118:
119: /**
120: * This creates the current time as a string conforming to a HTTP date following the format
121: * <i>EEE, dd MMM yyyy HH:mm:ss z</i>.
122: * @return The a HTTP formated string of the current time.
123: */
124: public static String getCurrentTime() {
125: return formatTime(System.currentTimeMillis());
126: }
127:
128: /**
129: * This formats the given time as a HTTP formatted string. The format is <i>EEE, dd MMM yyyy HH:mm:ss z</i>.
130: * @param time the time to format into a string.
131: * @return the formatted date.
132: */
133: public static String formatTime(long time) {
134: return dateFormat.format(new Date(time)).substring(0, 29);
135: }
136:
137: /**
138: * This parses the given time as a HTTP formatted string.
139: * @param date The date represented as the format String <i>EEE, dd MMM yyyy HH:mm:ss z</i>.
140: * @return the time in milliseconds.
141: * @throws ParseException throws this exeception when it cannot parse the date.
142: */
143: public static long parseTime(String date) throws ParseException {
144: return dateFormat.parse(date).getTime();
145: }
146:
147: /**
148: * Takes two paths a joins them together properly adding the '/' charater between them.
149: *
150: * @param path the first part of the path.
151: * @param relativePath the second part to join to the first path.
152: * @return the combined path of path and relativePath.
153: */
154: public static String join(String path, String relativePath) {
155: boolean pathEnds = path.endsWith("/");
156: boolean relativeStarts = relativePath.startsWith("/");
157: if ((pathEnds && !relativeStarts)
158: || (!relativeStarts && pathEnds)) {
159: return path + relativePath;
160: } else if (pathEnds && relativeStarts) {
161: return path + relativePath.substring(1);
162: } else {
163: return path + "/" + relativePath;
164: }
165: }
166:
167: /**
168: * This translates a url into a path on the filesystem. This decodes the url using the URLDecoder class, and
169: * creates an absolute path beginning with root.
170: *
171: * @param root this is an absolute path to prepend onto the url.
172: * @param url the url to resolve into the filesystem.
173: * @return the a File object representing this URL.
174: * @throws UnsupportedEncodingException
175: */
176: public static File translatePath(String root, String url)
177: throws UnsupportedEncodingException {
178: String name = URLDecoder.decode(url, "UTF-8");
179: name = name.replace('/', File.separatorChar);
180: File file = new File(root, name);
181: return file;
182: }
183:
184: public static boolean isSecure(String root, File file)
185: throws IOException {
186: PermissionCollection rootDirectory;
187: if (root.endsWith(File.separator)) {
188: FilePermission fp = new FilePermission(root + "-", "read");
189: rootDirectory = fp.newPermissionCollection();
190: rootDirectory.add(fp);
191: rootDirectory.add(new FilePermission(root.substring(0, root
192: .length() - 1), "read"));
193: } else {
194: FilePermission fp = new FilePermission(root, "read");
195: rootDirectory = fp.newPermissionCollection();
196: rootDirectory.add(fp);
197: rootDirectory.add(new FilePermission(root + File.separator
198: + "-", "read"));
199: }
200: return (rootDirectory.implies(new FilePermission(file
201: .getCanonicalPath(), "read")));
202: }
203:
204: /**
205: * This method tries to find a suitable InetAddress that is routable. It calls {@link java.net.InetAddress#getLocalHost}
206: * to find the local host. If that address it a site local address (192.168.*.*, 10.*.*.*, or 172.16.*.*) or the
207: * loopback address (127.0.0.1), it enumerates all the NetworkInterfaces, and tries to find an address that is
208: * not site local or loopback address. If it cannot it simply returns whatever {@link InetAddress#getLocalHost}.
209: * @return the address of a non site local or non loopback address, unless there is only loopback or site local addresses.
210: * @throws UnknownHostException
211: * @throws SocketException
212: */
213: public static InetAddress findRoutableHostAddress()
214: throws UnknownHostException, SocketException {
215: InetAddress localAddress = InetAddress.getLocalHost();
216: if (localAddress.isSiteLocalAddress()
217: || localAddress.isLoopbackAddress()) {
218: for (Enumeration networkEnum = NetworkInterface
219: .getNetworkInterfaces(); networkEnum
220: .hasMoreElements();) {
221: NetworkInterface netInterface = (NetworkInterface) networkEnum
222: .nextElement();
223: for (Enumeration inetAddressEnum = netInterface
224: .getInetAddresses(); inetAddressEnum
225: .hasMoreElements();) {
226: InetAddress address = (InetAddress) inetAddressEnum
227: .nextElement();
228: if (!address.isSiteLocalAddress()
229: && !address.isLoopbackAddress()) {
230: return address;
231: }
232: }
233: }
234: }
235: return localAddress;
236: }
237:
238: public static List findAllHostAddresses(boolean includeLoopback)
239: throws SocketException {
240: List addresses = new ArrayList();
241: for (Enumeration networkEnum = NetworkInterface
242: .getNetworkInterfaces(); networkEnum.hasMoreElements();) {
243: NetworkInterface netInterface = (NetworkInterface) networkEnum
244: .nextElement();
245: for (Enumeration inetAddressEnum = netInterface
246: .getInetAddresses(); inetAddressEnum
247: .hasMoreElements();) {
248: InetAddress address = (InetAddress) inetAddressEnum
249: .nextElement();
250: if (includeLoopback || !address.isLoopbackAddress()) {
251: addresses.add(address);
252: }
253: }
254: }
255: return addresses;
256: }
257:
258: }
|