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 }