Mercurial Hosting > luan
comparison core/src/luan/modules/LuanUrl.java @ 722:647602e8291a
add url options
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Fri, 03 Jun 2016 17:51:58 -0600 |
parents | |
children | eaf30d5aaf6a |
comparison
equal
deleted
inserted
replaced
721:524ea0056573 | 722:647602e8291a |
---|---|
1 package luan.modules; | |
2 | |
3 import java.io.InputStream; | |
4 import java.io.InputStreamReader; | |
5 import java.io.OutputStream; | |
6 import java.io.Reader; | |
7 import java.io.IOException; | |
8 import java.io.UnsupportedEncodingException; | |
9 import java.net.URL; | |
10 import java.net.URLConnection; | |
11 import java.net.HttpURLConnection; | |
12 import java.net.URLEncoder; | |
13 import java.util.Map; | |
14 import java.util.HashMap; | |
15 import java.util.List; | |
16 import java.util.Base64; | |
17 import luan.LuanState; | |
18 import luan.LuanTable; | |
19 import luan.LuanJavaFunction; | |
20 import luan.LuanException; | |
21 | |
22 | |
23 public final class LuanUrl extends IoLuan.LuanIn { | |
24 private static enum Method { GET, POST, DELETE } | |
25 | |
26 private URL url; | |
27 private Method method = Method.GET; | |
28 private Map headers; | |
29 private String content; | |
30 | |
31 LuanUrl(LuanState luan,URL url,LuanTable options) throws LuanException { | |
32 this.url = url; | |
33 if( options != null ) { | |
34 Map map = options.asMap(luan); | |
35 String methodStr = getString(map,"method"); | |
36 if( methodStr != null ) { | |
37 methodStr = methodStr.toUpperCase(); | |
38 try { | |
39 this.method = Method.valueOf(methodStr); | |
40 } catch(IllegalArgumentException e) { | |
41 throw new LuanException( "invalid method: "+methodStr ); | |
42 } | |
43 } | |
44 Map auth = getMap(luan,map,"authorization"); | |
45 if( auth != null ) { | |
46 String user = getString(auth,"user"); | |
47 String password = getString(auth,"password"); | |
48 if( !auth.isEmpty() ) | |
49 throw new LuanException( "unrecognized authorization options: "+auth ); | |
50 StringBuilder sb = new StringBuilder(); | |
51 if( user != null ) | |
52 sb.append(user); | |
53 sb.append(':'); | |
54 if( password != null ) | |
55 sb.append(password); | |
56 String val = "Basic " + Base64.getEncoder().encodeToString(sb.toString().getBytes()); | |
57 if( headers == null ) | |
58 headers = new HashMap(); | |
59 headers.put("Authorization",val); | |
60 } | |
61 Map params = getMap(luan,map,"parameters"); | |
62 if( params != null ) { | |
63 StringBuilder sb = new StringBuilder(); | |
64 for( Object hack : params.entrySet() ) { | |
65 Map.Entry entry = (Map.Entry)hack; | |
66 String key = (String)entry.getKey(); | |
67 Object val = entry.getValue(); | |
68 String keyEnc = encode(key); | |
69 if( val instanceof String ) { | |
70 and(sb); | |
71 sb.append( keyEnc ).append( '=' ).append( encode((String)val) ); | |
72 } else { | |
73 if( !(val instanceof LuanTable) ) | |
74 throw new LuanException( "parameter '"+key+"' must be string or table" ); | |
75 LuanTable t = (LuanTable)val; | |
76 if( !t.isList() ) | |
77 throw new LuanException( "parameter '"+key+"' table must be list" ); | |
78 for( Object obj : t.asList() ) { | |
79 if( !(obj instanceof String) ) | |
80 throw new LuanException( "parameter '"+key+"' values must be strings" ); | |
81 and(sb); | |
82 sb.append( keyEnc ).append( '=' ).append( encode((String)obj) ); | |
83 } | |
84 } | |
85 } | |
86 if( this.method==Method.DELETE ) | |
87 throw new LuanException( "the DELETE method cannot take parameters" ); | |
88 if( this.method==Method.POST ) { | |
89 content = sb.toString(); | |
90 } else { // GET | |
91 String urlS = url.toString(); | |
92 if( urlS.indexOf('?') == -1 ) { | |
93 urlS += '?'; | |
94 } else { | |
95 urlS += '&'; | |
96 } | |
97 urlS += sb; | |
98 try { | |
99 url = new URL(urlS); | |
100 } catch(IOException e) { | |
101 throw new RuntimeException(e); | |
102 } | |
103 } | |
104 } | |
105 if( !map.isEmpty() ) | |
106 throw new LuanException( "unrecognized options: "+map ); | |
107 } | |
108 } | |
109 | |
110 private static void and(StringBuilder sb) { | |
111 if( sb.length() > 0 ) | |
112 sb.append('&'); | |
113 } | |
114 | |
115 private static String encode(String s) { | |
116 try { | |
117 return URLEncoder.encode(s,"UTF-8"); | |
118 } catch(UnsupportedEncodingException e) { | |
119 throw new RuntimeException(e); | |
120 } | |
121 } | |
122 | |
123 private static String getString(Map map,String key) throws LuanException { | |
124 Object val = map.remove(key); | |
125 if( val!=null && !(val instanceof String) ) | |
126 throw new LuanException( "parameter '"+key+"' must be a string" ); | |
127 return (String)val; | |
128 } | |
129 | |
130 private static LuanTable getTable(Map map,String key) throws LuanException { | |
131 Object val = map.remove(key); | |
132 if( val!=null && !(val instanceof LuanTable) ) | |
133 throw new LuanException( "parameter '"+key+"' must be a table" ); | |
134 return (LuanTable)val; | |
135 } | |
136 | |
137 private static Map getMap(LuanState luan,Map map,String key) throws LuanException { | |
138 LuanTable t = getTable(map,key); | |
139 return t==null ? null : t.asMap(luan); | |
140 } | |
141 | |
142 @Override InputStream inputStream() throws IOException, LuanException { | |
143 URLConnection con = url.openConnection(); | |
144 if( headers != null ) { | |
145 for( Object hack : headers.entrySet() ) { | |
146 Map.Entry entry = (Map.Entry)hack; | |
147 String key = (String)entry.getKey(); | |
148 Object val = entry.getValue(); | |
149 if( val instanceof String ) { | |
150 con.addRequestProperty(key,(String)val); | |
151 } else { | |
152 List list = (List)val; | |
153 for( Object obj : list ) { | |
154 con.addRequestProperty(key,(String)obj); | |
155 } | |
156 } | |
157 } | |
158 } | |
159 if( method==Method.GET ) { | |
160 return con.getInputStream(); | |
161 } | |
162 | |
163 HttpURLConnection httpCon = (HttpURLConnection)con; | |
164 | |
165 if( method==Method.DELETE ) { | |
166 httpCon.setRequestMethod("DELETE"); | |
167 return httpCon.getInputStream(); | |
168 } | |
169 | |
170 // POST | |
171 | |
172 // httpCon.setRequestProperty("Content-Type","application/x-www-form-urlencoded"); | |
173 httpCon.setDoOutput(true); | |
174 httpCon.setRequestMethod("POST"); | |
175 | |
176 byte[] post = content.getBytes(); | |
177 // httpCon.setRequestProperty("Content-Length",Integer.toString(post.length)); | |
178 OutputStream out = httpCon.getOutputStream(); | |
179 out.write(post); | |
180 out.flush(); | |
181 try { | |
182 try { | |
183 return httpCon.getInputStream(); | |
184 } catch(IOException e) { | |
185 InputStream is = httpCon.getErrorStream(); | |
186 if( is == null ) | |
187 throw e; | |
188 Reader in = new InputStreamReader(is); | |
189 String msg = Utils.readAll(in); | |
190 in.close(); | |
191 throw new LuanException(msg,e); | |
192 } | |
193 } finally { | |
194 out.close(); | |
195 } | |
196 } | |
197 | |
198 @Override public String to_string() { | |
199 return url.toString(); | |
200 } | |
201 | |
202 @Override public String to_uri_string() { | |
203 return url.toString(); | |
204 } | |
205 /* | |
206 public String post(String postS) throws IOException { | |
207 return new UrlCall(url).post(postS); | |
208 } | |
209 | |
210 @Override public LuanTable table() { | |
211 LuanTable tbl = super.table(); | |
212 try { | |
213 tbl.rawPut( "post", new LuanJavaFunction( | |
214 LuanUrl.class.getMethod( "post", String.class ), this | |
215 ) ); | |
216 } catch(NoSuchMethodException e) { | |
217 throw new RuntimeException(e); | |
218 } | |
219 return tbl; | |
220 } | |
221 */ | |
222 } |