Mercurial Hosting > luan
annotate src/luan/modules/url/LuanUrl.java @ 1810:3c43b07e12b7 default tip
minor
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Sun, 12 May 2024 22:00:42 -0600 |
parents | 6668513a11d7 |
children |
rev | line source |
---|---|
725
a741a3a33423
add url support for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
723
diff
changeset
|
1 package luan.modules.url; |
722 | 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; | |
1315 | 8 import java.io.FileNotFoundException; |
722 | 9 import java.io.UnsupportedEncodingException; |
10 import java.net.URL; | |
11 import java.net.URLConnection; | |
12 import java.net.HttpURLConnection; | |
13 import java.net.URLEncoder; | |
1511 | 14 import java.net.SocketTimeoutException; |
1317
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
15 import java.security.MessageDigest; |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
16 import java.security.NoSuchAlgorithmException; |
722 | 17 import java.util.Map; |
18 import java.util.HashMap; | |
19 import java.util.List; | |
20 import java.util.Base64; | |
1509 | 21 import goodjava.io.IoUtils; |
1402
27efb1fcbcb5
move luan.lib to goodjava
Franklin Schmidt <fschmidt@gmail.com>
parents:
1392
diff
changeset
|
22 import goodjava.parser.ParseException; |
733
ffbbe25dab09
add http option time_out
Franklin Schmidt <fschmidt@gmail.com>
parents:
726
diff
changeset
|
23 import luan.Luan; |
722 | 24 import luan.LuanTable; |
25 import luan.LuanJavaFunction; | |
26 import luan.LuanException; | |
725
a741a3a33423
add url support for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
723
diff
changeset
|
27 import luan.modules.IoLuan; |
1649
f7e2df85fc0a
add String.digest_message
Franklin Schmidt <fschmidt@gmail.com>
parents:
1575
diff
changeset
|
28 import luan.modules.StringLuan; |
725
a741a3a33423
add url support for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
723
diff
changeset
|
29 import luan.modules.Utils; |
722 | 30 |
31 | |
32 public final class LuanUrl extends IoLuan.LuanIn { | |
725
a741a3a33423
add url support for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
723
diff
changeset
|
33 |
1753 | 34 private static enum Method { GET, POST, DELETE, PUT } |
722 | 35 |
1354 | 36 public final URL url; |
722 | 37 private Method method = Method.GET; |
1317
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
38 private final Map<String,Object> headers = new HashMap<String,Object>(); |
1363
1a7b8e38921a
add url post content
Franklin Schmidt <fschmidt@gmail.com>
parents:
1354
diff
changeset
|
39 private static final byte[] NO_CONTENT = new byte[0]; |
1a7b8e38921a
add url post content
Franklin Schmidt <fschmidt@gmail.com>
parents:
1354
diff
changeset
|
40 private byte[] content = NO_CONTENT; |
725
a741a3a33423
add url support for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
723
diff
changeset
|
41 private MultipartClient multipart = null; |
1511 | 42 private int timeout = 60000; |
1318
35a6a195819f
in authorization rename user to username
Franklin Schmidt <fschmidt@gmail.com>
parents:
1317
diff
changeset
|
43 private String authUsername = null; |
1317
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
44 private String authPassword = null; |
1364 | 45 public HttpURLConnection httpCon; |
722 | 46 |
1267 | 47 public LuanUrl(URL url,LuanTable options) throws LuanException { |
722 | 48 if( options != null ) { |
1420 | 49 options = new LuanTable(options); |
50 String methodStr = Utils.removeString(options,"method"); | |
722 | 51 if( methodStr != null ) { |
52 methodStr = methodStr.toUpperCase(); | |
53 try { | |
54 this.method = Method.valueOf(methodStr); | |
55 } catch(IllegalArgumentException e) { | |
56 throw new LuanException( "invalid method: "+methodStr ); | |
57 } | |
58 } | |
1420 | 59 Map headerMap = removeMap(options,"headers"); |
723 | 60 if( headerMap != null ) { |
61 for( Object hack : headerMap.entrySet() ) { | |
62 Map.Entry entry = (Map.Entry)hack; | |
1150
0842b9b570f8
change http headers interface
Franklin Schmidt <fschmidt@gmail.com>
parents:
1094
diff
changeset
|
63 String name = (String)entry.getKey(); |
723 | 64 Object val = entry.getValue(); |
65 if( val instanceof String ) { | |
66 headers.put(name,val); | |
67 } else { | |
68 if( !(val instanceof LuanTable) ) | |
1150
0842b9b570f8
change http headers interface
Franklin Schmidt <fschmidt@gmail.com>
parents:
1094
diff
changeset
|
69 throw new LuanException( "header '"+name+"' must be string or table" ); |
723 | 70 LuanTable t = (LuanTable)val; |
71 if( !t.isList() ) | |
1150
0842b9b570f8
change http headers interface
Franklin Schmidt <fschmidt@gmail.com>
parents:
1094
diff
changeset
|
72 throw new LuanException( "header '"+name+"' table must be list" ); |
723 | 73 headers.put(name,t.asList()); |
74 } | |
75 } | |
76 } | |
1420 | 77 LuanTable auth = Utils.removeTable(options,"authorization"); |
722 | 78 if( auth != null ) { |
1421 | 79 auth = new LuanTable(auth); |
1151 | 80 if( headers!=null && headers.containsKey("authorization") ) |
81 throw new LuanException( "can't define authorization with header 'authorization' defined" ); | |
1389
eb8b35dccd99
cleanup and stringify change
Franklin Schmidt <fschmidt@gmail.com>
parents:
1364
diff
changeset
|
82 String username = Utils.removeString(auth,"username"); |
1318
35a6a195819f
in authorization rename user to username
Franklin Schmidt <fschmidt@gmail.com>
parents:
1317
diff
changeset
|
83 if( username==null ) username = ""; |
1389
eb8b35dccd99
cleanup and stringify change
Franklin Schmidt <fschmidt@gmail.com>
parents:
1364
diff
changeset
|
84 String password = Utils.removeString(auth,"password"); |
1317
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
85 if( password==null ) password = ""; |
1389
eb8b35dccd99
cleanup and stringify change
Franklin Schmidt <fschmidt@gmail.com>
parents:
1364
diff
changeset
|
86 String type = Utils.removeString(auth,"type"); |
722 | 87 if( !auth.isEmpty() ) |
88 throw new LuanException( "unrecognized authorization options: "+auth ); | |
1317
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
89 if( type != null ) { |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
90 if( !type.toLowerCase().equals("basic") ) |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
91 throw new LuanException( "authorization type can only be 'basic' or nil" ); |
1318
35a6a195819f
in authorization rename user to username
Franklin Schmidt <fschmidt@gmail.com>
parents:
1317
diff
changeset
|
92 String val = basicAuth(username,password); |
1317
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
93 headers.put("authorization",val); |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
94 } else { |
1318
35a6a195819f
in authorization rename user to username
Franklin Schmidt <fschmidt@gmail.com>
parents:
1317
diff
changeset
|
95 authUsername = username; |
1317
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
96 authPassword = password; |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
97 } |
722 | 98 } |
1420 | 99 Map params = removeMap(options,"parameters"); |
100 String enctype = Utils.removeString(options,"enctype"); | |
101 Object content = options.remove("content"); | |
1363
1a7b8e38921a
add url post content
Franklin Schmidt <fschmidt@gmail.com>
parents:
1354
diff
changeset
|
102 if( content != null ) { |
1759 | 103 if( this.method != Method.POST && this.method != Method.PUT ) |
104 throw new LuanException( "content can only be used with POST or PUT" ); | |
1363
1a7b8e38921a
add url post content
Franklin Schmidt <fschmidt@gmail.com>
parents:
1354
diff
changeset
|
105 if( params != null ) |
1a7b8e38921a
add url post content
Franklin Schmidt <fschmidt@gmail.com>
parents:
1354
diff
changeset
|
106 throw new LuanException( "content cannot be used with parameters" ); |
1a7b8e38921a
add url post content
Franklin Schmidt <fschmidt@gmail.com>
parents:
1354
diff
changeset
|
107 if( content instanceof String ) { |
1a7b8e38921a
add url post content
Franklin Schmidt <fschmidt@gmail.com>
parents:
1354
diff
changeset
|
108 this.content = ((String)content).getBytes(); |
1a7b8e38921a
add url post content
Franklin Schmidt <fschmidt@gmail.com>
parents:
1354
diff
changeset
|
109 } else if( content instanceof byte[] ) { |
1a7b8e38921a
add url post content
Franklin Schmidt <fschmidt@gmail.com>
parents:
1354
diff
changeset
|
110 this.content = (byte[])content; |
1a7b8e38921a
add url post content
Franklin Schmidt <fschmidt@gmail.com>
parents:
1354
diff
changeset
|
111 } else |
1a7b8e38921a
add url post content
Franklin Schmidt <fschmidt@gmail.com>
parents:
1354
diff
changeset
|
112 throw new LuanException( "content must be String or byte[]" ); |
1a7b8e38921a
add url post content
Franklin Schmidt <fschmidt@gmail.com>
parents:
1354
diff
changeset
|
113 } |
726
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
114 if( enctype != null ) { |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
115 if( !enctype.equals("multipart/form-data") ) |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
116 throw new LuanException( "unrecognized enctype: "+enctype ); |
1759 | 117 if( this.method != Method.POST && this.method != Method.PUT ) |
118 throw new LuanException( "multipart/form-data can only be used with POST or PUT" ); | |
726
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
119 if( params==null ) |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
120 throw new LuanException( "multipart/form-data requires parameters" ); |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
121 if( params.isEmpty() ) |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
122 throw new LuanException( "multipart/form-data parameters can't be empty" ); |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
123 multipart = new MultipartClient(params); |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
124 } |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
125 else if( params != null ) { |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
126 StringBuilder sb = new StringBuilder(); |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
127 for( Object hack : params.entrySet() ) { |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
128 Map.Entry entry = (Map.Entry)hack; |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
129 String key = (String)entry.getKey(); |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
130 Object val = entry.getValue(); |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
131 String keyEnc = encode(key); |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
132 if( val instanceof String ) { |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
133 and(sb); |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
134 sb.append( keyEnc ).append( '=' ).append( encode((String)val) ); |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
135 } else { |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
136 if( !(val instanceof LuanTable) ) |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
137 throw new LuanException( "parameter '"+key+"' must be string or table" ); |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
138 LuanTable t = (LuanTable)val; |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
139 if( !t.isList() ) |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
140 throw new LuanException( "parameter '"+key+"' table must be list" ); |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
141 for( Object obj : t.asList() ) { |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
142 if( !(obj instanceof String) ) |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
143 throw new LuanException( "parameter '"+key+"' values must be strings" ); |
722 | 144 and(sb); |
726
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
145 sb.append( keyEnc ).append( '=' ).append( encode((String)obj) ); |
722 | 146 } |
147 } | |
726
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
148 } |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
149 if( this.method==Method.POST ) { |
1363
1a7b8e38921a
add url post content
Franklin Schmidt <fschmidt@gmail.com>
parents:
1354
diff
changeset
|
150 this.content = sb.toString().getBytes(); |
780
6a87d51ae0ed
allow parameters for HTTP DELETE
Franklin Schmidt <fschmidt@gmail.com>
parents:
775
diff
changeset
|
151 } else { |
1354 | 152 String urlS = url.toString(); |
726
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
153 if( urlS.indexOf('?') == -1 ) { |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
154 urlS += '?'; |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
155 } else { |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
156 urlS += '&'; |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
157 } |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
158 urlS += sb; |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
159 try { |
1354 | 160 url = new URL(urlS); |
726
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
161 } catch(IOException e) { |
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
162 throw new RuntimeException(e); |
722 | 163 } |
164 } | |
165 } | |
1420 | 166 Integer timeout = Utils.removeInteger(options,"time_out"); |
733
ffbbe25dab09
add http option time_out
Franklin Schmidt <fschmidt@gmail.com>
parents:
726
diff
changeset
|
167 if( timeout != null ) |
ffbbe25dab09
add http option time_out
Franklin Schmidt <fschmidt@gmail.com>
parents:
726
diff
changeset
|
168 this.timeout = timeout; |
1420 | 169 Utils.checkEmpty(options); |
722 | 170 } |
1354 | 171 this.url = url; |
722 | 172 } |
173 | |
174 private static void and(StringBuilder sb) { | |
175 if( sb.length() > 0 ) | |
176 sb.append('&'); | |
177 } | |
178 | |
179 private static String encode(String s) { | |
180 try { | |
181 return URLEncoder.encode(s,"UTF-8"); | |
182 } catch(UnsupportedEncodingException e) { | |
183 throw new RuntimeException(e); | |
184 } | |
185 } | |
186 | |
1420 | 187 private static Map removeMap(LuanTable options,String key) throws LuanException { |
188 LuanTable t = Utils.removeTable(options,key); | |
1267 | 189 return t==null ? null : t.asMap(); |
722 | 190 } |
191 | |
1335 | 192 @Override public InputStream inputStream() throws IOException, LuanException { |
1317
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
193 try { |
1335 | 194 return inputStream(null); |
1511 | 195 } catch(SocketTimeoutException e) { |
196 String msg = e.getMessage(); | |
197 if( msg != null ) { | |
198 throw new LuanException(e.getMessage()); | |
199 } else { | |
200 throw e; | |
201 } | |
1317
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
202 } catch(AuthException e) { |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
203 try { |
1335 | 204 return inputStream(e.authorization); |
1317
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
205 } catch(AuthException e2) { |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
206 throw new RuntimeException(e2); // never |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
207 } |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
208 } |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
209 } |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
210 |
1335 | 211 private InputStream inputStream(String authorization) |
1317
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
212 throws IOException, LuanException, AuthException |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
213 { |
722 | 214 URLConnection con = url.openConnection(); |
733
ffbbe25dab09
add http option time_out
Franklin Schmidt <fschmidt@gmail.com>
parents:
726
diff
changeset
|
215 if( timeout != 0 ) { |
ffbbe25dab09
add http option time_out
Franklin Schmidt <fschmidt@gmail.com>
parents:
726
diff
changeset
|
216 con.setConnectTimeout(timeout); |
ffbbe25dab09
add http option time_out
Franklin Schmidt <fschmidt@gmail.com>
parents:
726
diff
changeset
|
217 con.setReadTimeout(timeout); |
ffbbe25dab09
add http option time_out
Franklin Schmidt <fschmidt@gmail.com>
parents:
726
diff
changeset
|
218 } |
1317
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
219 for( Map.Entry<String,Object> entry : headers.entrySet() ) { |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
220 String key = entry.getKey(); |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
221 Object val = entry.getValue(); |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
222 if( val instanceof String ) { |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
223 con.addRequestProperty(key,(String)val); |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
224 } else { |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
225 List list = (List)val; |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
226 for( Object obj : list ) { |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
227 con.addRequestProperty(key,(String)obj); |
722 | 228 } |
229 } | |
230 } | |
1317
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
231 if( authorization != null ) |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
232 con.addRequestProperty("Authorization",authorization); |
1087
4aab4dd3ac9c
improve url error handling
Franklin Schmidt <fschmidt@gmail.com>
parents:
1085
diff
changeset
|
233 if( !(con instanceof HttpURLConnection) ) { |
4aab4dd3ac9c
improve url error handling
Franklin Schmidt <fschmidt@gmail.com>
parents:
1085
diff
changeset
|
234 if( method!=Method.GET ) |
4aab4dd3ac9c
improve url error handling
Franklin Schmidt <fschmidt@gmail.com>
parents:
1085
diff
changeset
|
235 throw new LuanException("method must be GET but is "+method); |
722 | 236 return con.getInputStream(); |
237 } | |
238 | |
1364 | 239 httpCon = (HttpURLConnection)con; |
722 | 240 |
1087
4aab4dd3ac9c
improve url error handling
Franklin Schmidt <fschmidt@gmail.com>
parents:
1085
diff
changeset
|
241 if( method==Method.GET ) { |
1335 | 242 return getInputStream(httpCon,authorization); |
1087
4aab4dd3ac9c
improve url error handling
Franklin Schmidt <fschmidt@gmail.com>
parents:
1085
diff
changeset
|
243 } |
4aab4dd3ac9c
improve url error handling
Franklin Schmidt <fschmidt@gmail.com>
parents:
1085
diff
changeset
|
244 |
722 | 245 if( method==Method.DELETE ) { |
246 httpCon.setRequestMethod("DELETE"); | |
1335 | 247 return getInputStream(httpCon,authorization); |
722 | 248 } |
249 | |
1759 | 250 /* |
1753 | 251 if( method==Method.PUT ) { |
252 httpCon.setRequestMethod("PUT"); | |
253 return getInputStream(httpCon,authorization); | |
254 } | |
1759 | 255 */ |
1753 | 256 |
1759 | 257 // POST or PUT |
722 | 258 |
1165
668f29bc52ea
clean up content-type
Franklin Schmidt <fschmidt@gmail.com>
parents:
1151
diff
changeset
|
259 // httpCon.setRequestProperty("content-type","application/x-www-form-urlencoded"); |
722 | 260 httpCon.setDoOutput(true); |
1759 | 261 httpCon.setRequestMethod(method.toString()); |
722 | 262 |
725
a741a3a33423
add url support for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
723
diff
changeset
|
263 OutputStream out; |
a741a3a33423
add url support for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
723
diff
changeset
|
264 if( multipart != null ) { |
a741a3a33423
add url support for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
723
diff
changeset
|
265 out = multipart.write(httpCon); |
a741a3a33423
add url support for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
723
diff
changeset
|
266 } else { |
1363
1a7b8e38921a
add url post content
Franklin Schmidt <fschmidt@gmail.com>
parents:
1354
diff
changeset
|
267 // httpCon.setRequestProperty("Content-Length",Integer.toString(content.length)); |
725
a741a3a33423
add url support for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
723
diff
changeset
|
268 out = httpCon.getOutputStream(); |
1363
1a7b8e38921a
add url post content
Franklin Schmidt <fschmidt@gmail.com>
parents:
1354
diff
changeset
|
269 out.write(content); |
725
a741a3a33423
add url support for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
723
diff
changeset
|
270 } |
726
14f136a4641f
use enctype for multipart/form-data
Franklin Schmidt <fschmidt@gmail.com>
parents:
725
diff
changeset
|
271 out.flush(); |
722 | 272 try { |
1335 | 273 return getInputStream(httpCon,authorization); |
722 | 274 } finally { |
275 out.close(); | |
276 } | |
277 } | |
278 | |
1335 | 279 private InputStream getInputStream(HttpURLConnection httpCon,String authorization) |
1317
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
280 throws IOException, LuanException, AuthException |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
281 { |
1085
a04da9a3e9eb
improve url delete error handling
Franklin Schmidt <fschmidt@gmail.com>
parents:
780
diff
changeset
|
282 try { |
a04da9a3e9eb
improve url delete error handling
Franklin Schmidt <fschmidt@gmail.com>
parents:
780
diff
changeset
|
283 return httpCon.getInputStream(); |
1349 | 284 // } catch(FileNotFoundException e) { |
285 // throw e; | |
1085
a04da9a3e9eb
improve url delete error handling
Franklin Schmidt <fschmidt@gmail.com>
parents:
780
diff
changeset
|
286 } catch(IOException e) { |
1094
cb4c20fce7d0
add "response_code" and "response_message" to http url luan exceptions
Franklin Schmidt <fschmidt@gmail.com>
parents:
1087
diff
changeset
|
287 int responseCode = httpCon.getResponseCode(); |
1318
35a6a195819f
in authorization rename user to username
Franklin Schmidt <fschmidt@gmail.com>
parents:
1317
diff
changeset
|
288 if( responseCode == 401 && authUsername != null && authorization==null ) { |
1317
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
289 String authStr = httpCon.getHeaderField("www-authenticate"); |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
290 //System.out.println("auth = "+authStr); |
1575
0160650180bc
better http authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1519
diff
changeset
|
291 List<WwwAuthenticate> auths; |
1317
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
292 try { |
1575
0160650180bc
better http authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1519
diff
changeset
|
293 auths = WwwAuthenticate.parse(authStr); |
0160650180bc
better http authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1519
diff
changeset
|
294 } catch(ParseException pe) { |
0160650180bc
better http authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1519
diff
changeset
|
295 throw new LuanException(pe); |
0160650180bc
better http authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1519
diff
changeset
|
296 } |
0160650180bc
better http authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1519
diff
changeset
|
297 for( WwwAuthenticate auth : auths ) { |
1317
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
298 if( auth.type.equals("Basic") ) { |
1318
35a6a195819f
in authorization rename user to username
Franklin Schmidt <fschmidt@gmail.com>
parents:
1317
diff
changeset
|
299 String val = basicAuth(authUsername,authPassword); |
1317
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
300 throw new AuthException(val); |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
301 } else if( auth.type.equals("Digest") ) { |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
302 String realm = auth.options.get("realm"); |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
303 if(realm==null) throw new RuntimeException("missing realm"); |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
304 String algorithm = auth.options.get("algorithm"); |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
305 if( algorithm!=null && !algorithm.equals("MD5") ) |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
306 throw new LuanException("unsupported digest algorithm: "+algorithm); |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
307 String qop = auth.options.get("qop"); |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
308 if( qop!=null && !qop.equals("auth") ) |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
309 throw new LuanException("unsupported digest qop: "+qop); |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
310 String nonce = auth.options.get("nonce"); |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
311 if(nonce==null) throw new RuntimeException("missing nonce"); |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
312 String uri = fullPath(url); |
1318
35a6a195819f
in authorization rename user to username
Franklin Schmidt <fschmidt@gmail.com>
parents:
1317
diff
changeset
|
313 String a1 = authUsername + ':' + realm + ':' + authPassword; |
1317
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
314 String a2 = "" + method + ':' + uri; |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
315 String nc = "00000001"; |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
316 String cnonce = "7761faf2daa45b3b"; // who cares? |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
317 String response = md5(a1) + ':' + nonce; |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
318 if( qop != null ) { |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
319 response += ':' + nc + ':' + cnonce + ':' + qop; |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
320 } |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
321 response += ':' + md5(a2); |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
322 response = md5(response); |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
323 String val = "Digest"; |
1318
35a6a195819f
in authorization rename user to username
Franklin Schmidt <fschmidt@gmail.com>
parents:
1317
diff
changeset
|
324 val += " username=\"" + authUsername + "\""; |
1317
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
325 val += ", realm=\"" + realm + "\""; |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
326 val += ", uri=\"" + uri + "\""; |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
327 val += ", nonce=\"" + nonce + "\""; |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
328 val += ", response=\"" + response + "\""; |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
329 if( qop != null ) { |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
330 val += ", qop=" + qop; |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
331 val += ", nc=" + nc; |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
332 val += ", cnonce=\"" + cnonce + "\""; |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
333 } |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
334 //System.out.println("val = "+val); |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
335 throw new AuthException(val); |
1575
0160650180bc
better http authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1519
diff
changeset
|
336 } |
1317
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
337 } |
1575
0160650180bc
better http authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1519
diff
changeset
|
338 throw new RuntimeException(authStr); |
1317
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
339 } |
1519 | 340 String msg = "" + responseCode; |
1094
cb4c20fce7d0
add "response_code" and "response_message" to http url luan exceptions
Franklin Schmidt <fschmidt@gmail.com>
parents:
1087
diff
changeset
|
341 String responseMessage = httpCon.getResponseMessage(); |
1519 | 342 if( responseMessage != null ) |
343 msg += " - " + responseMessage; | |
344 String responseContent = null; | |
1085
a04da9a3e9eb
improve url delete error handling
Franklin Schmidt <fschmidt@gmail.com>
parents:
780
diff
changeset
|
345 InputStream is = httpCon.getErrorStream(); |
1519 | 346 if( is != null ) { |
347 Reader in = new InputStreamReader(is); | |
348 responseContent = IoUtils.readAll(in); | |
349 in.close(); | |
350 msg += "\n" + responseContent; | |
351 } | |
1094
cb4c20fce7d0
add "response_code" and "response_message" to http url luan exceptions
Franklin Schmidt <fschmidt@gmail.com>
parents:
1087
diff
changeset
|
352 LuanException le = new LuanException(msg,e); |
1335 | 353 le.put("response_code",responseCode); |
354 le.put("response_message",responseMessage); | |
1519 | 355 le.put("response_content",responseContent); |
1094
cb4c20fce7d0
add "response_code" and "response_message" to http url luan exceptions
Franklin Schmidt <fschmidt@gmail.com>
parents:
1087
diff
changeset
|
356 throw le; |
1085
a04da9a3e9eb
improve url delete error handling
Franklin Schmidt <fschmidt@gmail.com>
parents:
780
diff
changeset
|
357 } |
a04da9a3e9eb
improve url delete error handling
Franklin Schmidt <fschmidt@gmail.com>
parents:
780
diff
changeset
|
358 } |
a04da9a3e9eb
improve url delete error handling
Franklin Schmidt <fschmidt@gmail.com>
parents:
780
diff
changeset
|
359 |
722 | 360 @Override public String to_string() { |
361 return url.toString(); | |
362 } | |
363 | |
364 @Override public String to_uri_string() { | |
365 return url.toString(); | |
366 } | |
367 | |
1318
35a6a195819f
in authorization rename user to username
Franklin Schmidt <fschmidt@gmail.com>
parents:
1317
diff
changeset
|
368 private static String basicAuth(String username,String password) { |
35a6a195819f
in authorization rename user to username
Franklin Schmidt <fschmidt@gmail.com>
parents:
1317
diff
changeset
|
369 String s = username + ':' + password; |
1317
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
370 return "Basic " + Base64.getEncoder().encodeToString(s.getBytes()); |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
371 } |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
372 |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
373 private final class AuthException extends Exception { |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
374 final String authorization; |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
375 |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
376 AuthException(String authorization) { |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
377 this.authorization = authorization; |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
378 } |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
379 } |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
380 |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
381 // retarded java api lacks this |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
382 public static String fullPath(URL url) { |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
383 String path = url.getPath(); |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
384 String query = url.getQuery(); |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
385 if( query != null ) |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
386 path += "?" + query; |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
387 return path; |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
388 } |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
389 |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
390 public static String md5(String s) { |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
391 try { |
1649
f7e2df85fc0a
add String.digest_message
Franklin Schmidt <fschmidt@gmail.com>
parents:
1575
diff
changeset
|
392 return StringLuan.digest_message("MD5",s); |
f7e2df85fc0a
add String.digest_message
Franklin Schmidt <fschmidt@gmail.com>
parents:
1575
diff
changeset
|
393 } catch(LuanException e) { |
f7e2df85fc0a
add String.digest_message
Franklin Schmidt <fschmidt@gmail.com>
parents:
1575
diff
changeset
|
394 throw new RuntimeException(e); |
1317
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
395 } catch(NoSuchAlgorithmException e) { |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
396 throw new RuntimeException(e); |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
397 } |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
398 } |
c286c1e36b81
add client digest authentication
Franklin Schmidt <fschmidt@gmail.com>
parents:
1315
diff
changeset
|
399 |
722 | 400 } |