package com.bradmcevoy.http; import com.bradmcevoy.common.Path; import java.net.URI; import java.net.URISyntaxException; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.Charset; import java.util.Calendar; import java.util.Date; import java.util.Iterator; import java.util.List; public class Utils { private final static char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; public static Resource findChild( Resource parent, Path path ) { return _findChild( parent, path.getParts(), 0 ); } /** * does percentage decoding on a path portion of a url * * E.g. /foo > /foo * /with%20space -> /with space * * @param href */ public static String decodePath( String href ) { // For IPv6 href = href.replace( "[", "%5B" ).replace( "]", "%5D" ); // Seems that some client apps send spaces.. maybe.. href = href.replace( " ", "%20"); try { if( href.startsWith( "/" ) ) { URI uri = new URI( "http://anything.com" + href ); return uri.getPath(); } else { URI uri = new URI( "http://anything.com/" + href ); String s = uri.getPath(); return s.substring( 1 ); } } catch( URISyntaxException ex ) { throw new RuntimeException( ex ); } } private static Resource _findChild( Resource parent, String[] arr, int i ) { if( parent instanceof CollectionResource ) { CollectionResource col = (CollectionResource) parent; String childName = arr[i]; Resource child = col.child( childName ); if( child == null ) { return null; } else { if( i < arr.length - 1 ) { return _findChild( child, arr, i + 1 ); } else { return child; } } } else { return null; } } public static Date now() { return new Date(); } public static Date addSeconds( Date dt, long seconds ) { return addSeconds( dt, (int) seconds ); } public static Date addSeconds( Date dt, int seconds ) { Calendar cal = Calendar.getInstance(); cal.setTime( dt ); cal.add( Calendar.SECOND, seconds ); return cal.getTime(); } public static String getProtocol( String url ) { String protocol = url.substring( 0, url.indexOf( ":" ) ); return protocol; } public static String escapeXml( String s ) { s = s.replaceAll( "\"", """ ); s = s.replaceAll( "&", "&" ); s = s.replaceAll( "'", "'" ); s = s.replaceAll( "<", "<" ); s = s.replaceAll( ">", ">" ); // s = s.replaceAll("�", "ae"); return s; } /** * this is a modified verion of java.net.URI.encode(s) * * the java.net version only encodes characters over \u0080, but this * version also applies encoding to characters below char 48 * * this method should be applied only to parts of a URL, not the whole * URL as forward slashes, semi-colons etc will be encoded * * by "part of url" i mean the bits between slashes * * @param s */ public static String percentEncode( String s ) { s = _percentEncode( s ); // the original method, from java.net s = s.replace( ":", "%3A"); s = s.replace( ";", "%3B"); s = s.replace( "=", "%3D"); s = s.replace( "?", "%3F"); s = s.replace( "@", "%40"); return s; } private static String _percentEncode( String s ) { int n = s.length(); if( n == 0 ) { return s; } // First check whether we actually need to encode for( int i = 0;; ) { char b = s.charAt( i ); if( b >= '\u0080' || b <= (char) 48 || isSquareBracket( b ) ) { break; } if( ++i >= n ) { return s; } } String ns = normalize( s ); ByteBuffer bb = null; bb = Charset.forName( "UTF-8" ).encode( CharBuffer.wrap( ns ) ); StringBuilder sb = new StringBuilder(); while( bb.hasRemaining() ) { int b = bb.get() & 0xff; if( ( b >= 0x80 || b < (char) 48 || isSquareBracket( b ) ) && ( b != '.' && b != '-' ) ) { appendEscape( sb, (byte) b ); } else { sb.append( (char) b ); } } return sb.toString(); } private static boolean isSquareBracket( int b ) { return b == 0x5B || b == 0x5D; } private static void appendEscape( StringBuilder sb, byte b ) { sb.append( '%' ); sb.append( hexDigits[( b >> 4 ) & 0x0f] ); sb.append( hexDigits[( b >> 0 ) & 0x0f] ); } public static Date mostRecent( Date... dates ) { if( dates == null || dates.length == 0 ) return null; Date recent = dates[0]; for( Date dt : dates ) { if( dt.getTime() > recent.getTime() ) recent = dt; } return recent; } /** * java.text.Normalizer is only available for jdk 1.6. Since it isnt * really required and we don't want to annoy our 1.5 colleagues, this * is commented out. * * It isnt really needed because URLs still get consistently encoded and * decoded without it. Its just that you might get different results on different * platforms * * @param s * @return */ private static String normalize( String s ) { //return Normalizer.normalize(s, Normalizer.Form.NFC); return s; } /** * Convert the list of strings to a comma separated string * * @param list */ public static String toCsv(List<String> list) { String res = ""; Iterator<String> it = list.iterator(); while(it.hasNext()) { res += it.next(); if( it.hasNext() ) res += ", "; } return res; } }