1:
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:
62: public class HTTPURLConnection
63: extends HttpURLConnection
64: {
65:
66:
69: private static final Map connectionPool = new LinkedHashMap();
70:
71:
74: private HTTPConnection connection;
75:
76: private String proxyHostname;
77: private int proxyPort;
78: private String agent;
79: private boolean keepAlive;
80: private int maxConnections;
81:
82: private Request request;
83: private Headers requestHeaders;
84: private ByteArrayOutputStream requestSink;
85: private boolean requestMethodSetExplicitly;
86:
87: private Response response;
88: private ByteArrayInputStream responseSink;
89:
90:
94: public HTTPURLConnection(URL url)
95: {
96: super(url);
97: requestHeaders = new Headers();
98: AccessController.doPrivileged(this.new GetHTTPPropertiesAction());
99: }
100:
101: class GetHTTPPropertiesAction
102: implements PrivilegedAction
103: {
104:
105: public Object run()
106: {
107: proxyHostname = System.getProperty("http.proxyHost");
108: if (proxyHostname != null && proxyHostname.length() > 0)
109: {
110: String port = System.getProperty("http.proxyPort");
111: if (port != null && port.length() > 0)
112: {
113: proxyPort = Integer.parseInt(port);
114: }
115: else
116: {
117: proxyHostname = null;
118: proxyPort = -1;
119: }
120: }
121: agent = System.getProperty("http.agent");
122: String ka = System.getProperty("http.keepAlive");
123: keepAlive = !(ka != null && "false".equals(ka));
124: String mc = System.getProperty("http.maxConnections");
125: maxConnections = (mc != null && mc.length() > 0) ?
126: Math.max(Integer.parseInt(mc), 1) : 5;
127: return null;
128: }
129:
130: }
131:
132: public void connect()
133: throws IOException
134: {
135: if (connected)
136: {
137: return;
138: }
139: String protocol = url.getProtocol();
140: boolean secure = "https".equals(protocol);
141: String host = url.getHost();
142: int port = url.getPort();
143: if (port < 0)
144: {
145: port = secure ? HTTPConnection.HTTPS_PORT :
146: HTTPConnection.HTTP_PORT;
147: }
148: String file = url.getFile();
149: String username = url.getUserInfo();
150: String password = null;
151: if (username != null)
152: {
153: int ci = username.indexOf(':');
154: if (ci != -1)
155: {
156: password = username.substring(ci + 1);
157: username = username.substring(0, ci);
158: }
159: }
160: final Credentials creds = (username == null) ? null :
161: new Credentials (username, password);
162:
163: boolean retry;
164: do
165: {
166: retry = false;
167: if (connection == null)
168: {
169: connection = getConnection(host, port, secure);
170: }
171: if (proxyHostname != null)
172: {
173: if (proxyPort < 0)
174: {
175: proxyPort = secure ? HTTPConnection.HTTPS_PORT :
176: HTTPConnection.HTTP_PORT;
177: }
178: connection.setProxy(proxyHostname, proxyPort);
179: }
180: request = connection.newRequest(method, file);
181: if (!keepAlive)
182: {
183: request.setHeader("Connection", "close");
184: }
185: if (agent != null)
186: {
187: request.setHeader("User-Agent", agent);
188: }
189: request.getHeaders().putAll(requestHeaders);
190: if (requestSink != null)
191: {
192: byte[] content = requestSink.toByteArray();
193: RequestBodyWriter writer = new ByteArrayRequestBodyWriter(content);
194: request.setRequestBodyWriter(writer);
195: }
196: ByteArrayResponseBodyReader reader = new ByteArrayResponseBodyReader();
197: request.setResponseBodyReader(reader);
198: if (creds != null)
199: {
200: request.setAuthenticator(new Authenticator() {
201: public Credentials getCredentials(String realm, int attempts)
202: {
203: return (attempts < 2) ? creds : null;
204: }
205: });
206: }
207: response = request.dispatch();
208: if (response.getCodeClass() == 3 && getInstanceFollowRedirects())
209: {
210:
211: String location = response.getHeader("Location");
212: String connectionUri = connection.getURI();
213: int start = connectionUri.length();
214: if (location.startsWith(connectionUri) &&
215: location.charAt(start) == '/')
216: {
217: file = location.substring(start);
218: retry = true;
219: }
220: else if (location.startsWith("http:"))
221: {
222: connection.close();
223: connection = null;
224: secure = false;
225: start = 7;
226: int end = location.indexOf('/', start);
227: host = location.substring(start, end);
228: int ci = host.lastIndexOf(':');
229: if (ci != -1)
230: {
231: port = Integer.parseInt(host.substring (ci + 1));
232: host = host.substring(0, ci);
233: }
234: else
235: {
236: port = HTTPConnection.HTTP_PORT;
237: }
238: file = location.substring(end);
239: retry = true;
240: }
241: else if (location.startsWith("https:"))
242: {
243: connection.close();
244: connection = null;
245: secure = true;
246: start = 8;
247: int end = location.indexOf('/', start);
248: host = location.substring(start, end);
249: int ci = host.lastIndexOf(':');
250: if (ci != -1)
251: {
252: port = Integer.parseInt(host.substring (ci + 1));
253: host = host.substring(0, ci);
254: }
255: else
256: {
257: port = HTTPConnection.HTTPS_PORT;
258: }
259: file = location.substring(end);
260: retry = true;
261: }
262:
263: }
264: else
265: {
266: responseSink = new ByteArrayInputStream(reader.toByteArray ());
267: }
268: }
269: while (retry);
270: connected = true;
271: }
272:
273:
276: HTTPConnection getConnection(String host, int port, boolean secure)
277: throws IOException
278: {
279: HTTPConnection connection;
280: if (keepAlive)
281: {
282: StringBuffer buf = new StringBuffer(secure ? "https://" : "http://");
283: buf.append(host);
284: buf.append(':');
285: buf.append(port);
286: String key = buf.toString();
287: synchronized (connectionPool)
288: {
289: connection = (HTTPConnection) connectionPool.get(key);
290: if (connection == null)
291: {
292: connection = new HTTPConnection(host, port, secure);
293:
294: if (connectionPool.size() == maxConnections)
295: {
296:
297: Object lru = connectionPool.keySet().iterator().next();
298: connectionPool.remove(lru);
299: }
300: connectionPool.put(key, connection);
301: }
302: }
303: }
304: else
305: {
306: connection = new HTTPConnection(host, port, secure);
307: }
308: return connection;
309: }
310:
311: public void disconnect()
312: {
313: if (connection != null)
314: {
315: try
316: {
317: connection.close();
318: }
319: catch (IOException e)
320: {
321: }
322: }
323: }
324:
325: public boolean usingProxy()
326: {
327: return (proxyHostname != null);
328: }
329:
330:
337: public void setRequestMethod(String method)
338: throws ProtocolException
339: {
340: if (connected)
341: {
342: throw new ProtocolException("Already connected");
343: }
344:
345: method = method.toUpperCase();
346: int len = method.length();
347: if (len == 0)
348: {
349: throw new ProtocolException("Empty method name");
350: }
351: for (int i = 0; i < len; i++)
352: {
353: char c = method.charAt(i);
354: if (c < 0x41 || c > 0x5a)
355: {
356: throw new ProtocolException("Illegal character '" + c +
357: "' at index " + i);
358: }
359: }
360:
361: this.method = method;
362: requestMethodSetExplicitly = true;
363: }
364:
365: public String getRequestProperty(String key)
366: {
367: return requestHeaders.getValue(key);
368: }
369:
370: public Map getRequestProperties()
371: {
372: return requestHeaders;
373: }
374:
375: public void setRequestProperty(String key, String value)
376: {
377: requestHeaders.put(key, value);
378: }
379:
380: public void addRequestProperty(String key, String value)
381: {
382: String old = requestHeaders.getValue(key);
383: if (old == null)
384: {
385: requestHeaders.put(key, value);
386: }
387: else
388: {
389: requestHeaders.put(key, old + "," + value);
390: }
391: }
392:
393: public OutputStream getOutputStream()
394: throws IOException
395: {
396: if (connected)
397: {
398: throw new ProtocolException("Already connected");
399: }
400: if (!doOutput)
401: {
402: throw new ProtocolException("doOutput is false");
403: }
404: else if (!requestMethodSetExplicitly)
405: {
406:
411: method = "POST";
412: }
413: if (requestSink == null)
414: {
415: requestSink = new ByteArrayOutputStream();
416: }
417: return requestSink;
418: }
419:
420:
421:
422: public InputStream getInputStream()
423: throws IOException
424: {
425: if (!connected)
426: {
427: connect();
428: }
429: if (!doInput)
430: {
431: throw new ProtocolException("doInput is false");
432: }
433: return responseSink;
434: }
435:
436: public Map getHeaderFields()
437: {
438: if (!connected)
439: {
440: try
441: {
442: connect();
443: }
444: catch (IOException e)
445: {
446: return null;
447: }
448: }
449: Map headers = response.getHeaders();
450: Map ret = new LinkedHashMap();
451: ret.put("", Collections.singletonList(getStatusLine(response)));
452: for (Iterator i = headers.entrySet().iterator(); i.hasNext(); )
453: {
454: Map.Entry entry = (Map.Entry) i.next();
455: String key = (String) entry.getKey();
456: String value = (String) entry.getValue();
457: ret.put(key, Collections.singletonList(value));
458: }
459: return ret;
460: }
461:
462: String getStatusLine(Response response)
463: {
464: return "HTTP/" + response.getMajorVersion() +
465: "." + response.getMinorVersion() +
466: " " + response.getCode() +
467: " " + response.getMessage();
468: }
469:
470: public String getHeaderField(int index)
471: {
472: if (!connected)
473: {
474: try
475: {
476: connect();
477: }
478: catch (IOException e)
479: {
480: return null;
481: }
482: }
483: if (index == 0)
484: {
485: return getStatusLine(response);
486: }
487: Iterator i = response.getHeaders().entrySet().iterator();
488: Map.Entry entry;
489: int count = 1;
490: do
491: {
492: if (!i.hasNext())
493: {
494: return null;
495: }
496: entry = (Map.Entry) i.next();
497: count++;
498: }
499: while (count <= index);
500: return (String) entry.getValue();
501: }
502:
503: public String getHeaderFieldKey(int index)
504: {
505: if (!connected)
506: {
507: try
508: {
509: connect();
510: }
511: catch (IOException e)
512: {
513: return null;
514: }
515: }
516: if (index == 0)
517: {
518: return null;
519: }
520: Iterator i = response.getHeaders().entrySet().iterator();
521: Map.Entry entry;
522: int count = 1;
523: do
524: {
525: entry = (Map.Entry) i.next();
526: count++;
527: }
528: while (count <= index);
529: return (String) entry.getKey();
530: }
531:
532: public String getHeaderField(String name)
533: {
534: if (!connected)
535: {
536: try
537: {
538: connect();
539: }
540: catch (IOException e)
541: {
542: return null;
543: }
544: }
545: return (String) response.getHeader(name);
546: }
547:
548: public long getHeaderFieldDate(String name, long def)
549: {
550: if (!connected)
551: {
552: try
553: {
554: connect();
555: }
556: catch (IOException e)
557: {
558: return def;
559: }
560: }
561: Date date = response.getDateHeader(name);
562: return (date == null) ? def : date.getTime();
563: }
564:
565: public String getContentType()
566: {
567: return getHeaderField("Content-Type");
568: }
569:
570: public int getResponseCode()
571: throws IOException
572: {
573: if (!connected)
574: {
575: connect();
576: }
577: return response.getCode();
578: }
579:
580: public String getResponseMessage()
581: throws IOException
582: {
583: if (!connected)
584: {
585: connect();
586: }
587: return response.getMessage();
588: }
589:
590: }