001 package railo.commons.net; 002 003 import java.io.UnsupportedEncodingException; 004 005 import railo.commons.io.SystemUtil; 006 import railo.runtime.net.http.ReqRspUtil; 007 008 public class URLDecoder { 009 010 private URLDecoder(){} 011 012 /** 013 * @param string 014 * @return 015 */ 016 public static String decode(String str, boolean force) { 017 try { 018 return decode(str,SystemUtil.getCharset(), force); 019 } 020 catch (UnsupportedEncodingException e) { 021 return str; 022 } 023 } 024 025 /** 026 * Decodes a <code>application/x-www-form-urlencoded</code> string using a specific 027 * encoding scheme. 028 * The supplied encoding is used to determine 029 * what characters are represented by any consecutive sequences of the 030 * form "<code>%<i>xy</i></code>". 031 * <p> 032 * <em><strong>Note:</strong> The <a href= 033 * "http://www.w3.org/TR/html40/appendix/notes.html#non-ascii-chars"> 034 * World Wide Web Consortium Recommendation</a> states that 035 * UTF-8 should be used. Not doing so may introduce 036 * incompatibilites.</em> 037 * 038 * @param s the <code>String</code> to decode 039 * @param enc The name of a supported 040 * <a href="../lang/package-summary.html#charenc">character 041 * encoding</a>. 042 * @param force if set to false Railo only encodes when there is at least one "%<2-digit-hex-value>" in string, means string with only + inside are not encoded 043 * @return the newly decoded <code>String</code> 044 * @throws UnsupportedEncodingException 045 * @see URLEncoder#encode(java.lang.String, java.lang.String) 046 */ 047 public static String decode(String s, String enc, boolean force) throws UnsupportedEncodingException { 048 if(!force && !ReqRspUtil.needDecoding(s)) return s; 049 //if(true) return java.net.URLDecoder.decode(s, enc); 050 051 boolean needToChange = false; 052 StringBuilder sb = new StringBuilder(); 053 int numChars = s.length(); 054 int i = 0; 055 056 057 058 while (i < numChars) { 059 char c = s.charAt(i); 060 switch (c) { 061 case '+': 062 sb.append(' '); 063 i++; 064 needToChange = true; 065 break; 066 case '%': 067 068 try { 069 byte[] bytes = new byte[(numChars-i)/3]; 070 int pos = 0; 071 072 while ( ((i+2) < numChars) && 073 (c=='%')) { 074 bytes[pos++] = (byte)Integer.parseInt(s.substring(i+1,i+3),16); 075 i+= 3; 076 if (i < numChars) 077 c = s.charAt(i); 078 } 079 080 if ((i < numChars) && (c=='%')){ 081 needToChange = true; 082 sb.append(c); 083 i++; 084 continue; 085 //throw new IOException("Incomplete trailing escape (%) pattern"); 086 } 087 sb.append(new String(bytes, 0, pos, enc)); 088 } catch (NumberFormatException e) { 089 needToChange = true; 090 sb.append(c); 091 i++; 092 //throw new IOException("Illegal hex characters in escape (%) pattern - " + e.getMessage()); 093 } 094 needToChange = true; 095 break; 096 default: 097 sb.append(c); 098 i++; 099 break; 100 } 101 } 102 103 return (needToChange? sb.toString() : s); 104 } 105 } 106 107