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