1 |
/* |
/* |
2 |
* $Id$ |
* HTTPURLConnection.java |
3 |
* Copyright (C) 2004 The Free Software Foundation |
* Copyright (C) 2004 The Free Software Foundation |
4 |
* |
* |
5 |
* This file is part of GNU inetlib, a library. |
* This file is part of GNU inetlib, a library. |
48 |
import java.net.URL; |
import java.net.URL; |
49 |
import java.security.AccessController; |
import java.security.AccessController; |
50 |
import java.security.PrivilegedAction; |
import java.security.PrivilegedAction; |
51 |
|
import java.util.Date; |
52 |
import java.util.Iterator; |
import java.util.Iterator; |
53 |
|
import java.util.LinkedHashMap; |
54 |
import java.util.Map; |
import java.util.Map; |
55 |
|
|
56 |
/** |
/** |
59 |
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a> |
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a> |
60 |
*/ |
*/ |
61 |
public class HTTPURLConnection |
public class HTTPURLConnection |
62 |
extends HttpURLConnection |
extends HttpURLConnection |
63 |
{ |
{ |
64 |
|
|
65 |
/* |
/* |
82 |
* Constructor. |
* Constructor. |
83 |
* @param url the URL |
* @param url the URL |
84 |
*/ |
*/ |
85 |
public HTTPURLConnection (URL url) |
public HTTPURLConnection(URL url) |
86 |
{ |
{ |
87 |
super (url); |
super(url); |
88 |
requestHeaders = new Headers (); |
requestHeaders = new Headers(); |
89 |
AccessController.doPrivileged(this.new GetProxyAction()); |
AccessController.doPrivileged(this.new GetProxyAction()); |
90 |
} |
} |
91 |
|
|
92 |
class GetProxyAction implements PrivilegedAction |
class GetProxyAction |
93 |
|
implements PrivilegedAction |
94 |
{ |
{ |
95 |
|
|
96 |
public Object run() |
public Object run() |
106 |
|
|
107 |
} |
} |
108 |
|
|
109 |
public void connect () |
public void connect() |
110 |
throws IOException |
throws IOException |
111 |
{ |
{ |
112 |
if (connected) |
if (connected) |
113 |
{ |
{ |
114 |
return; |
return; |
115 |
} |
} |
116 |
String protocol = url.getProtocol (); |
String protocol = url.getProtocol(); |
117 |
boolean secure = "https".equals (protocol); |
boolean secure = "https".equals(protocol); |
118 |
String host = url.getHost (); |
String host = url.getHost(); |
119 |
int port = url.getPort (); |
int port = url.getPort(); |
120 |
if (port < 0) |
if (port < 0) |
121 |
{ |
{ |
122 |
port = secure ? HTTPConnection.HTTPS_PORT : |
port = secure ? HTTPConnection.HTTPS_PORT : |
123 |
HTTPConnection.HTTP_PORT; |
HTTPConnection.HTTP_PORT; |
124 |
} |
} |
125 |
String file = url.getFile (); |
String file = url.getFile(); |
126 |
String username = url.getUserInfo (); |
String username = url.getUserInfo(); |
127 |
String password = null; |
String password = null; |
128 |
if (username != null) |
if (username != null) |
129 |
{ |
{ |
130 |
int ci = username.indexOf (':'); |
int ci = username.indexOf(':'); |
131 |
if (ci != -1) |
if (ci != -1) |
132 |
{ |
{ |
133 |
password = username.substring (ci + 1); |
password = username.substring(ci + 1); |
134 |
username = username.substring (0, ci); |
username = username.substring(0, ci); |
135 |
} |
} |
136 |
} |
} |
137 |
final Credentials creds = (username == null) ? null : |
final Credentials creds = (username == null) ? null : |
143 |
retry = false; |
retry = false; |
144 |
if (connection == null) |
if (connection == null) |
145 |
{ |
{ |
146 |
connection = new HTTPConnection (host, port, secure); |
connection = new HTTPConnection(host, port, secure); |
147 |
} |
} |
148 |
if (proxyHostname != null) |
if (proxyHostname != null) |
149 |
{ |
{ |
152 |
proxyPort = secure ? HTTPConnection.HTTPS_PORT : |
proxyPort = secure ? HTTPConnection.HTTPS_PORT : |
153 |
HTTPConnection.HTTP_PORT; |
HTTPConnection.HTTP_PORT; |
154 |
} |
} |
155 |
connection.setProxy (proxyHostname, proxyPort); |
connection.setProxy(proxyHostname, proxyPort); |
156 |
} |
} |
157 |
request = connection.newRequest (method, file); |
request = connection.newRequest(method, file); |
158 |
request.getHeaders ().putAll (requestHeaders); |
request.getHeaders().putAll(requestHeaders); |
159 |
if (requestSink != null) |
if (requestSink != null) |
160 |
{ |
{ |
161 |
byte[] content = requestSink.toByteArray (); |
byte[] content = requestSink.toByteArray(); |
162 |
RequestBodyWriter writer = new ByteArrayRequestBodyWriter (content); |
RequestBodyWriter writer = new ByteArrayRequestBodyWriter(content); |
163 |
request.setRequestBodyWriter (writer); |
request.setRequestBodyWriter(writer); |
164 |
} |
} |
165 |
ByteArrayResponseBodyReader reader = new ByteArrayResponseBodyReader (); |
ByteArrayResponseBodyReader reader = new ByteArrayResponseBodyReader(); |
166 |
request.setResponseBodyReader (reader); |
request.setResponseBodyReader(reader); |
167 |
if (creds != null) |
if (creds != null) |
168 |
{ |
{ |
169 |
request.setAuthenticator(new Authenticator() { |
request.setAuthenticator(new Authenticator() { |
173 |
} |
} |
174 |
}); |
}); |
175 |
} |
} |
176 |
response = request.dispatch (); |
response = request.dispatch(); |
177 |
if (response.getCodeClass () == 3 && getInstanceFollowRedirects ()) |
if (response.getCodeClass() == 3 && getInstanceFollowRedirects()) |
178 |
{ |
{ |
179 |
// Follow redirect |
// Follow redirect |
180 |
String location = response.getHeader ("Location"); |
String location = response.getHeader("Location"); |
181 |
String connectionUri = connection.getURI (); |
String connectionUri = connection.getURI(); |
182 |
int start = connectionUri.length (); |
int start = connectionUri.length(); |
183 |
if (location.startsWith (connectionUri) && |
if (location.startsWith(connectionUri) && |
184 |
location.charAt (start) == '/') |
location.charAt(start) == '/') |
185 |
{ |
{ |
186 |
file = location.substring (start); |
file = location.substring(start); |
187 |
retry = true; |
retry = true; |
188 |
} |
} |
189 |
else if (location.startsWith ("http:")) |
else if (location.startsWith("http:")) |
190 |
{ |
{ |
191 |
connection.close (); |
connection.close(); |
192 |
connection = null; |
connection = null; |
193 |
secure = false; |
secure = false; |
194 |
start = 7; |
start = 7; |
195 |
int end = location.indexOf ('/', start); |
int end = location.indexOf('/', start); |
196 |
host = location.substring(start, end); |
host = location.substring(start, end); |
197 |
int ci = host.lastIndexOf (':'); |
int ci = host.lastIndexOf(':'); |
198 |
if (ci != -1) |
if (ci != -1) |
199 |
{ |
{ |
200 |
port = Integer.parseInt (host.substring (ci + 1)); |
port = Integer.parseInt(host.substring (ci + 1)); |
201 |
host = host.substring (0, ci); |
host = host.substring(0, ci); |
202 |
} |
} |
203 |
else |
else |
204 |
{ |
{ |
205 |
port = HTTPConnection.HTTP_PORT; |
port = HTTPConnection.HTTP_PORT; |
206 |
} |
} |
207 |
file = location.substring (end); |
file = location.substring(end); |
208 |
retry = true; |
retry = true; |
209 |
} |
} |
210 |
else if (location.startsWith ("https:")) |
else if (location.startsWith("https:")) |
211 |
{ |
{ |
212 |
connection.close (); |
connection.close(); |
213 |
connection = null; |
connection = null; |
214 |
secure = true; |
secure = true; |
215 |
start = 8; |
start = 8; |
216 |
int end = location.indexOf ('/', start); |
int end = location.indexOf('/', start); |
217 |
host = location.substring(start, end); |
host = location.substring(start, end); |
218 |
int ci = host.lastIndexOf (':'); |
int ci = host.lastIndexOf(':'); |
219 |
if (ci != -1) |
if (ci != -1) |
220 |
{ |
{ |
221 |
port = Integer.parseInt (host.substring (ci + 1)); |
port = Integer.parseInt(host.substring (ci + 1)); |
222 |
host = host.substring (0, ci); |
host = host.substring(0, ci); |
223 |
} |
} |
224 |
else |
else |
225 |
{ |
{ |
226 |
port = HTTPConnection.HTTPS_PORT; |
port = HTTPConnection.HTTPS_PORT; |
227 |
} |
} |
228 |
file = location.substring (end); |
file = location.substring(end); |
229 |
retry = true; |
retry = true; |
230 |
} |
} |
231 |
// Otherwise this is not an HTTP redirect, can't follow |
// Otherwise this is not an HTTP redirect, can't follow |
232 |
} |
} |
233 |
else |
else |
234 |
{ |
{ |
235 |
responseSink = new ByteArrayInputStream (reader.toByteArray ()); |
responseSink = new ByteArrayInputStream(reader.toByteArray ()); |
236 |
} |
} |
237 |
} |
} |
238 |
while (retry); |
while (retry); |
239 |
connected = true; |
connected = true; |
240 |
} |
} |
241 |
|
|
242 |
public void disconnect () |
public void disconnect() |
243 |
{ |
{ |
244 |
if (connection != null) |
if (connection != null) |
245 |
{ |
{ |
246 |
try |
try |
247 |
{ |
{ |
248 |
connection.close (); |
connection.close(); |
249 |
} |
} |
250 |
catch (IOException e) |
catch (IOException e) |
251 |
{ |
{ |
253 |
} |
} |
254 |
} |
} |
255 |
|
|
256 |
public boolean usingProxy () |
public boolean usingProxy() |
257 |
{ |
{ |
258 |
return (proxyHostname != null); |
return (proxyHostname != null); |
259 |
} |
} |
265 |
* function. |
* function. |
266 |
* @param method the method |
* @param method the method |
267 |
*/ |
*/ |
268 |
public void setRequestMethod (String method) |
public void setRequestMethod(String method) |
269 |
throws ProtocolException |
throws ProtocolException |
270 |
{ |
{ |
271 |
if (connected) |
if (connected) |
272 |
{ |
{ |
273 |
throw new ProtocolException ("Already connected"); |
throw new ProtocolException("Already connected"); |
274 |
} |
} |
275 |
// Validate |
// Validate |
276 |
method = method.toUpperCase (); |
method = method.toUpperCase(); |
277 |
int len = method.length (); |
int len = method.length(); |
278 |
if (len == 0) |
if (len == 0) |
279 |
{ |
{ |
280 |
throw new ProtocolException ("Empty method name"); |
throw new ProtocolException("Empty method name"); |
281 |
} |
} |
282 |
for (int i = 0; i < len; i++) |
for (int i = 0; i < len; i++) |
283 |
{ |
{ |
284 |
char c = method.charAt (i); |
char c = method.charAt(i); |
285 |
if (c < 0x41 || c > 0x5a) |
if (c < 0x41 || c > 0x5a) |
286 |
{ |
{ |
287 |
throw new ProtocolException ("Illegal character '" + c + |
throw new ProtocolException("Illegal character '" + c + |
288 |
"' at index " + i); |
"' at index " + i); |
289 |
} |
} |
290 |
} |
} |
291 |
// OK |
// OK |
293 |
requestMethodSetExplicitly = true; |
requestMethodSetExplicitly = true; |
294 |
} |
} |
295 |
|
|
296 |
public String getRequestProperty (String key) |
public String getRequestProperty(String key) |
297 |
{ |
{ |
298 |
return requestHeaders.getValue (key); |
return requestHeaders.getValue(key); |
299 |
} |
} |
300 |
|
|
301 |
public Map getRequestProperties () |
public Map getRequestProperties() |
302 |
{ |
{ |
303 |
return requestHeaders; |
return requestHeaders; |
304 |
} |
} |
305 |
|
|
306 |
public void setRequestProperty (String key, String value) |
public void setRequestProperty(String key, String value) |
307 |
{ |
{ |
308 |
requestHeaders.put (key, value); |
requestHeaders.put(key, value); |
309 |
} |
} |
310 |
|
|
311 |
public void addRequestProperty (String key, String value) |
public void addRequestProperty(String key, String value) |
312 |
{ |
{ |
313 |
String old = requestHeaders.getValue (key); |
String old = requestHeaders.getValue(key); |
314 |
if (old == null) |
if (old == null) |
315 |
{ |
{ |
316 |
requestHeaders.put (key, value); |
requestHeaders.put(key, value); |
317 |
} |
} |
318 |
else |
else |
319 |
{ |
{ |
320 |
requestHeaders.put (key, old + "," + value); |
requestHeaders.put(key, old + "," + value); |
321 |
} |
} |
322 |
} |
} |
323 |
|
|
324 |
public OutputStream getOutputStream () |
public OutputStream getOutputStream() |
325 |
throws IOException |
throws IOException |
326 |
{ |
{ |
327 |
if (connected) |
if (connected) |
328 |
{ |
{ |
329 |
throw new ProtocolException ("Already connected"); |
throw new ProtocolException("Already connected"); |
330 |
} |
} |
331 |
if (!doOutput) |
if (!doOutput) |
332 |
{ |
{ |
333 |
throw new ProtocolException ("doOutput is false"); |
throw new ProtocolException("doOutput is false"); |
334 |
} |
} |
335 |
else if (!requestMethodSetExplicitly) |
else if (!requestMethodSetExplicitly) |
336 |
{ |
{ |
343 |
} |
} |
344 |
if (requestSink == null) |
if (requestSink == null) |
345 |
{ |
{ |
346 |
requestSink = new ByteArrayOutputStream (); |
requestSink = new ByteArrayOutputStream(); |
347 |
} |
} |
348 |
return requestSink; |
return requestSink; |
349 |
} |
} |
350 |
|
|
351 |
// -- Response -- |
// -- Response -- |
352 |
|
|
353 |
public InputStream getInputStream () |
public InputStream getInputStream() |
354 |
throws IOException |
throws IOException |
355 |
{ |
{ |
356 |
if (!connected) |
if (!connected) |
357 |
{ |
{ |
358 |
connect (); |
connect(); |
359 |
} |
} |
360 |
if (!doInput) |
if (!doInput) |
361 |
{ |
{ |
362 |
throw new ProtocolException ("doInput is false"); |
throw new ProtocolException("doInput is false"); |
363 |
} |
} |
364 |
return responseSink; |
return responseSink; |
365 |
} |
} |
366 |
|
|
367 |
public Map getHeaderFields () |
public Map getHeaderFields() |
368 |
{ |
{ |
369 |
if (!connected) |
if (!connected) |
370 |
{ |
{ |
371 |
return null; |
try |
372 |
|
{ |
373 |
|
connect(); |
374 |
|
} |
375 |
|
catch (IOException e) |
376 |
|
{ |
377 |
|
return null; |
378 |
|
} |
379 |
} |
} |
380 |
return response.getHeaders (); |
Map headers = response.getHeaders(); |
381 |
|
Map ret = new LinkedHashMap(); |
382 |
|
ret.put(null, getStatusLine(response)); |
383 |
|
ret.putAll(response.getHeaders()); |
384 |
|
return ret; |
385 |
} |
} |
386 |
|
|
387 |
public String getHeaderField (int index) |
String getStatusLine(Response response) |
388 |
|
{ |
389 |
|
return "HTTP/" + response.getMajorVersion() + |
390 |
|
"." + response.getMinorVersion() + |
391 |
|
" " + response.getCode() + |
392 |
|
" " + response.getMessage(); |
393 |
|
} |
394 |
|
|
395 |
|
public String getHeaderField(int index) |
396 |
{ |
{ |
397 |
if (!connected) |
if (!connected) |
398 |
{ |
{ |
399 |
return null; |
try |
400 |
|
{ |
401 |
|
connect(); |
402 |
|
} |
403 |
|
catch (IOException e) |
404 |
|
{ |
405 |
|
return null; |
406 |
|
} |
407 |
|
} |
408 |
|
if (index == 0) |
409 |
|
{ |
410 |
|
return getStatusLine(response); |
411 |
} |
} |
412 |
Iterator i = response.getHeaders ().entrySet ().iterator (); |
Iterator i = response.getHeaders().entrySet().iterator(); |
413 |
Map.Entry entry; |
Map.Entry entry; |
414 |
int count = 0; |
int count = 1; |
415 |
do |
do |
416 |
{ |
{ |
417 |
entry = (Map.Entry) i.next (); |
entry = (Map.Entry) i.next(); |
418 |
count++; |
count++; |
419 |
} |
} |
420 |
while (count < index); |
while (count < index); |
421 |
return (String) entry.getValue (); |
return (String) entry.getValue(); |
422 |
} |
} |
423 |
|
|
424 |
public String getHeaderFieldKey (int index) |
public String getHeaderFieldKey(int index) |
425 |
{ |
{ |
426 |
if (!connected) |
if (!connected) |
427 |
{ |
{ |
428 |
|
try |
429 |
|
{ |
430 |
|
connect(); |
431 |
|
} |
432 |
|
catch (IOException e) |
433 |
|
{ |
434 |
|
return null; |
435 |
|
} |
436 |
|
} |
437 |
|
if (index == null) |
438 |
|
{ |
439 |
return null; |
return null; |
440 |
} |
} |
441 |
Iterator i = response.getHeaders ().entrySet ().iterator (); |
Iterator i = response.getHeaders().entrySet().iterator(); |
442 |
Map.Entry entry; |
Map.Entry entry; |
443 |
int count = 0; |
int count = 1; |
444 |
do |
do |
445 |
{ |
{ |
446 |
entry = (Map.Entry) i.next (); |
entry = (Map.Entry) i.next(); |
447 |
count++; |
count++; |
448 |
} |
} |
449 |
while (count < index); |
while (count < index); |
450 |
return (String) entry.getKey (); |
return (String) entry.getKey(); |
451 |
|
} |
452 |
|
|
453 |
|
public String getHeaderField(String name) |
454 |
|
{ |
455 |
|
if (!connected) |
456 |
|
{ |
457 |
|
try |
458 |
|
{ |
459 |
|
connect(); |
460 |
|
} |
461 |
|
catch (IOException e) |
462 |
|
{ |
463 |
|
return null; |
464 |
|
} |
465 |
|
} |
466 |
|
return (String) response.getHeader(name); |
467 |
|
} |
468 |
|
|
469 |
|
public long getHeaderFieldDate(String name, long def) |
470 |
|
{ |
471 |
|
if (!connected) |
472 |
|
{ |
473 |
|
try |
474 |
|
{ |
475 |
|
connect(); |
476 |
|
} |
477 |
|
catch (IOException e) |
478 |
|
{ |
479 |
|
return def; |
480 |
|
} |
481 |
|
} |
482 |
|
Date date = response.getDateHeader(name); |
483 |
|
return (date == null) ? def : date.getTime(); |
484 |
|
} |
485 |
|
|
486 |
|
public String getContentType() |
487 |
|
{ |
488 |
|
return getHeaderField("Content-Type"); |
489 |
|
} |
490 |
|
|
491 |
|
public int getResponseCode() |
492 |
|
throws IOException |
493 |
|
{ |
494 |
|
if (!connected) |
495 |
|
{ |
496 |
|
connect(); |
497 |
|
} |
498 |
|
return response.getCode(); |
499 |
|
} |
500 |
|
|
501 |
|
public String getResponseMessage() |
502 |
|
throws IOException |
503 |
|
{ |
504 |
|
if (!connected) |
505 |
|
{ |
506 |
|
connect(); |
507 |
|
} |
508 |
|
return response.getMessage(); |
509 |
} |
} |
510 |
|
|
511 |
} |
} |
512 |
|
|