Skip to content

Instantly share code, notes, and snippets.

@twuni
Created July 27, 2013 07:46
Show Gist options
  • Save twuni/6094157 to your computer and use it in GitHub Desktop.
Save twuni/6094157 to your computer and use it in GitHub Desktop.
A secure, high performance, thread-safe URL encoder implementation in Java. It's intended to be a drop-in replacement for java.net.URLEncoder that uses mutable CharSequences instead of Strings, for applications which require thorough mutability for sensitive data.
import java.nio.CharBuffer;
import java.util.BitSet;
public class URLEncoder {
private static final char [] IGNORED_BY_DEFAULT = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!*()-_'.~".toCharArray();
private static final char [] HEX = "0123456789ABCDEF".toCharArray();
private static final URLEncoder DEFAULT = new URLEncoder();
public static CharSequence encode( CharSequence s ) {
return getDefaultInstance().encodeURIComponent( s );
}
public static URLEncoder getDefaultInstance() {
return DEFAULT;
}
/**
* Convert a number to a character array, using the provided buffer.
*
* @param number
* the number to convert
* @param array
* the buffer in which to store the character representation of the converted number
* @param mapping
* an array of characters whose index corresponds to the character representing that
* digit. The length of this array determines in which base the number will be
* represented in the given array.
* @return the given array, after modification. If the array's length is greater than is
* necessary, its contents will be right-aligned and left-padded with the mapping for
* the number zero. For example, the result of
* {@code itoa( 5, new char[8], "01".toCharArray() )} would be "00000101".
*/
public static char [] itoa( int number, char [] array, char [] mapping ) {
int count = 0;
int maximum = array.length - 1;
for( int value = number; value > 0; value /= mapping.length ) {
int digit = value % mapping.length;
value -= digit;
array[maximum - count] = mapping[digit];
count++;
}
if( count <= maximum ) {
for( int zero = count; zero <= maximum; zero++ ) {
array[maximum - zero] = mapping[0];
}
}
return array;
}
public static char [] itoa( int number, int arrayLength, char [] mapping ) {
return itoa( number, new char [arrayLength], mapping );
}
public static char [] itoa( int number, int arrayLength, String mapping ) {
return itoa( number, arrayLength, mapping.toCharArray() );
}
private final char [] a = new char [2];
private final BitSet ignored = new BitSet( 256 );
public URLEncoder() {
this( IGNORED_BY_DEFAULT );
}
/**
* Constructs a new URL encoder that encodes everything except the given characters.
*
* @param unencodedCharacters
* an array of characters to ignore when encoding.
*/
public URLEncoder( char [] unencodedCharacters ) {
for( int i = 0; i < unencodedCharacters.length; i++ ) {
ignored.set( unencodedCharacters[i] );
}
}
public URLEncoder( String unencodedCharacters ) {
this( unencodedCharacters.toCharArray() );
}
public CharSequence encodeURIComponent( CharSequence s ) {
CharBuffer out = CharBuffer.allocate( s.length() * 3 );
out.limit( s.length() );
for( int i = 0; i < s.length(); i++ ) {
char c = s.charAt( i );
if( ignored.get( c ) ) {
out.append( c );
} else {
out.append( '%' );
out.limit( out.limit() + 2 );
itoa( c, a, HEX );
out.append( a[0] );
out.append( a[1] );
}
}
out.position( 0 );
return out;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment