1:
37:
38:
39: package ;
40:
41: import ;
42: import ;
43: import ;
44:
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51: import ;
52: import ;
53: import ;
54: import ;
55: import ;
56: import ;
57: import ;
58: import ;
59:
60: import ;
61: import ;
62: import ;
63: import ;
64: import ;
65:
66:
71: public class HTTPConnection
72: {
73:
74:
77: public static final int HTTP_PORT = 80;
78:
79:
82: public static final int HTTPS_PORT = 443;
83:
84: private static final String userAgent = SystemProperties.getProperty("http.agent");
85:
86:
89: protected final String hostname;
90:
91:
94: protected final int port;
95:
96:
99: protected final boolean secure;
100:
101:
104: protected final int connectionTimeout;
105:
106:
109: protected final int timeout;
110:
111:
114: protected String proxyHostname;
115:
116:
119: protected int proxyPort;
120:
121:
124: protected int majorVersion;
125:
126:
129: protected int minorVersion;
130:
131: private final List handshakeCompletedListeners;
132:
133:
136: protected Socket socket;
137:
138:
141: private SSLSocketFactory sslSocketFactory;
142:
143:
146: protected InputStream in;
147:
148:
151: protected OutputStream out;
152:
153:
156: private Map nonceCounts;
157:
158:
161: protected CookieManager cookieManager;
162:
163:
164:
167: private LinkedHashMap pool;
168:
169:
173: public HTTPConnection(String hostname)
174: {
175: this(hostname, HTTP_PORT, false, 0, 0);
176: }
177:
178:
183: public HTTPConnection(String hostname, boolean secure)
184: {
185: this(hostname, secure ? HTTPS_PORT : HTTP_PORT, secure, 0, 0);
186: }
187:
188:
195: public HTTPConnection(String hostname, boolean secure,
196: int connectionTimeout, int timeout)
197: {
198: this(hostname, secure ? HTTPS_PORT : HTTP_PORT, secure,
199: connectionTimeout, timeout);
200: }
201:
202:
207: public HTTPConnection(String hostname, int port)
208: {
209: this(hostname, port, false, 0, 0);
210: }
211:
212:
218: public HTTPConnection(String hostname, int port, boolean secure)
219: {
220: this(hostname, port, secure, 0, 0);
221: }
222:
223:
231: public HTTPConnection(String hostname, int port, boolean secure,
232: int connectionTimeout, int timeout)
233: {
234: this.hostname = hostname;
235: this.port = port;
236: this.secure = secure;
237: this.connectionTimeout = connectionTimeout;
238: this.timeout = timeout;
239: majorVersion = minorVersion = 1;
240: handshakeCompletedListeners = new ArrayList(2);
241: }
242:
243:
246: public String getHostName()
247: {
248: return hostname;
249: }
250:
251:
254: public int getPort()
255: {
256: return port;
257: }
258:
259:
262: public boolean isSecure()
263: {
264: return secure;
265: }
266:
267:
271: public String getVersion()
272: {
273: return "HTTP/" + majorVersion + '.' + minorVersion;
274: }
275:
276:
281: public void setVersion(int majorVersion, int minorVersion)
282: {
283: if (majorVersion != 1)
284: {
285: throw new IllegalArgumentException("major version not supported: " +
286: majorVersion);
287: }
288: if (minorVersion < 0 || minorVersion > 1)
289: {
290: throw new IllegalArgumentException("minor version not supported: " +
291: minorVersion);
292: }
293: this.majorVersion = majorVersion;
294: this.minorVersion = minorVersion;
295: }
296:
297:
302: public void setProxy(String hostname, int port)
303: {
304: proxyHostname = hostname;
305: proxyPort = port;
306: }
307:
308:
311: public boolean isUsingProxy()
312: {
313: return (proxyHostname != null && proxyPort > 0);
314: }
315:
316:
320: public void setCookieManager(CookieManager cookieManager)
321: {
322: this.cookieManager = cookieManager;
323: }
324:
325:
328: public CookieManager getCookieManager()
329: {
330: return cookieManager;
331: }
332:
333:
336: int useCount;
337:
338:
347: static Object getPoolKey(String h, int p, boolean sec)
348: {
349: StringBuilder buf = new StringBuilder(sec ? "https://" : "http://");
350: buf.append(h);
351: buf.append(':');
352: buf.append(p);
353: return buf.toString();
354: }
355:
356:
363: void setPool(LinkedHashMap p)
364: {
365: pool = p;
366: }
367:
368:
373: void release()
374: {
375: if (pool != null)
376: {
377: synchronized (pool)
378: {
379: useCount++;
380: Object key = HTTPConnection.getPoolKey(hostname, port, secure);
381: pool.put(key, this);
382: while (pool.size() >= HTTPURLConnection.maxConnections)
383: {
384:
385: Object lru = pool.keySet().iterator().next();
386: HTTPConnection c = (HTTPConnection)pool.remove(lru);
387: try
388: {
389: c.closeConnection();
390: }
391: catch (IOException ioe)
392: {
393:
394: }
395: }
396: }
397: }
398: }
399:
400:
406: public Request newRequest(String method, String path)
407: {
408: if (method == null || method.length() == 0)
409: {
410: throw new IllegalArgumentException("method must have non-zero length");
411: }
412: if (path == null || path.length() == 0)
413: {
414: path = "/";
415: }
416: Request ret = new Request(this, method, path);
417: if ((secure && port != HTTPS_PORT) ||
418: (!secure && port != HTTP_PORT))
419: {
420: ret.setHeader("Host", hostname + ":" + port);
421: }
422: else
423: {
424: ret.setHeader("Host", hostname);
425: }
426: ret.setHeader("User-Agent", userAgent);
427: ret.setHeader("Connection", "keep-alive");
428: ret.setHeader("Accept-Encoding",
429: "chunked;q=1.0, gzip;q=0.9, deflate;q=0.8, " +
430: "identity;q=0.6, *;q=0");
431: if (cookieManager != null)
432: {
433: Cookie[] cookies = cookieManager.getCookies(hostname, secure, path);
434: if (cookies != null && cookies.length > 0)
435: {
436: StringBuilder buf = new StringBuilder();
437: buf.append("$Version=1");
438: for (int i = 0; i < cookies.length; i++)
439: {
440: buf.append(',');
441: buf.append(' ');
442: buf.append(cookies[i].toString());
443: }
444: ret.setHeader("Cookie", buf.toString());
445: }
446: }
447: return ret;
448: }
449:
450:
453: public void close()
454: throws IOException
455: {
456: closeConnection();
457: }
458:
459:
463: protected synchronized Socket getSocket()
464: throws IOException
465: {
466: if (socket == null)
467: {
468: String connectHostname = hostname;
469: int connectPort = port;
470: if (isUsingProxy())
471: {
472: connectHostname = proxyHostname;
473: connectPort = proxyPort;
474: }
475: socket = new Socket();
476: InetSocketAddress address =
477: new InetSocketAddress(connectHostname, connectPort);
478: if (connectionTimeout > 0)
479: {
480: socket.connect(address, connectionTimeout);
481: }
482: else
483: {
484: socket.connect(address);
485: }
486: if (timeout > 0)
487: {
488: socket.setSoTimeout(timeout);
489: }
490: if (secure)
491: {
492: try
493: {
494: SSLSocketFactory factory = getSSLSocketFactory();
495: SSLSocket ss =
496: (SSLSocket) factory.createSocket(socket, connectHostname,
497: connectPort, true);
498: String[] protocols = { "TLSv1", "SSLv3" };
499: ss.setEnabledProtocols(protocols);
500: ss.setUseClientMode(true);
501: synchronized (handshakeCompletedListeners)
502: {
503: if (!handshakeCompletedListeners.isEmpty())
504: {
505: for (Iterator i =
506: handshakeCompletedListeners.iterator();
507: i.hasNext(); )
508: {
509: HandshakeCompletedListener l =
510: (HandshakeCompletedListener) i.next();
511: ss.addHandshakeCompletedListener(l);
512: }
513: }
514: }
515: ss.startHandshake();
516: socket = ss;
517: }
518: catch (GeneralSecurityException e)
519: {
520: throw new IOException(e.getMessage());
521: }
522: }
523: in = socket.getInputStream();
524: in = new BufferedInputStream(in);
525: out = socket.getOutputStream();
526: out = new BufferedOutputStream(out);
527: }
528: return socket;
529: }
530:
531: SSLSocketFactory getSSLSocketFactory()
532: throws GeneralSecurityException
533: {
534: if (sslSocketFactory == null)
535: {
536: TrustManager tm = new EmptyX509TrustManager();
537: SSLContext context = SSLContext.getInstance("SSL");
538: TrustManager[] trust = new TrustManager[] { tm };
539: context.init(null, trust, null);
540: sslSocketFactory = context.getSocketFactory();
541: }
542: return sslSocketFactory;
543: }
544:
545: void setSSLSocketFactory(SSLSocketFactory factory)
546: {
547: sslSocketFactory = factory;
548: }
549:
550: protected synchronized InputStream getInputStream()
551: throws IOException
552: {
553: if (socket == null)
554: {
555: getSocket();
556: }
557: return in;
558: }
559:
560: protected synchronized OutputStream getOutputStream()
561: throws IOException
562: {
563: if (socket == null)
564: {
565: getSocket();
566: }
567: return out;
568: }
569:
570:
573: protected synchronized void closeConnection()
574: throws IOException
575: {
576: if (socket != null)
577: {
578: try
579: {
580: socket.close();
581: }
582: finally
583: {
584: socket = null;
585: }
586: }
587: }
588:
589:
593: protected String getURI()
594: {
595: StringBuilder buf = new StringBuilder();
596: buf.append(secure ? "https://" : "http://");
597: buf.append(hostname);
598: if (secure)
599: {
600: if (port != HTTPConnection.HTTPS_PORT)
601: {
602: buf.append(':');
603: buf.append(port);
604: }
605: }
606: else
607: {
608: if (port != HTTPConnection.HTTP_PORT)
609: {
610: buf.append(':');
611: buf.append(port);
612: }
613: }
614: return buf.toString();
615: }
616:
617:
621: int getNonceCount(String nonce)
622: {
623: if (nonceCounts == null)
624: {
625: return 0;
626: }
627: return((Integer) nonceCounts.get(nonce)).intValue();
628: }
629:
630:
633: void incrementNonce(String nonce)
634: {
635: int current = getNonceCount(nonce);
636: if (nonceCounts == null)
637: {
638: nonceCounts = new HashMap();
639: }
640: nonceCounts.put(nonce, new Integer(current + 1));
641: }
642:
643:
644:
645: void addHandshakeCompletedListener(HandshakeCompletedListener l)
646: {
647: synchronized (handshakeCompletedListeners)
648: {
649: handshakeCompletedListeners.add(l);
650: }
651: }
652: void removeHandshakeCompletedListener(HandshakeCompletedListener l)
653: {
654: synchronized (handshakeCompletedListeners)
655: {
656: handshakeCompletedListeners.remove(l);
657: }
658: }
659:
660: }