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