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