99320a50117fafc2bf8b9639f43edc67e802a944
[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         String q = url.getQuery();
85         if(q == null)
86             q = "";
87         return(urlparams(q));
88     }
89
90     public static MultiMap<String, String> urlparams(Request req) {
91         return(urlparams(req.url()));
92     }
93     
94     public static String encquery(Map<String, String> pars) {
95         StringBuilder buf = new StringBuilder();
96         boolean f = true;
97         for(Map.Entry<String, String> par : pars.entrySet()) {
98             if(!f)
99                 buf.append('&');
100             buf.append(Misc.urlq(par.getKey()));
101             buf.append('=');
102             buf.append(Misc.urlq(par.getValue()));
103             f = false;
104         }
105         return(buf.toString());
106     }
107     
108     public static MultiMap<String, String> postparams(Request req) {
109         if(req.method() != "POST")
110             return(null);
111         String clens = req.inheaders().get("Content-Length");
112         if(clens == null)
113             return(null);
114         int clen;
115         try {
116             clen = Integer.parseInt(clens);
117         } catch(NumberFormatException e) {
118             return(null);
119         }
120         String ctype = req.inheaders().get("Content-Type");
121         if(ctype == null)
122             return(null);
123         ctype = ctype.toLowerCase();
124         if(ctype.equals("application/x-www-form-urlencoded")) {
125             if(clen > (1 << 20)) /* Just to be safe */
126                 return(null);
127             byte[] data;
128             try {
129                 data = Misc.readall(req.input());
130             } catch(IOException e) {
131                 return(null);
132             }
133             String dec = new String(data, Misc.utf8);
134             return(urlparams(dec));
135         }
136         return(null);
137     }
138 }