001: /*
002: * @(#)HttpURLConnection.java 1.35 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package java.net;
029:
030: import java.io.InputStream;
031: import java.io.IOException;
032: import java.security.Permission;
033: import java.text.DateFormat;
034: import java.text.SimpleDateFormat;
035:
036: /**
037: * A URLConnection with support for HTTP-specific features. See
038: * <A HREF="http://www.w3.org/pub/WWW/Protocols/"> the spec </A> for
039: * details.
040: * <p>
041: *
042: * Each HttpURLConnection instance is used to make a single request
043: * but the underlying network connection to the HTTP server may be
044: * transparently shared by other instances. Calling the close() methods
045: * on the InputStream or OutputStream of an HttpURLConnection
046: * after a request may free network resources associated with this
047: * instance but has no effect on any shared persistent connection.
048: * Calling the disconnect() method may close the underlying socket
049: * if a persistent connection is otherwise idle at that time.
050: *
051: * @see java.net.HttpURLConnection#disconnect()
052: * @since JDK1.1
053: */
054: abstract public class HttpURLConnection extends URLConnection {
055: /* instance variables */
056:
057: /**
058: * The HTTP method (GET,POST,PUT,etc.).
059: */
060: protected String method = "GET";
061:
062: /**
063: * Returns the key for the <code>n</code><sup>th</sup> header field.
064: * Some implementations may treat the <code>0</code><sup>th</sup>
065: * header field as special, i.e. as the status line returned by the HTTP
066: * server. In this case, {@link #getHeaderField(int) getHeaderField(0)} returns the status
067: * line, but <code>getHeaderFieldKey(0)</code> returns null.
068: *
069: * @param n an index, where n >=0.
070: * @return the key for the <code>n</code><sup>th</sup> header field,
071: * or <code>null</code> if the key does not exist.
072: */
073: public String getHeaderFieldKey(int n) {
074: return null;
075: }
076:
077: /**
078: * Returns the value for the <code>n</code><sup>th</sup> header field.
079: * Some implementations may treat the <code>0</code><sup>th</sup>
080: * header field as special, i.e. as the status line returned by the HTTP
081: * server.
082: * <p>
083: * This method can be used in conjunction with the
084: * {@link #getHeaderFieldKey getHeaderFieldKey} method to iterate through all
085: * the headers in the message.
086: *
087: * @param n an index, where n>=0.
088: * @return the value of the <code>n</code><sup>th</sup> header field,
089: * or <code>null</code> if the value does not exist.
090: * @see java.net.HttpURLConnection#getHeaderFieldKey(int)
091: */
092: public String getHeaderField(int n) {
093: return null;
094: }
095:
096: /**
097: * An <code>int</code> representing the three digit HTTP Status-Code.
098: * <ul>
099: * <li> 1xx: Informational
100: * <li> 2xx: Success
101: * <li> 3xx: Redirection
102: * <li> 4xx: Client Error
103: * <li> 5xx: Server Error
104: * </ul>
105: */
106: protected int responseCode = -1;
107:
108: /**
109: * The HTTP response message.
110: */
111: protected String responseMessage = null;
112:
113: /* static variables */
114:
115: /* do we automatically follow redirects? The default is true. */
116: private static boolean followRedirects = true;
117:
118: /**
119: * If <code>true</code>, the protocol will automatically follow redirects.
120: * If <code>false</code>, the protocol will not automatically follow
121: * redirects.
122: * <p>
123: * This field is set by the <code>setInstanceFollowRedirects</code>
124: * method. Its value is returned by the <code>getInstanceFollowRedirects</code>
125: * method.
126: * <p>
127: * Its default value is based on the value of the static followRedirects
128: * at HttpURLConnection construction time.
129: *
130: * @see java.net.HttpURLConnection#setInstanceFollowRedirects(boolean)
131: * @see java.net.HttpURLConnection#getInstanceFollowRedirects()
132: * @see java.net.HttpURLConnection#setFollowRedirects(boolean)
133: */
134: protected boolean instanceFollowRedirects = followRedirects;
135:
136: /* valid HTTP methods */
137: private static final String[] methods = { "GET", "POST", "HEAD",
138: "OPTIONS", "PUT", "DELETE", "TRACE" };
139:
140: /**
141: * Constructor for the HttpURLConnection.
142: * @param u the URL
143: */
144: protected HttpURLConnection(URL u) {
145: super (u);
146: }
147:
148: /**
149: * Sets whether HTTP redirects (requests with response code 3xx) should
150: * be automatically followed by this class. True by default. Applets
151: * cannot change this variable.
152: * <p>
153: * If there is a security manager, this method first calls
154: * the security manager's <code>checkSetFactory</code> method
155: * to ensure the operation is allowed.
156: * This could result in a SecurityException.
157: *
158: * @param set a <code>boolean</code> indicating whether or not
159: * to follow HTTP redirects.
160: * @exception SecurityException if a security manager exists and its
161: * <code>checkSetFactory</code> method doesn't
162: * allow the operation.
163: * @see SecurityManager#checkSetFactory
164: * @see #getFollowRedirects()
165: */
166: public static void setFollowRedirects(boolean set) {
167: SecurityManager sec = System.getSecurityManager();
168: if (sec != null) {
169: // seems to be the best check here...
170: sec.checkSetFactory();
171: }
172: followRedirects = set;
173: }
174:
175: /**
176: * Returns a <code>boolean</code> indicating
177: * whether or not HTTP redirects (3xx) should
178: * be automatically followed.
179: *
180: * @return <code>true</code> if HTTP redirects should
181: * be automatically followed, <tt>false</tt> if not.
182: * @see #setFollowRedirects(boolean)
183: */
184: public static boolean getFollowRedirects() {
185: return followRedirects;
186: }
187:
188: /**
189: * Sets whether HTTP redirects (requests with response code 3xx) should
190: * be automatically followed by this <code>HttpURLConnection</code>
191: * instance.
192: * <p>
193: * The default value comes from followRedirects, which defaults to
194: * true.
195: *
196: * @param followRedirects a <code>boolean</code> indicating
197: * whether or not to follow HTTP redirects.
198: *
199: * @see java.net.HttpURLConnection#instanceFollowRedirects
200: * @see #getInstanceFollowRedirects
201: */
202: public void setInstanceFollowRedirects(boolean followRedirects) {
203: instanceFollowRedirects = followRedirects;
204: }
205:
206: /**
207: * Returns the value of this <code>HttpURLConnection</code>'s
208: * <code>instanceFollowRedirects</code> field.
209: *
210: * @return the value of this <code>HttpURLConnection</code>'s
211: * <code>instanceFollowRedirects</code> field.
212: * @see java.net.HttpURLConnection#instanceFollowRedirects
213: * @see #setInstanceFollowRedirects(boolean)
214: */
215: public boolean getInstanceFollowRedirects() {
216: return instanceFollowRedirects;
217: }
218:
219: /**
220: * Set the method for the URL request, one of:
221: * <UL>
222: * <LI>GET
223: * <LI>POST
224: * <LI>HEAD
225: * <LI>OPTIONS
226: * <LI>PUT
227: * <LI>DELETE
228: * <LI>TRACE
229: * </UL> are legal, subject to protocol restrictions. The default
230: * method is GET.
231: *
232: * @param method the HTTP method
233: * @exception ProtocolException if the method cannot be reset or if
234: * the requested method isn't valid for HTTP.
235: * @see #getRequestMethod()
236: */
237: public void setRequestMethod(String method)
238: throws ProtocolException {
239: if (connected) {
240: throw new ProtocolException(
241: "Can't reset method: already connected");
242: }
243: // This restriction will prevent people from using this class to
244: // experiment w/ new HTTP methods using java. But it should
245: // be placed for security - the request String could be
246: // arbitrarily long.
247:
248: for (int i = 0; i < methods.length; i++) {
249: if (methods[i].equals(method)) {
250: this .method = method;
251: return;
252: }
253: }
254: throw new ProtocolException("Invalid HTTP method: " + method);
255: }
256:
257: /**
258: * Get the request method.
259: * @return the HTTP request method
260: * @see #setRequestMethod(java.lang.String)
261: */
262: public String getRequestMethod() {
263: return method;
264: }
265:
266: /**
267: * Gets the status code from an HTTP response message.
268: * For example, in the case of the following status lines:
269: * <PRE>
270: * HTTP/1.0 200 OK
271: * HTTP/1.0 401 Unauthorized
272: * </PRE>
273: * It will return 200 and 401 respectively.
274: * Returns -1 if no code can be discerned
275: * from the response (i.e., the response is not valid HTTP).
276: * @throws IOException if an error occurred connecting to the server.
277: * @return the HTTP Status-Code, or -1
278: */
279: public int getResponseCode() throws IOException {
280: /*
281: * We're got the response code already
282: */
283: if (responseCode != -1) {
284: return responseCode;
285: }
286:
287: /*
288: * Ensure that we have connected to the server. Record
289: * exception as we need to re-throw it if there isn't
290: * a status line.
291: */
292: Exception exc = null;
293: try {
294: getInputStream();
295: } catch (Exception e) {
296: exc = e;
297: }
298:
299: /*
300: * If we can't a status-line then re-throw any exception
301: * that getInputStream threw.
302: */
303: String statusLine = getHeaderField(0);
304: if (statusLine == null) {
305: if (exc != null) {
306: if (exc instanceof RuntimeException)
307: throw (RuntimeException) exc;
308: else
309: throw (IOException) exc;
310: }
311: return -1;
312: }
313:
314: /*
315: * Examine the status-line - should be formatted as per
316: * section 6.1 of RFC 2616 :-
317: *
318: * Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase
319: *
320: * If status line can't be parsed return -1.
321: */
322: if (statusLine.startsWith("HTTP/1.")) {
323: int codePos = statusLine.indexOf(' ');
324: if (codePos > 0) {
325:
326: int phrasePos = statusLine.indexOf(' ', codePos + 1);
327: if (phrasePos > 0 && phrasePos < statusLine.length()) {
328: responseMessage = statusLine
329: .substring(phrasePos + 1);
330: }
331:
332: // deviation from RFC 2616 - don't reject status line
333: // if SP Reason-Phrase is not included.
334: if (phrasePos < 0)
335: phrasePos = statusLine.length();
336:
337: try {
338: responseCode = Integer.parseInt(statusLine
339: .substring(codePos + 1, phrasePos));
340: return responseCode;
341: } catch (NumberFormatException e) {
342: }
343: }
344: }
345: return -1;
346: }
347:
348: /**
349: * Gets the HTTP response message, if any, returned along with the
350: * response code from a server. From responses like:
351: * <PRE>
352: * HTTP/1.0 200 OK
353: * HTTP/1.0 404 Not Found
354: * </PRE>
355: * Extracts the Strings "OK" and "Not Found" respectively.
356: * Returns null if none could be discerned from the responses
357: * (the result was not valid HTTP).
358: * @throws IOException if an error occurred connecting to the server.
359: * @return the HTTP response message, or <code>null</code>
360: */
361: public String getResponseMessage() throws IOException {
362: getResponseCode();
363: return responseMessage;
364: }
365:
366: public long getHeaderFieldDate(String name, long Default) {
367: String dateString = getHeaderField(name);
368: try {
369: dateString.trim();
370: if (dateString.indexOf("GMT") == -1) {
371: dateString = dateString + " GMT";
372: }
373: DateFormat df = new SimpleDateFormat(
374: "EEE, d MMM yyyy H:mm:ss zzz");
375: return df.parse(dateString).getTime();
376: } catch (ThreadDeath td) {
377: throw td;
378: } catch (Throwable t) {
379: }
380: return Default;
381: }
382:
383: /**
384: * Indicates that other requests to the server
385: * are unlikely in the near future. Calling disconnect()
386: * should not imply that this HttpURLConnection
387: * instance can be reused for other requests.
388: */
389: public abstract void disconnect();
390:
391: /**
392: * Indicates if the connection is going through a proxy.
393: * @return a boolean indicating if the connection is
394: * using a proxy.
395: */
396: public abstract boolean usingProxy();
397:
398: public Permission getPermission() throws IOException {
399: int port = url.getPort();
400: port = port < 0 ? 80 : port;
401: String host = url.getHost() + ":" + port;
402: Permission permission = new SocketPermission(host, "connect");
403: return permission;
404: }
405:
406: /**
407: * Returns the error stream if the connection failed
408: * but the server sent useful data nonetheless. The
409: * typical example is when an HTTP server responds
410: * with a 404, which will cause a FileNotFoundException
411: * to be thrown in connect, but the server sent an HTML
412: * help page with suggestions as to what to do.
413: *
414: * <p>This method will not cause a connection to be initiated. If
415: * the connection was not connected, or if the server did not have
416: * an error while connecting or if the server had an error but
417: * no error data was sent, this method will return null. This is
418: * the default.
419: *
420: * @return an error stream if any, null if there have been no
421: * errors, the connection is not connected or the server sent no
422: * useful data.
423: */
424: public InputStream getErrorStream() {
425: return null;
426: }
427:
428: /**
429: * The response codes for HTTP, as of version 1.1.
430: */
431:
432: /* 2XX: generally "OK" */
433:
434: /**
435: * HTTP Status-Code 200: OK.
436: */
437: public static final int HTTP_OK = 200;
438:
439: /**
440: * HTTP Status-Code 201: Created.
441: */
442: public static final int HTTP_CREATED = 201;
443:
444: /**
445: * HTTP Status-Code 202: Accepted.
446: */
447: public static final int HTTP_ACCEPTED = 202;
448:
449: /**
450: * HTTP Status-Code 203: Non-Authoritative Information.
451: */
452: public static final int HTTP_NOT_AUTHORITATIVE = 203;
453:
454: /**
455: * HTTP Status-Code 204: No Content.
456: */
457: public static final int HTTP_NO_CONTENT = 204;
458:
459: /**
460: * HTTP Status-Code 205: Reset Content.
461: */
462: public static final int HTTP_RESET = 205;
463:
464: /**
465: * HTTP Status-Code 206: Partial Content.
466: */
467: public static final int HTTP_PARTIAL = 206;
468:
469: /* 3XX: relocation/redirect */
470:
471: /**
472: * HTTP Status-Code 300: Multiple Choices.
473: */
474: public static final int HTTP_MULT_CHOICE = 300;
475:
476: /**
477: * HTTP Status-Code 301: Moved Permanently.
478: */
479: public static final int HTTP_MOVED_PERM = 301;
480:
481: /**
482: * HTTP Status-Code 302: Temporary Redirect.
483: */
484: public static final int HTTP_MOVED_TEMP = 302;
485:
486: /**
487: * HTTP Status-Code 303: See Other.
488: */
489: public static final int HTTP_SEE_OTHER = 303;
490:
491: /**
492: * HTTP Status-Code 304: Not Modified.
493: */
494: public static final int HTTP_NOT_MODIFIED = 304;
495:
496: /**
497: * HTTP Status-Code 305: Use Proxy.
498: */
499: public static final int HTTP_USE_PROXY = 305;
500:
501: /* 4XX: client error */
502:
503: /**
504: * HTTP Status-Code 400: Bad Request.
505: */
506: public static final int HTTP_BAD_REQUEST = 400;
507:
508: /**
509: * HTTP Status-Code 401: Unauthorized.
510: */
511: public static final int HTTP_UNAUTHORIZED = 401;
512:
513: /**
514: * HTTP Status-Code 402: Payment Required.
515: */
516: public static final int HTTP_PAYMENT_REQUIRED = 402;
517:
518: /**
519: * HTTP Status-Code 403: Forbidden.
520: */
521: public static final int HTTP_FORBIDDEN = 403;
522:
523: /**
524: * HTTP Status-Code 404: Not Found.
525: */
526: public static final int HTTP_NOT_FOUND = 404;
527:
528: /**
529: * HTTP Status-Code 405: Method Not Allowed.
530: */
531: public static final int HTTP_BAD_METHOD = 405;
532:
533: /**
534: * HTTP Status-Code 406: Not Acceptable.
535: */
536: public static final int HTTP_NOT_ACCEPTABLE = 406;
537:
538: /**
539: * HTTP Status-Code 407: Proxy Authentication Required.
540: */
541: public static final int HTTP_PROXY_AUTH = 407;
542:
543: /**
544: * HTTP Status-Code 408: Request Time-Out.
545: */
546: public static final int HTTP_CLIENT_TIMEOUT = 408;
547:
548: /**
549: * HTTP Status-Code 409: Conflict.
550: */
551: public static final int HTTP_CONFLICT = 409;
552:
553: /**
554: * HTTP Status-Code 410: Gone.
555: */
556: public static final int HTTP_GONE = 410;
557:
558: /**
559: * HTTP Status-Code 411: Length Required.
560: */
561: public static final int HTTP_LENGTH_REQUIRED = 411;
562:
563: /**
564: * HTTP Status-Code 412: Precondition Failed.
565: */
566: public static final int HTTP_PRECON_FAILED = 412;
567:
568: /**
569: * HTTP Status-Code 413: Request Entity Too Large.
570: */
571: public static final int HTTP_ENTITY_TOO_LARGE = 413;
572:
573: /**
574: * HTTP Status-Code 414: Request-URI Too Large.
575: */
576: public static final int HTTP_REQ_TOO_LONG = 414;
577:
578: /**
579: * HTTP Status-Code 415: Unsupported Media Type.
580: */
581: public static final int HTTP_UNSUPPORTED_TYPE = 415;
582:
583: /* 5XX: server error */
584:
585: /**
586: * deprecated it is misplaced and shouldn't have existed.
587: *
588: public static final int HTTP_SERVER_ERROR = 500;
589: */
590:
591: /**
592: * HTTP Status-Code 500: Internal Server Error.
593: */
594: public static final int HTTP_INTERNAL_ERROR = 500;
595:
596: /**
597: * HTTP Status-Code 501: Not Implemented.
598: */
599: public static final int HTTP_NOT_IMPLEMENTED = 501;
600:
601: /**
602: * HTTP Status-Code 502: Bad Gateway.
603: */
604: public static final int HTTP_BAD_GATEWAY = 502;
605:
606: /**
607: * HTTP Status-Code 503: Service Unavailable.
608: */
609: public static final int HTTP_UNAVAILABLE = 503;
610:
611: /**
612: * HTTP Status-Code 504: Gateway Timeout.
613: */
614: public static final int HTTP_GATEWAY_TIMEOUT = 504;
615:
616: /**
617: * HTTP Status-Code 505: HTTP Version Not Supported.
618: */
619: public static final int HTTP_VERSION = 505;
620:
621: }
|