Added URL parameter {en,de}coding.
[jsvc.git] / src / dolda / jsvc / util / Params.java
1 package dolda.jsvc.util;
2
3 import dolda.jsvc.*;
4 import java.util.*;
5 import java.io.*;
6 import java.net.*;
7 import java.nio.charset.CharacterCodingException;
8
9 public class Params {
10     public static class EncodingException extends RequestRestart {
11         public EncodingException(String msg) {
12             super(msg);
13         }
14         
15         public void respond(Request req) {
16             throw(Restarts.stdresponse(400, "Invalid parameter encoding", getMessage()));
17         }
18     }
19     
20     public static MultiMap<String, String> urlparams(String q) {
21         try {
22             MultiMap<String, String> ret = new WrappedMultiMap<String, String>(new TreeMap<String, Collection<String>>());
23             String st = "key";
24             String key = null; /* Java is stupid. */
25             MixedBuffer buf = new MixedBuffer();
26             int i = 0;
27             while(true) {
28                 int c = (i >= q.length())?-1:(q.charAt(i++));
29                 if(st == "key") {
30                     if(c == '%') {
31                         if(q.length() - i < 2)
32                             throw(new EncodingException("Invalid character escape"));
33                         try {
34                             buf.append((byte)((Misc.hex2int(q.charAt(i)) << 4) | Misc.hex2int(q.charAt(i + 1))));
35                         } catch(NumberFormatException e) {
36                             throw(new EncodingException("Invalid character escape"));
37                         }
38                         i += 2;
39                     } else if(c == '=') {
40                         key = buf.convert();
41                         buf = new MixedBuffer();
42                         st = "val";
43                     } else if(c == '&') {
44                         ret.add(buf.convert(), "");
45                         buf = new MixedBuffer();
46                     } else if(c == -1) {
47                         if(buf.size() == 0) {
48                             break;
49                         } else {
50                             ret.add(buf.convert(), "");
51                             buf = new MixedBuffer();
52                         }
53                     } else {
54                         buf.append((char)c);
55                     }
56                 } else if(st == "val") {
57                     if(c == '%') {
58                         if(q.length() - i < 2)
59                             throw(new EncodingException("Invalid character escape"));
60                         try {
61                             buf.append((byte)((Misc.hex2int(q.charAt(i)) << 4) | Misc.hex2int(q.charAt(i + 1))));
62                         } catch(NumberFormatException e) {
63                             throw(new EncodingException("Invalid character escape"));
64                         }
65                         i += 2;
66                     } else if((c == '&') || (c == -1)) {
67                         ret.add(key, buf.convert());
68                         buf = new MixedBuffer();
69                         st = "key";
70                     } else if(c == '+') {
71                         buf.append(' ');
72                     } else {
73                         buf.append((char)c);
74                     }
75                 }
76             }
77             return(ret);
78         } catch(CharacterCodingException e) {
79             throw(new EncodingException("Escaped parameter text is not proper UTF-8"));
80         }
81     }
82
83     public static MultiMap<String, String> urlparams(URL url) {
84         return(urlparams(url.getQuery()));
85     }
86
87     public static MultiMap<String, String> urlparams(Request req) {
88         return(urlparams(req.url()));
89     }
90     
91     public static String encquery(Map<String, String> pars) {
92         StringBuilder buf = new StringBuilder();
93         boolean f = true;
94         for(Map.Entry<String, String> par : pars.entrySet()) {
95             if(!f)
96                 buf.append('&');
97             buf.append(Misc.urlq(par.getKey()));
98             buf.append('=');
99             buf.append(Misc.urlq(par.getValue()));
100             f = false;
101         }
102         return(buf.toString());
103     }
104 }