Cleaned up parameter decoding.
[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(Reader in) throws IOException {
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             while(true) {
27                 int c = in.read();
28                 if(st == "key") {
29                     if(c == '%') {
30                         try {
31                             int d1 = in.read();
32                             int d2 = in.read();
33                             buf.append((byte)((Misc.hex2int((char)d1) << 4) | Misc.hex2int((char)d2)));
34                         } catch(NumberFormatException e) {
35                             throw(new EncodingException("Invalid character escape"));
36                         }
37                     } else if(c == '=') {
38                         key = buf.convert();
39                         buf = new MixedBuffer();
40                         st = "val";
41                     } else if(c == '&') {
42                         ret.add(buf.convert(), "");
43                         buf = new MixedBuffer();
44                     } else if(c == -1) {
45                         if(buf.size() == 0) {
46                             break;
47                         } else {
48                             ret.add(buf.convert(), "");
49                             buf = new MixedBuffer();
50                         }
51                     } else {
52                         buf.append((char)c);
53                     }
54                 } else if(st == "val") {
55                     if(c == '%') {
56                         try {
57                             int d1 = in.read();
58                             int d2 = in.read();
59                             buf.append((byte)((Misc.hex2int((char)d1) << 4) | Misc.hex2int((char)d2)));
60                         } catch(NumberFormatException e) {
61                             throw(new EncodingException("Invalid character escape"));
62                         }
63                     } else if((c == '&') || (c == -1)) {
64                         ret.add(key, buf.convert());
65                         buf = new MixedBuffer();
66                         st = "key";
67                     } else if(c == '+') {
68                         buf.append(' ');
69                     } else {
70                         buf.append((char)c);
71                     }
72                 }
73             }
74             return(ret);
75         } catch(CharacterCodingException e) {
76             throw(new EncodingException("Escaped parameter text is not proper UTF-8"));
77         }
78     }
79
80     public static MultiMap<String, String> urlparams(String q) {
81         try {
82             return(urlparams(new StringReader(q)));
83         } catch(IOException e) {
84             /* This will, of course, never ever once happen, but do
85              * you think Javac cares? */
86             throw(new Error(e));
87         }
88     }
89
90     public static MultiMap<String, String> urlparams(URL url) {
91         String q = url.getQuery();
92         if(q == null)
93             q = "";
94         return(urlparams(q));
95     }
96
97     public static MultiMap<String, String> urlparams(Request req) {
98         return(urlparams(req.url()));
99     }
100     
101     public static String encquery(Map<String, String> pars) {
102         StringBuilder buf = new StringBuilder();
103         boolean f = true;
104         for(Map.Entry<String, String> par : pars.entrySet()) {
105             if(!f)
106                 buf.append('&');
107             buf.append(Misc.urlq(par.getKey()));
108             buf.append('=');
109             buf.append(Misc.urlq(par.getValue()));
110             f = false;
111         }
112         return(buf.toString());
113     }
114     
115     public static MultiMap<String, String> postparams(Request req) {
116         if(req.method() != "POST")
117             return(null);
118         String ctype = req.inheaders().get("Content-Type");
119         if(ctype == null)
120             return(null);
121         ctype = ctype.toLowerCase();
122         if(ctype.equals("application/x-www-form-urlencoded")) {
123             byte[] data;
124             try {
125                 return(urlparams(new InputStreamReader(req.input(), "UTF-8")));
126             } catch(IOException e) {
127                 return(null);
128             }
129         }
130         return(null);
131     }
132 }