1:
37:
38:
39: package ;
40:
41: import ;
42: import ;
43: import ;
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51: import ;
52: import ;
53: import ;
54: import ;
55: import ;
56:
57: import ;
58: import ;
59: import ;
60: import ;
61: import ;
62: import ;
63:
64:
69: public class HTTPURLConnection
70: extends HttpsURLConnection
71: implements HandshakeCompletedListener
72: {
73:
74:
77: private static final LinkedHashMap connectionPool = new LinkedHashMap();
78: static int maxConnections;
79:
80:
83: private HTTPConnection connection;
84:
85:
86: String proxyHostname;
87: int proxyPort;
88: String agent;
89: boolean keepAlive;
90:
91: private Request request;
92: private Headers requestHeaders;
93: private ByteArrayOutputStream requestSink;
94: private boolean requestMethodSetExplicitly;
95:
96: private Response response;
97: private InputStream responseSink;
98: private InputStream errorSink;
99:
100: private HandshakeCompletedEvent handshakeEvent;
101:
102:
106: public HTTPURLConnection(URL url)
107: throws IOException
108: {
109: super(url);
110: requestHeaders = new Headers();
111: AccessController.doPrivileged(this.new GetHTTPPropertiesAction());
112: }
113:
114: class GetHTTPPropertiesAction
115: implements PrivilegedAction
116: {
117:
118: public Object run()
119: {
120: proxyHostname = System.getProperty("http.proxyHost");
121: if (proxyHostname != null && proxyHostname.length() > 0)
122: {
123: String port = System.getProperty("http.proxyPort");
124: if (port != null && port.length() > 0)
125: {
126: proxyPort = Integer.parseInt(port);
127: }
128: else
129: {
130: proxyHostname = null;
131: proxyPort = -1;
132: }
133: }
134: agent = System.getProperty("http.agent");
135: String ka = System.getProperty("http.keepAlive");
136: keepAlive = !(ka != null && "false".equals(ka));
137: String mc = System.getProperty("http.maxConnections");
138: maxConnections = (mc != null && mc.length() > 0) ?
139: Math.max(Integer.parseInt(mc), 1) : 5;
140: return null;
141: }
142:
143: }
144:
145: public void connect()
146: throws IOException
147: {
148: if (connected)
149: {
150: return;
151: }
152: String protocol = url.getProtocol();
153: boolean secure = "https".equals(protocol);
154: String host = url.getHost();
155: int port = url.getPort();
156: if (port < 0)
157: {
158: port = secure ? HTTPConnection.HTTPS_PORT :
159: HTTPConnection.HTTP_PORT;
160: }
161: String file = url.getFile();
162: String username = url.getUserInfo();
163: String password = null;
164: if (username != null)
165: {
166: int ci = username.indexOf(':');
167: if (ci != -1)
168: {
169: password = username.substring(ci + 1);
170: username = username.substring(0, ci);
171: }
172: }
173: final Credentials creds = (username == null) ? null :
174: new Credentials (username, password);
175:
176: boolean retry;
177: do
178: {
179: retry = false;
180: if (connection == null)
181: {
182: connection = getConnection(host, port, secure);
183: if (secure)
184: {
185: SSLSocketFactory factory = getSSLSocketFactory();
186: HostnameVerifier verifier = getHostnameVerifier();
187: if (factory != null)
188: {
189: connection.setSSLSocketFactory(factory);
190: }
191: connection.addHandshakeCompletedListener(this);
192:
193: }
194: }
195: if (proxyHostname != null)
196: {
197: if (proxyPort < 0)
198: {
199: proxyPort = secure ? HTTPConnection.HTTPS_PORT :
200: HTTPConnection.HTTP_PORT;
201: }
202: connection.setProxy(proxyHostname, proxyPort);
203: }
204: try
205: {
206: request = connection.newRequest(method, file);
207: if (!keepAlive)
208: {
209: request.setHeader("Connection", "close");
210: }
211: if (agent != null)
212: {
213: request.setHeader("User-Agent", agent);
214: }
215: request.getHeaders().putAll(requestHeaders);
216: if (requestSink != null)
217: {
218: byte[] content = requestSink.toByteArray();
219: RequestBodyWriter writer = new ByteArrayRequestBodyWriter(content);
220: request.setRequestBodyWriter(writer);
221: }
222: if (creds != null)
223: {
224: request.setAuthenticator(new Authenticator() {
225: public Credentials getCredentials(String realm, int attempts)
226: {
227: return (attempts < 2) ? creds : null;
228: }
229: });
230: }
231: response = request.dispatch();
232: }
233: catch (IOException ioe)
234: {
235: if (connection.useCount > 0)
236: {
237:
238: try
239: {
240: connection.close();
241: }
242: catch (IOException _)
243: {
244:
245: }
246: connection = null;
247: retry = true;
248: continue;
249: }
250: else
251: {
252:
253: throw ioe;
254: }
255: }
256:
257: if (isRedirect(response) && getInstanceFollowRedirects())
258: {
259:
260:
261:
262:
263: InputStream body = response.getBody();
264: if (body != null)
265: {
266: byte[] ignore = new byte[1024];
267: while (true)
268: {
269: int n = body.read(ignore, 0, ignore.length);
270: if (n == -1)
271: break;
272: }
273: }
274:
275:
276: String location = response.getHeader("Location");
277: if (location != null)
278: {
279: String connectionUri = connection.getURI();
280: int start = connectionUri.length();
281: if (location.startsWith(connectionUri) &&
282: location.charAt(start) == '/')
283: {
284: file = location.substring(start);
285: retry = true;
286: }
287: else if (location.startsWith("http:"))
288: {
289: connection.close();
290: connection = null;
291: secure = false;
292: start = 7;
293: int end = location.indexOf('/', start);
294: if (end == -1)
295: end = location.length();
296: host = location.substring(start, end);
297: int ci = host.lastIndexOf(':');
298: if (ci != -1)
299: {
300: port = Integer.parseInt(host.substring (ci + 1));
301: host = host.substring(0, ci);
302: }
303: else
304: {
305: port = HTTPConnection.HTTP_PORT;
306: }
307: file = location.substring(end);
308: retry = true;
309: }
310: else if (location.startsWith("https:"))
311: {
312: connection.close();
313: connection = null;
314: secure = true;
315: start = 8;
316: int end = location.indexOf('/', start);
317: if (end == -1)
318: end = location.length();
319: host = location.substring(start, end);
320: int ci = host.lastIndexOf(':');
321: if (ci != -1)
322: {
323: port = Integer.parseInt(host.substring (ci + 1));
324: host = host.substring(0, ci);
325: }
326: else
327: {
328: port = HTTPConnection.HTTPS_PORT;
329: }
330: file = location.substring(end);
331: retry = true;
332: }
333: else if (location.length() > 0)
334: {
335:
336: if (location.charAt(0) == '/')
337: {
338:
339: file = location;
340: }
341: else
342: {
343:
344: int lsi = file.lastIndexOf('/');
345: file = (lsi == -1) ? "/" : file.substring(0, lsi + 1);
346: file += location;
347: }
348: retry = true;
349: }
350: }
351: }
352: else
353: {
354: responseSink = response.getBody();
355:
356: if (response.getCode() == 404)
357: {
358: errorSink = responseSink;
359: throw new FileNotFoundException(url.toString());
360: }
361: }
362: }
363: while (retry);
364: connected = true;
365: }
366:
367: private static boolean isRedirect(Response response)
368: {
369: int sc = response.getCode();
370: return (sc != 304 && (sc / 100) == 3);
371: }
372:
373:
376: HTTPConnection getConnection(String host, int port, boolean secure)
377: throws IOException
378: {
379: HTTPConnection connection;
380: if (keepAlive)
381: {
382: Object key = HTTPConnection.getPoolKey(host, port, secure);
383: synchronized (connectionPool)
384: {
385: connection = (HTTPConnection) connectionPool.remove(key);
386: if (connection == null)
387: {
388: connection = new HTTPConnection(host, port, secure);
389: connection.setPool(connectionPool);
390: }
391: }
392: }
393: else
394: {
395: connection = new HTTPConnection(host, port, secure);
396: }
397: return connection;
398: }
399:
400: public void disconnect()
401: {
402: if (connection != null)
403: {
404: try
405: {
406: connection.close();
407: }
408: catch (IOException e)
409: {
410: }
411: }
412: }
413:
414: public boolean usingProxy()
415: {
416: return (proxyHostname != null);
417: }
418:
419:
426: public void setRequestMethod(String method)
427: throws ProtocolException
428: {
429: if (connected)
430: {
431: throw new ProtocolException("Already connected");
432: }
433:
434: method = method.toUpperCase();
435: int len = method.length();
436: if (len == 0)
437: {
438: throw new ProtocolException("Empty method name");
439: }
440: for (int i = 0; i < len; i++)
441: {
442: char c = method.charAt(i);
443: if (c < 0x41 || c > 0x5a)
444: {
445: throw new ProtocolException("Illegal character '" + c +
446: "' at index " + i);
447: }
448: }
449:
450: this.method = method;
451: requestMethodSetExplicitly = true;
452: }
453:
454: public String getRequestProperty(String key)
455: {
456: return requestHeaders.getValue(key);
457: }
458:
459: public Map getRequestProperties()
460: {
461: return requestHeaders;
462: }
463:
464: public void setRequestProperty(String key, String value)
465: {
466: requestHeaders.put(key, value);
467: }
468:
469: public void addRequestProperty(String key, String value)
470: {
471: String old = requestHeaders.getValue(key);
472: if (old == null)
473: {
474: requestHeaders.put(key, value);
475: }
476: else
477: {
478: requestHeaders.put(key, old + "," + value);
479: }
480: }
481:
482: public OutputStream getOutputStream()
483: throws IOException
484: {
485: if (connected)
486: {
487: throw new ProtocolException("Already connected");
488: }
489: if (!doOutput)
490: {
491: throw new ProtocolException("doOutput is false");
492: }
493: else if (!requestMethodSetExplicitly)
494: {
495:
500: method = "POST";
501: }
502: if (requestSink == null)
503: {
504: requestSink = new ByteArrayOutputStream();
505: }
506: return requestSink;
507: }
508:
509:
510:
511: public InputStream getInputStream()
512: throws IOException
513: {
514: if (!connected)
515: {
516: connect();
517: }
518: if (!doInput)
519: {
520: throw new ProtocolException("doInput is false");
521: }
522: return responseSink;
523: }
524:
525: public InputStream getErrorStream()
526: {
527: return errorSink;
528: }
529:
530: public Map getHeaderFields()
531: {
532: if (!connected)
533: {
534: try
535: {
536: connect();
537: }
538: catch (IOException e)
539: {
540: return null;
541: }
542: }
543: Headers headers = response.getHeaders();
544: LinkedHashMap ret = new LinkedHashMap();
545: ret.put(null, Collections.singletonList(getStatusLine(response)));
546: for (Iterator i = headers.entrySet().iterator(); i.hasNext(); )
547: {
548: Map.Entry entry = (Map.Entry) i.next();
549: String key = (String) entry.getKey();
550: String value = (String) entry.getValue();
551: ret.put(key, Collections.singletonList(value));
552: }
553: return Collections.unmodifiableMap(ret);
554: }
555:
556: String getStatusLine(Response response)
557: {
558: return "HTTP/" + response.getMajorVersion() +
559: "." + response.getMinorVersion() +
560: " " + response.getCode() +
561: " " + response.getMessage();
562: }
563:
564: public String getHeaderField(int index)
565: {
566: if (!connected)
567: {
568: try
569: {
570: connect();
571: }
572: catch (IOException e)
573: {
574: return null;
575: }
576: }
577: if (index == 0)
578: {
579: return getStatusLine(response);
580: }
581: Iterator i = response.getHeaders().entrySet().iterator();
582: Map.Entry entry;
583: int count = 1;
584: do
585: {
586: if (!i.hasNext())
587: {
588: return null;
589: }
590: entry = (Map.Entry) i.next();
591: count++;
592: }
593: while (count <= index);
594: return (String) entry.getValue();
595: }
596:
597: public String getHeaderFieldKey(int index)
598: {
599: if (!connected)
600: {
601: try
602: {
603: connect();
604: }
605: catch (IOException e)
606: {
607: return null;
608: }
609: }
610: if (index == 0)
611: {
612: return null;
613: }
614: Iterator i = response.getHeaders().entrySet().iterator();
615: Map.Entry entry;
616: int count = 1;
617: do
618: {
619: if (!i.hasNext())
620: {
621: return null;
622: }
623: entry = (Map.Entry) i.next();
624: count++;
625: }
626: while (count <= index);
627: return (String) entry.getKey();
628: }
629:
630: public String getHeaderField(String name)
631: {
632: if (!connected)
633: {
634: try
635: {
636: connect();
637: }
638: catch (IOException e)
639: {
640: return null;
641: }
642: }
643: return (String) response.getHeader(name);
644: }
645:
646: public long getHeaderFieldDate(String name, long def)
647: {
648: if (!connected)
649: {
650: try
651: {
652: connect();
653: }
654: catch (IOException e)
655: {
656: return def;
657: }
658: }
659: Date date = response.getDateHeader(name);
660: return (date == null) ? def : date.getTime();
661: }
662:
663: public String getContentType()
664: {
665: return getHeaderField("Content-Type");
666: }
667:
668: public int getResponseCode()
669: throws IOException
670: {
671: if (!connected)
672: {
673: connect();
674: }
675: return response.getCode();
676: }
677:
678: public String getResponseMessage()
679: throws IOException
680: {
681: if (!connected)
682: {
683: connect();
684: }
685: return response.getMessage();
686: }
687:
688:
689:
690: public String getCipherSuite()
691: {
692: if (!connected)
693: {
694: throw new IllegalStateException("not connected");
695: }
696: return handshakeEvent.getCipherSuite();
697: }
698:
699: public Certificate[] getLocalCertificates()
700: {
701: if (!connected)
702: {
703: throw new IllegalStateException("not connected");
704: }
705: return handshakeEvent.getLocalCertificates();
706: }
707:
708: public Certificate[] getServerCertificates()
709: throws SSLPeerUnverifiedException
710: {
711: if (!connected)
712: {
713: throw new IllegalStateException("not connected");
714: }
715: return handshakeEvent.getPeerCertificates();
716: }
717:
718:
719:
720: public void handshakeCompleted(HandshakeCompletedEvent event)
721: {
722: handshakeEvent = event;
723: }
724:
725: }