Added support for decoding application/x-www-form-urlencoded POST parameters.
[jsvc.git] / src / dolda / jsvc / util / Params.java
CommitLineData
efa9722b
FT
1package dolda.jsvc.util;
2
3import dolda.jsvc.*;
4import java.util.*;
5import java.io.*;
6import java.net.*;
7import java.nio.charset.CharacterCodingException;
8
9public 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) {
ca045757
FT
84 String q = url.getQuery();
85 if(q == null)
86 q = "";
87 return(urlparams(q));
efa9722b
FT
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 }
ca045757
FT
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 }
efa9722b 138}