KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > net > HttpURLConnection


1 /*
2  * @(#)HttpURLConnection.java 1.42 04/06/07
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.net;
9
10 import java.io.InputStream JavaDoc;
11 import java.io.IOException JavaDoc;
12 import java.security.Permission JavaDoc;
13 import java.util.Date JavaDoc;
14
15 /**
16  * A URLConnection with support for HTTP-specific features. See
17  * <A HREF="http://www.w3.org/pub/WWW/Protocols/"> the spec </A> for
18  * details.
19  * <p>
20  *
21  * Each HttpURLConnection instance is used to make a single request
22  * but the underlying network connection to the HTTP server may be
23  * transparently shared by other instances. Calling the close() methods
24  * on the InputStream or OutputStream of an HttpURLConnection
25  * after a request may free network resources associated with this
26  * instance but has no effect on any shared persistent connection.
27  * Calling the disconnect() method may close the underlying socket
28  * if a persistent connection is otherwise idle at that time.
29  *
30  * @see java.net.HttpURLConnection#disconnect()
31  * @since JDK1.1
32  */

33 abstract public class HttpURLConnection extends URLConnection JavaDoc {
34     /* instance variables */
35
36     /**
37      * The HTTP method (GET,POST,PUT,etc.).
38      */

39     protected String JavaDoc method = "GET";
40
41     /**
42      * The chunk-length when using chunked encoding streaming mode for output.
43      * A value of <code>-1</code> means chunked encoding is disabled for output.
44      */

45     protected int chunkLength = -1;
46
47     /**
48      * The fixed content-length when using fixed-length streaming mode.
49      * A value of <code>-1</code> means fixed-length streaming mode is disabled
50      * for output.
51      */

52     protected int fixedContentLength = -1;
53
54     /**
55      * Returns the key for the <code>n</code><sup>th</sup> header field.
56      * Some implementations may treat the <code>0</code><sup>th</sup>
57      * header field as special, i.e. as the status line returned by the HTTP
58      * server. In this case, {@link #getHeaderField(int) getHeaderField(0)} returns the status
59      * line, but <code>getHeaderFieldKey(0)</code> returns null.
60      *
61      * @param n an index, where n >=0.
62      * @return the key for the <code>n</code><sup>th</sup> header field,
63      * or <code>null</code> if the key does not exist.
64      */

65     public String JavaDoc getHeaderFieldKey (int n) {
66     return null;
67     }
68
69     /**
70      * This method is used to enable streaming of a HTTP request body
71      * without internal buffering, when the content length is known in
72      * advance.
73      * <p>
74      * An exception will be thrown if the application
75      * attempts to write more data than the indicated
76      * content-length, or if the application closes the OutputStream
77      * before writing the indicated amount.
78      * <p>
79      * When output streaming is enabled, authentication
80      * and redirection cannot be handled automatically.
81      * A HttpRetryException will be thrown when reading
82      * the response if authentication or redirection are required.
83      * This exception can be queried for the details of the error.
84      * <p>
85      * This method must be called before the URLConnection is connected.
86      *
87      * @param contentLength The number of bytes which will be written
88      * to the OutputStream.
89      *
90      * @throws IllegalStateException if URLConnection is already connected
91      * or if a different streaming mode is already enabled.
92      *
93      * @throws IllegalArgumentException if a content length less than
94      * zero is specified.
95      *
96      * @see #setChunkedStreamingMode(int)
97      */

98     public void setFixedLengthStreamingMode (int contentLength) {
99     if (connected) {
100         throw new IllegalStateException JavaDoc ("Already connected");
101     }
102     if (chunkLength != -1) {
103         throw new IllegalStateException JavaDoc ("Chunked encoding streaming mode set");
104     }
105     if (contentLength < 0) {
106         throw new IllegalArgumentException JavaDoc ("invalid content length");
107     }
108     fixedContentLength = contentLength;
109     }
110
111     /* Default chunk size (including chunk header) if not specified;
112      * we want to keep this in sync with the one defined in
113      * sun.net.www.http.ChunkedOutputStream
114      */

115     private static final int DEFAULT_CHUNK_SIZE = 4096;
116
117     /**
118      * This method is used to enable streaming of a HTTP request body
119      * without internal buffering, when the content length is <b>not</b>
120      * known in advance. In this mode, chunked transfer encoding
121      * is used to send the request body. Note, not all HTTP servers
122      * support this mode.
123      * <p>
124      * When output streaming is enabled, authentication
125      * and redirection cannot be handled automatically.
126      * A HttpRetryException will be thrown when reading
127      * the response if authentication or redirection are required.
128      * This exception can be queried for the details of the error.
129      * <p>
130      * This method must be called before the URLConnection is connected.
131      *
132      * @param chunklen The number of bytes to write in each chunk.
133      * If chunklen is less than or equal to zero, a default
134      * value will be used.
135      *
136      * @throws IllegalStateException if URLConnection is already connected
137      * or if a different streaming mode is already enabled.
138      *
139      * @see #setFixedLengthStreamingMode(int)
140      */

141     public void setChunkedStreamingMode (int chunklen) {
142     if (connected) {
143         throw new IllegalStateException JavaDoc ("Can't set streaming mode: already connected");
144     }
145     if (fixedContentLength != -1) {
146         throw new IllegalStateException JavaDoc ("Fixed length streaming mode set");
147     }
148     chunkLength = chunklen <=0? DEFAULT_CHUNK_SIZE : chunklen;
149     }
150
151     /**
152      * Returns the value for the <code>n</code><sup>th</sup> header field.
153      * Some implementations may treat the <code>0</code><sup>th</sup>
154      * header field as special, i.e. as the status line returned by the HTTP
155      * server.
156      * <p>
157      * This method can be used in conjunction with the
158      * {@link #getHeaderFieldKey getHeaderFieldKey} method to iterate through all
159      * the headers in the message.
160      *
161      * @param n an index, where n>=0.
162      * @return the value of the <code>n</code><sup>th</sup> header field,
163      * or <code>null</code> if the value does not exist.
164      * @see java.net.HttpURLConnection#getHeaderFieldKey(int)
165      */

166     public String JavaDoc getHeaderField(int n) {
167     return null;
168     }
169
170     /**
171      * An <code>int</code> representing the three digit HTTP Status-Code.
172      * <ul>
173      * <li> 1xx: Informational
174      * <li> 2xx: Success
175      * <li> 3xx: Redirection
176      * <li> 4xx: Client Error
177      * <li> 5xx: Server Error
178      * </ul>
179      */

180     protected int responseCode = -1;
181
182     /**
183      * The HTTP response message.
184      */

185     protected String JavaDoc responseMessage = null;
186
187     /* static variables */
188
189     /* do we automatically follow redirects? The default is true. */
190     private static boolean followRedirects = true;
191
192     /**
193      * If <code>true</code>, the protocol will automatically follow redirects.
194      * If <code>false</code>, the protocol will not automatically follow
195      * redirects.
196      * <p>
197      * This field is set by the <code>setInstanceFollowRedirects</code>
198      * method. Its value is returned by the <code>getInstanceFollowRedirects</code>
199      * method.
200      * <p>
201      * Its default value is based on the value of the static followRedirects
202      * at HttpURLConnection construction time.
203      *
204      * @see java.net.HttpURLConnection#setInstanceFollowRedirects(boolean)
205      * @see java.net.HttpURLConnection#getInstanceFollowRedirects()
206      * @see java.net.HttpURLConnection#setFollowRedirects(boolean)
207      */

208     protected boolean instanceFollowRedirects = followRedirects;
209
210     /* valid HTTP methods */
211     private static final String JavaDoc[] methods = {
212     "GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE"
213     };
214
215     /**
216      * Constructor for the HttpURLConnection.
217      * @param u the URL
218      */

219     protected HttpURLConnection (URL JavaDoc u) {
220     super(u);
221     }
222     
223     /**
224      * Sets whether HTTP redirects (requests with response code 3xx) should
225      * be automatically followed by this class. True by default. Applets
226      * cannot change this variable.
227      * <p>
228      * If there is a security manager, this method first calls
229      * the security manager's <code>checkSetFactory</code> method
230      * to ensure the operation is allowed.
231      * This could result in a SecurityException.
232      *
233      * @param set a <code>boolean</code> indicating whether or not
234      * to follow HTTP redirects.
235      * @exception SecurityException if a security manager exists and its
236      * <code>checkSetFactory</code> method doesn't
237      * allow the operation.
238      * @see SecurityManager#checkSetFactory
239      * @see #getFollowRedirects()
240      */

241     public static void setFollowRedirects(boolean set) {
242     SecurityManager JavaDoc sec = System.getSecurityManager();
243     if (sec != null) {
244         // seems to be the best check here...
245
sec.checkSetFactory();
246     }
247     followRedirects = set;
248     }
249
250     /**
251      * Returns a <code>boolean</code> indicating
252      * whether or not HTTP redirects (3xx) should
253      * be automatically followed.
254      *
255      * @return <code>true</code> if HTTP redirects should
256      * be automatically followed, <tt>false</tt> if not.
257      * @see #setFollowRedirects(boolean)
258      */

259     public static boolean getFollowRedirects() {
260     return followRedirects;
261     }
262
263     /**
264      * Sets whether HTTP redirects (requests with response code 3xx) should
265      * be automatically followed by this <code>HttpURLConnection</code>
266      * instance.
267      * <p>
268      * The default value comes from followRedirects, which defaults to
269      * true.
270      *
271      * @param followRedirects a <code>boolean</code> indicating
272      * whether or not to follow HTTP redirects.
273      *
274      * @see java.net.HttpURLConnection#instanceFollowRedirects
275      * @see #getInstanceFollowRedirects
276      */

277      public void setInstanceFollowRedirects(boolean followRedirects) {
278     instanceFollowRedirects = followRedirects;
279      }
280
281      /**
282      * Returns the value of this <code>HttpURLConnection</code>'s
283      * <code>instanceFollowRedirects</code> field.
284      *
285      * @return the value of this <code>HttpURLConnection</code>'s
286      * <code>instanceFollowRedirects</code> field.
287      * @see java.net.HttpURLConnection#instanceFollowRedirects
288      * @see #setInstanceFollowRedirects(boolean)
289      */

290      public boolean getInstanceFollowRedirects() {
291          return instanceFollowRedirects;
292      }
293
294     /**
295      * Set the method for the URL request, one of:
296      * <UL>
297      * <LI>GET
298      * <LI>POST
299      * <LI>HEAD
300      * <LI>OPTIONS
301      * <LI>PUT
302      * <LI>DELETE
303      * <LI>TRACE
304      * </UL> are legal, subject to protocol restrictions. The default
305      * method is GET.
306      *
307      * @param method the HTTP method
308      * @exception ProtocolException if the method cannot be reset or if
309      * the requested method isn't valid for HTTP.
310      * @see #getRequestMethod()
311      */

312     public void setRequestMethod(String JavaDoc method) throws ProtocolException JavaDoc {
313     if (connected) {
314         throw new ProtocolException JavaDoc("Can't reset method: already connected");
315     }
316     // This restriction will prevent people from using this class to
317
// experiment w/ new HTTP methods using java. But it should
318
// be placed for security - the request String could be
319
// arbitrarily long.
320

321     for (int i = 0; i < methods.length; i++) {
322         if (methods[i].equals(method)) {
323         this.method = method;
324         return;
325         }
326     }
327     throw new ProtocolException JavaDoc("Invalid HTTP method: " + method);
328     }
329
330     /**
331      * Get the request method.
332      * @return the HTTP request method
333      * @see #setRequestMethod(java.lang.String)
334      */

335     public String JavaDoc getRequestMethod() {
336     return method;
337     }
338     
339     /**
340      * Gets the status code from an HTTP response message.
341      * For example, in the case of the following status lines:
342      * <PRE>
343      * HTTP/1.0 200 OK
344      * HTTP/1.0 401 Unauthorized
345      * </PRE>
346      * It will return 200 and 401 respectively.
347      * Returns -1 if no code can be discerned
348      * from the response (i.e., the response is not valid HTTP).
349      * @throws IOException if an error occurred connecting to the server.
350      * @return the HTTP Status-Code, or -1
351      */

352     public int getResponseCode() throws IOException JavaDoc {
353     /*
354      * We're got the response code already
355      */

356     if (responseCode != -1) {
357         return responseCode;
358     }
359
360     /*
361      * Ensure that we have connected to the server. Record
362      * exception as we need to re-throw it if there isn't
363      * a status line.
364      */

365     Exception JavaDoc exc = null;
366     try {
367             getInputStream();
368     } catch (Exception JavaDoc e) {
369         exc = e;
370     }
371
372     /*
373      * If we can't a status-line then re-throw any exception
374      * that getInputStream threw.
375      */

376     String JavaDoc statusLine = getHeaderField(0);
377     if (statusLine == null) {
378         if (exc != null) {
379         if (exc instanceof RuntimeException JavaDoc)
380                     throw (RuntimeException JavaDoc)exc;
381                 else
382                     throw (IOException JavaDoc)exc;
383         }
384         return -1;
385     }
386
387     /*
388      * Examine the status-line - should be formatted as per
389      * section 6.1 of RFC 2616 :-
390      *
391      * Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase
392      *
393      * If status line can't be parsed return -1.
394      */

395     if (statusLine.startsWith("HTTP/1.")) {
396         int codePos = statusLine.indexOf(' ');
397         if (codePos > 0) {
398
399         int phrasePos = statusLine.indexOf(' ', codePos+1);
400         if (phrasePos > 0 && phrasePos < statusLine.length()) {
401             responseMessage = statusLine.substring(phrasePos+1);
402         }
403
404         // deviation from RFC 2616 - don't reject status line
405
// if SP Reason-Phrase is not included.
406
if (phrasePos < 0)
407             phrasePos = statusLine.length();
408
409         try {
410             responseCode = Integer.parseInt
411                             (statusLine.substring(codePos+1, phrasePos));
412             return responseCode;
413         } catch (NumberFormatException JavaDoc e) { }
414         }
415     }
416     return -1;
417     }
418
419     /**
420      * Gets the HTTP response message, if any, returned along with the
421      * response code from a server. From responses like:
422      * <PRE>
423      * HTTP/1.0 200 OK
424      * HTTP/1.0 404 Not Found
425      * </PRE>
426      * Extracts the Strings "OK" and "Not Found" respectively.
427      * Returns null if none could be discerned from the responses
428      * (the result was not valid HTTP).
429      * @throws IOException if an error occurred connecting to the server.
430      * @return the HTTP response message, or <code>null</code>
431      */

432     public String JavaDoc getResponseMessage() throws IOException JavaDoc {
433     getResponseCode();
434     return responseMessage;
435     }
436
437     public long getHeaderFieldDate(String JavaDoc name, long Default) {
438     String JavaDoc dateString = getHeaderField(name);
439     try {
440         dateString.trim();
441         if (dateString.indexOf("GMT") == -1) {
442             dateString = dateString+" GMT";
443         }
444         return Date.parse(dateString);
445     } catch (Exception JavaDoc e) {
446     }
447     return Default;
448     }
449
450
451     /**
452      * Indicates that other requests to the server
453      * are unlikely in the near future. Calling disconnect()
454      * should not imply that this HttpURLConnection
455      * instance can be reused for other requests.
456      */

457     public abstract void disconnect();
458
459     /**
460      * Indicates if the connection is going through a proxy.
461      * @return a boolean indicating if the connection is
462      * using a proxy.
463      */

464     public abstract boolean usingProxy();
465
466     public Permission JavaDoc getPermission() throws IOException JavaDoc {
467     int port = url.getPort();
468     port = port < 0 ? 80 : port;
469     String JavaDoc host = url.getHost() + ":" + port;
470     Permission JavaDoc permission = new SocketPermission JavaDoc(host, "connect");
471     return permission;
472     }
473
474    /**
475     * Returns the error stream if the connection failed
476     * but the server sent useful data nonetheless. The
477     * typical example is when an HTTP server responds
478     * with a 404, which will cause a FileNotFoundException
479     * to be thrown in connect, but the server sent an HTML
480     * help page with suggestions as to what to do.
481     *
482     * <p>This method will not cause a connection to be initiated. If
483     * the connection was not connected, or if the server did not have
484     * an error while connecting or if the server had an error but
485     * no error data was sent, this method will return null. This is
486     * the default.
487     *
488     * @return an error stream if any, null if there have been no
489     * errors, the connection is not connected or the server sent no
490     * useful data.
491     */

492     public InputStream JavaDoc getErrorStream() {
493     return null;
494     }
495
496     /**
497      * The response codes for HTTP, as of version 1.1.
498      */

499
500     // REMIND: do we want all these??
501
// Others not here that we do want??
502

503     /* 2XX: generally "OK" */
504
505     /**
506      * HTTP Status-Code 200: OK.
507      */

508     public static final int HTTP_OK = 200;
509
510     /**
511      * HTTP Status-Code 201: Created.
512      */

513     public static final int HTTP_CREATED = 201;
514
515     /**
516      * HTTP Status-Code 202: Accepted.
517      */

518     public static final int HTTP_ACCEPTED = 202;
519
520     /**
521      * HTTP Status-Code 203: Non-Authoritative Information.
522      */

523     public static final int HTTP_NOT_AUTHORITATIVE = 203;
524
525     /**
526      * HTTP Status-Code 204: No Content.
527      */

528     public static final int HTTP_NO_CONTENT = 204;
529
530     /**
531      * HTTP Status-Code 205: Reset Content.
532      */

533     public static final int HTTP_RESET = 205;
534
535     /**
536      * HTTP Status-Code 206: Partial Content.
537      */

538     public static final int HTTP_PARTIAL = 206;
539
540     /* 3XX: relocation/redirect */
541
542     /**
543      * HTTP Status-Code 300: Multiple Choices.
544      */

545     public static final int HTTP_MULT_CHOICE = 300;
546
547     /**
548      * HTTP Status-Code 301: Moved Permanently.
549      */

550     public static final int HTTP_MOVED_PERM = 301;
551
552     /**
553      * HTTP Status-Code 302: Temporary Redirect.
554      */

555     public static final int HTTP_MOVED_TEMP = 302;
556  
557     /**
558      * HTTP Status-Code 303: See Other.
559      */

560     public static final int HTTP_SEE_OTHER = 303;
561
562     /**
563      * HTTP Status-Code 304: Not Modified.
564      */

565     public static final int HTTP_NOT_MODIFIED = 304;
566
567     /**
568      * HTTP Status-Code 305: Use Proxy.
569      */

570     public static final int HTTP_USE_PROXY = 305;
571
572     /* 4XX: client error */
573
574     /**
575      * HTTP Status-Code 400: Bad Request.
576      */

577     public static final int HTTP_BAD_REQUEST = 400;
578
579     /**
580      * HTTP Status-Code 401: Unauthorized.
581      */

582     public static final int HTTP_UNAUTHORIZED = 401;
583
584     /**
585      * HTTP Status-Code 402: Payment Required.
586      */

587     public static final int HTTP_PAYMENT_REQUIRED = 402;
588
589     /**
590      * HTTP Status-Code 403: Forbidden.
591      */

592     public static final int HTTP_FORBIDDEN = 403;
593
594     /**
595      * HTTP Status-Code 404: Not Found.
596      */

597     public static final int HTTP_NOT_FOUND = 404;
598
599     /**
600      * HTTP Status-Code 405: Method Not Allowed.
601      */

602     public static final int HTTP_BAD_METHOD = 405;
603
604     /**
605      * HTTP Status-Code 406: Not Acceptable.
606      */

607     public static final int HTTP_NOT_ACCEPTABLE = 406;
608
609     /**
610      * HTTP Status-Code 407: Proxy Authentication Required.
611      */

612     public static final int HTTP_PROXY_AUTH = 407;
613
614     /**
615      * HTTP Status-Code 408: Request Time-Out.
616      */

617     public static final int HTTP_CLIENT_TIMEOUT = 408;
618
619     /**
620      * HTTP Status-Code 409: Conflict.
621      */

622     public static final int HTTP_CONFLICT = 409;
623
624     /**
625      * HTTP Status-Code 410: Gone.
626      */

627     public static final int HTTP_GONE = 410;
628
629     /**
630      * HTTP Status-Code 411: Length Required.
631      */

632     public static final int HTTP_LENGTH_REQUIRED = 411;
633
634     /**
635      * HTTP Status-Code 412: Precondition Failed.
636      */

637     public static final int HTTP_PRECON_FAILED = 412;
638
639     /**
640      * HTTP Status-Code 413: Request Entity Too Large.
641      */

642     public static final int HTTP_ENTITY_TOO_LARGE = 413;
643
644     /**
645      * HTTP Status-Code 414: Request-URI Too Large.
646      */

647     public static final int HTTP_REQ_TOO_LONG = 414;
648
649     /**
650      * HTTP Status-Code 415: Unsupported Media Type.
651      */

652     public static final int HTTP_UNSUPPORTED_TYPE = 415;
653     
654     /* 5XX: server error */
655
656     /**
657      * HTTP Status-Code 500: Internal Server Error.
658      * @deprecated it is misplaced and shouldn't have existed.
659      */

660     @Deprecated JavaDoc
661     public static final int HTTP_SERVER_ERROR = 500;
662
663     /**
664      * HTTP Status-Code 500: Internal Server Error.
665      */

666     public static final int HTTP_INTERNAL_ERROR = 500;
667
668     /**
669      * HTTP Status-Code 501: Not Implemented.
670      */

671     public static final int HTTP_NOT_IMPLEMENTED = 501;
672
673     /**
674      * HTTP Status-Code 502: Bad Gateway.
675      */

676     public static final int HTTP_BAD_GATEWAY = 502;
677
678     /**
679      * HTTP Status-Code 503: Service Unavailable.
680      */

681     public static final int HTTP_UNAVAILABLE = 503;
682
683     /**
684      * HTTP Status-Code 504: Gateway Timeout.
685      */

686     public static final int HTTP_GATEWAY_TIMEOUT = 504;
687
688     /**
689      * HTTP Status-Code 505: HTTP Version Not Supported.
690      */

691     public static final int HTTP_VERSION = 505;
692
693 }
694
Popular Tags