Source for java.net.HttpURLConnection

   1: /* HttpURLConnection.java -- Subclass of communications links using
   2:    Hypertext Transfer Protocol.
   3:    Copyright (C) 1998, 1999, 2000, 2002, 2003  Free Software Foundation
   4: 
   5: This file is part of GNU Classpath.
   6: 
   7: GNU Classpath is free software; you can redistribute it and/or modify
   8: it under the terms of the GNU General Public License as published by
   9: the Free Software Foundation; either version 2, or (at your option)
  10: any later version.
  11: 
  12: GNU Classpath is distributed in the hope that it will be useful, but
  13: WITHOUT ANY WARRANTY; without even the implied warranty of
  14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15: General Public License for more details.
  16: 
  17: You should have received a copy of the GNU General Public License
  18: along with GNU Classpath; see the file COPYING.  If not, write to the
  19: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  20: 02110-1301 USA.
  21: 
  22: Linking this library statically or dynamically with other modules is
  23: making a combined work based on this library.  Thus, the terms and
  24: conditions of the GNU General Public License cover the whole
  25: combination.
  26: 
  27: As a special exception, the copyright holders of this library give you
  28: permission to link this library with independent modules to produce an
  29: executable, regardless of the license terms of these independent
  30: modules, and to copy and distribute the resulting executable under
  31: terms of your choice, provided that you also meet, for each linked
  32: independent module, the terms and conditions of the license of that
  33: module.  An independent module is a module which is not derived from
  34: or based on this library.  If you modify this library, you may extend
  35: this exception to your version of the library, but you are not
  36: obligated to do so.  If you do not wish to do so, delete this
  37: exception statement from your version. */
  38: 
  39: package java.net;
  40: 
  41: import java.io.IOException;
  42: import java.io.InputStream;
  43: import java.io.PushbackInputStream;
  44: import java.security.Permission;
  45: 
  46: 
  47: /*
  48:  * Written using on-line Java Platform 1.2 API Specification, as well
  49:  * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
  50:  * Status:  Believed complete and correct.
  51:  */
  52: 
  53: /**
  54:  * This class provides a common abstract implementation for those
  55:  * URL connection classes that will connect using the HTTP protocol.
  56:  * In addition to the functionality provided by the URLConnection
  57:  * class, it defines constants for HTTP return code values and
  58:  * methods for setting the HTTP request method and determining whether
  59:  * or not to follow redirects.
  60:  *
  61:  * @since 1.1
  62:  *
  63:  * @author Warren Levy (warrenl@cygnus.com)
  64:  * @author Aaron M. Renn (arenn@urbanophile.com)
  65:  */
  66: public abstract class HttpURLConnection extends URLConnection
  67: {
  68:   /* HTTP Success Response Codes */
  69: 
  70:   /**
  71:    * Indicates that the client may continue with its request.  This value
  72:    * is specified as part of RFC 2068 but was not included in Sun's JDK, so
  73:    * beware of using this value
  74:    */
  75:   static final int HTTP_CONTINUE = 100;
  76: 
  77:   /**
  78:    * Indicates the request succeeded.
  79:    */
  80:   public static final int HTTP_OK = 200;
  81: 
  82:   /**
  83:    * The requested resource has been created.
  84:    */
  85:   public static final int HTTP_CREATED = 201;
  86: 
  87:   /**
  88:    * The request has been accepted for processing but has not completed.
  89:    * There is no guarantee that the requested action will actually ever
  90:    * be completed succesfully, but everything is ok so far.
  91:    */
  92:   public static final int HTTP_ACCEPTED = 202;
  93: 
  94:   /**
  95:    * The meta-information returned in the header is not the actual data
  96:    * from the original server, but may be from a local or other copy.
  97:    * Normally this still indicates a successful completion.
  98:    */
  99:   public static final int HTTP_NOT_AUTHORITATIVE = 203;
 100: 
 101:   /**
 102:    * The server performed the request, but there is no data to send
 103:    * back.  This indicates that the user's display should not be changed.
 104:    */
 105:   public static final int HTTP_NO_CONTENT = 204;
 106: 
 107:   /**
 108:    * The server performed the request, but there is no data to sent back,
 109:    * however, the user's display should be "reset" to clear out any form
 110:    * fields entered.
 111:    */
 112:   public static final int HTTP_RESET = 205;
 113: 
 114:   /**
 115:    * The server completed the partial GET request for the resource.
 116:    */
 117:   public static final int HTTP_PARTIAL = 206;
 118: 
 119:   /* HTTP Redirection Response Codes */
 120: 
 121:   /**
 122:    * There is a list of choices available for the requested resource.
 123:    */
 124:   public static final int HTTP_MULT_CHOICE = 300;
 125: 
 126:   /**
 127:    * The resource has been permanently moved to a new location.
 128:    */
 129:   public static final int HTTP_MOVED_PERM = 301;
 130: 
 131:   /**
 132:    * The resource requested has been temporarily moved to a new location.
 133:    */
 134:   public static final int HTTP_MOVED_TEMP = 302;
 135: 
 136:   /**
 137:    * The response to the request issued is available at another location.
 138:    */
 139:   public static final int HTTP_SEE_OTHER = 303;
 140: 
 141:   /**
 142:    * The document has not been modified since the criteria specified in
 143:    * a conditional GET.
 144:    */
 145:   public static final int HTTP_NOT_MODIFIED = 304;
 146: 
 147:   /**
 148:    * The requested resource needs to be accessed through a proxy.
 149:    */
 150:   public static final int HTTP_USE_PROXY = 305;
 151: 
 152:   /* HTTP Client Error Response Codes */
 153: 
 154:   /**
 155:    * The request was misformed or could not be understood.
 156:    */
 157:   public static final int HTTP_BAD_REQUEST = 400;
 158: 
 159:   /**
 160:    * The request made requires user authorization.  Try again with
 161:    * a correct authentication header.
 162:    */
 163:   public static final int HTTP_UNAUTHORIZED = 401;
 164: 
 165:   /**
 166:    * Code reserved for future use - I hope way in the future.
 167:    */
 168:   public static final int HTTP_PAYMENT_REQUIRED = 402;
 169: 
 170:   /**
 171:    * There is no permission to access the requested resource.
 172:    */
 173:   public static final int HTTP_FORBIDDEN = 403;
 174: 
 175:   /**
 176:    * The requested resource was not found.
 177:    */
 178:   public static final int HTTP_NOT_FOUND = 404;
 179: 
 180:   /**
 181:    * The specified request method is not allowed for this resource.
 182:    */
 183:   public static final int HTTP_BAD_METHOD = 405;
 184: 
 185:   /**
 186:    * Based on the input headers sent, the resource returned in response
 187:    * to the request would not be acceptable to the client.
 188:    */
 189:   public static final int HTTP_NOT_ACCEPTABLE = 406;
 190: 
 191:   /**
 192:    * The client must authenticate with a proxy prior to attempting this
 193:    * request.
 194:    */
 195:   public static final int HTTP_PROXY_AUTH = 407;
 196: 
 197:   /**
 198:    * The request timed out.
 199:    */
 200:   public static final int HTTP_CLIENT_TIMEOUT = 408;
 201: 
 202:   /**
 203:    * There is a conflict between the current state of the resource and the
 204:    * requested action.
 205:    */
 206:   public static final int HTTP_CONFLICT = 409;
 207: 
 208:   /**
 209:    * The requested resource is no longer available.  This ususally indicates
 210:    * a permanent condition.
 211:    */
 212:   public static final int HTTP_GONE = 410;
 213: 
 214:   /**
 215:    * A Content-Length header is required for this request, but was not
 216:    * supplied.
 217:    */
 218:   public static final int HTTP_LENGTH_REQUIRED = 411;
 219: 
 220:   /**
 221:    * A client specified pre-condition was not met on the server.
 222:    */
 223:   public static final int HTTP_PRECON_FAILED = 412;
 224: 
 225:   /**
 226:    * The request sent was too large for the server to handle.
 227:    */
 228:   public static final int HTTP_ENTITY_TOO_LARGE = 413;
 229: 
 230:   /**
 231:    * The name of the resource specified was too long.
 232:    */
 233:   public static final int HTTP_REQ_TOO_LONG = 414;
 234: 
 235:   /**
 236:    * The request is in a format not supported by the requested resource.
 237:    */
 238:   public static final int HTTP_UNSUPPORTED_TYPE = 415;
 239: 
 240:   /* HTTP Server Error Response Codes */
 241: 
 242:   /**
 243:    * This error code indicates that some sort of server error occurred.
 244:    *
 245:    * @deprecated
 246:    */
 247:   public static final int HTTP_SERVER_ERROR = 500;
 248: 
 249:   /**
 250:    * The server encountered an unexpected error (such as a CGI script crash)
 251:    * that prevents the request from being fulfilled.
 252:    */
 253:   public static final int HTTP_INTERNAL_ERROR = 500;
 254: 
 255:   /**
 256:    * The server does not support the requested functionality.
 257:    * @since 1.3
 258:    */
 259:   public static final int HTTP_NOT_IMPLEMENTED = 501;
 260: 
 261:   /**
 262:    * The proxy encountered a bad response from the server it was proxy-ing for
 263:    */
 264:   public static final int HTTP_BAD_GATEWAY = 502;
 265: 
 266:   /**
 267:    * The HTTP service is not availalble, such as because it is overloaded
 268:    * and does not want additional requests.
 269:    */
 270:   public static final int HTTP_UNAVAILABLE = 503;
 271: 
 272:   /**
 273:    * The proxy timed out getting a reply from the remote server it was
 274:    * proxy-ing for.
 275:    */
 276:   public static final int HTTP_GATEWAY_TIMEOUT = 504;
 277: 
 278:   /**
 279:    * This server does not support the protocol version requested.
 280:    */
 281:   public static final int HTTP_VERSION = 505;
 282: 
 283:   // Non-HTTP response static variables
 284: 
 285:   /**
 286:    * Flag to indicate whether or not redirects should be automatically
 287:    * followed by default.
 288:    */
 289:   private static boolean followRedirects = true;
 290: 
 291:   /**
 292:    * This is a list of valid request methods, separated by "|" characters.
 293:    */
 294:   private static final String valid_methods =
 295:     "|GET|POST|HEAD|OPTIONS|PUT|DELETE|TRACE|";
 296: 
 297:   // Instance Variables
 298: 
 299:   /**
 300:    * The requested method in use for this connection. Default is GET.
 301:    */
 302:   protected String method = "GET";
 303: 
 304:   /**
 305:    * The response code received from the server
 306:    */
 307:   protected int responseCode = -1;
 308: 
 309:   /**
 310:    * The response message string received from the server.
 311:    */
 312:   protected String responseMessage;
 313: 
 314:   /**
 315:    * If this instance should follow redirect requests.
 316:    */
 317:   protected boolean instanceFollowRedirects = followRedirects;
 318: 
 319:   /**
 320:    * Whether we already got a valid response code for this connection.
 321:    * Used by <code>getResponseCode()</code> and
 322:    * <code>getResponseMessage()</code>.
 323:    */
 324:   private boolean gotResponseVals;
 325: 
 326:   /**
 327:    * Create an HttpURLConnection for the specified URL
 328:    *
 329:    * @param url The URL to create this connection for.
 330:    */
 331:   protected HttpURLConnection(URL url)
 332:   {
 333:     super(url);
 334:   }
 335: 
 336:   /**
 337:    * Closes the connection to the server.
 338:    */
 339:   public abstract void disconnect();
 340: 
 341:   /**
 342:    * Returns a boolean indicating whether or not this connection is going
 343:    * through a proxy
 344:    *
 345:    * @return true if through a proxy, false otherwise
 346:    */
 347:   public abstract boolean usingProxy();
 348: 
 349:   /**
 350:    * Sets whether HTTP redirects (requests with response code 3xx) should be
 351:    * automatically followed by this class. True by default
 352:    *
 353:    * @param set true if redirects should be followed, false otherwis.
 354:    *
 355:    * @exception SecurityException If a security manager exists and its
 356:    * checkSetFactory method doesn't allow the operation
 357:    */
 358:   public static void setFollowRedirects(boolean set)
 359:   {
 360:     // Throw an exception if an extant security mgr precludes
 361:     // setting the factory.
 362:     SecurityManager s = System.getSecurityManager();
 363:     if (s != null)
 364:       s.checkSetFactory();
 365: 
 366:     followRedirects = set;
 367:   }
 368: 
 369:   /**
 370:    * Returns a boolean indicating whether or not HTTP redirects will
 371:    * automatically be followed or not.
 372:    *
 373:    * @return true if redirects will be followed, false otherwise
 374:    */
 375:   public static boolean getFollowRedirects()
 376:   {
 377:     return followRedirects;
 378:   }
 379: 
 380:   /**
 381:    * Returns the value of this HttpURLConnection's instanceFollowRedirects
 382:    * field
 383:    *
 384:    * @return true if following redirects is enabled, false otherwise
 385:    */
 386:   public boolean getInstanceFollowRedirects()
 387:   {
 388:     return instanceFollowRedirects;
 389:   }
 390: 
 391:   /**
 392:    * Sets the value of this HttpURLConnection's instanceFollowRedirects field
 393:    *
 394:    * @param follow true to enable following redirects, false otherwise
 395:    */
 396:   public void setInstanceFollowRedirects(boolean follow)
 397:   {
 398:     instanceFollowRedirects = follow;
 399:   }
 400: 
 401:   /**
 402:    * Set the method for the URL request, one of:
 403:    * GET POST HEAD OPTIONS PUT DELETE TRACE are legal
 404:    *
 405:    * @param method the method to use
 406:    *
 407:    * @exception ProtocolException If the method cannot be reset or if the
 408:    * requested method isn't valid for HTTP
 409:    */
 410:   public void setRequestMethod(String method) throws ProtocolException
 411:   {
 412:     if (connected)
 413:       throw new ProtocolException("Already connected");
 414: 
 415:     method = method.toUpperCase();
 416:     if (valid_methods.indexOf("|" + method + "|") != -1)
 417:       this.method = method;
 418:     else
 419:       throw new ProtocolException("Invalid HTTP request method: " + method);
 420:   }
 421: 
 422:   /**
 423:    * The request method currently in use for this connection.
 424:    *
 425:    * @return The request method
 426:    */
 427:   public String getRequestMethod()
 428:   {
 429:     return method;
 430:   }
 431: 
 432:   /**
 433:    * Gets the status code from an HTTP response message, or -1 if
 434:    * the response code could not be determined.
 435:    * Note that all valid response codes have class variables
 436:    * defined for them in this class.
 437:    *
 438:    * @return The response code
 439:    *
 440:    * @exception IOException If an error occurs
 441:    */
 442:   public int getResponseCode() throws IOException
 443:   {
 444:     if (! gotResponseVals)
 445:       getResponseVals();
 446:     return responseCode;
 447:   }
 448: 
 449:   /**
 450:    * Gets the HTTP response message, if any, returned along with the
 451:    * response code from a server. Null if no response message was set
 452:    * or an error occured while connecting.
 453:    *
 454:    * @return The response message
 455:    *
 456:    * @exception IOException If an error occurs
 457:    */
 458:   public String getResponseMessage() throws IOException
 459:   {
 460:     if (! gotResponseVals)
 461:       getResponseVals();
 462:     return responseMessage;
 463:   }
 464: 
 465:   private void getResponseVals() throws IOException
 466:   {
 467:     // getHeaderField() will connect for us, but do it here first in
 468:     // order to pick up IOExceptions.
 469:     if (! connected)
 470:       connect();
 471: 
 472:     gotResponseVals = true;
 473: 
 474:     // If responseCode not yet explicitly set by subclass
 475:     if (responseCode == -1)
 476:       {
 477:         // Response is the first header received from the connection.
 478:         String respField = getHeaderField(0);
 479: 
 480:         if (respField == null || ! respField.startsWith("HTTP/"))
 481:           {
 482:             // Set to default values on failure.
 483:             responseCode = -1;
 484:             responseMessage = null;
 485:             return;
 486:           }
 487: 
 488:         int firstSpc;
 489:         int nextSpc;
 490:         firstSpc = respField.indexOf(' ');
 491:         nextSpc = respField.indexOf(' ', firstSpc + 1);
 492:         responseMessage = respField.substring(nextSpc + 1);
 493:         String codeStr = respField.substring(firstSpc + 1, nextSpc);
 494:         try
 495:           {
 496:             responseCode = Integer.parseInt(codeStr);
 497:           }
 498:         catch (NumberFormatException e)
 499:           {
 500:             // Set to default values on failure.
 501:             responseCode = -1;
 502:             responseMessage = null;
 503:           }
 504:       }
 505:   }
 506: 
 507:   /**
 508:    * Returns a permission object representing the permission necessary to make
 509:    * the connection represented by this object
 510:    *
 511:    * @return the permission necessary for this connection
 512:    *
 513:    * @exception IOException If an error occurs
 514:    */
 515:   public Permission getPermission() throws IOException
 516:   {
 517:     URL url = getURL();
 518:     String host = url.getHost();
 519:     int port = url.getPort();
 520:     if (port == -1)
 521:       port = 80;
 522: 
 523:     host = host + ":" + port;
 524: 
 525:     return new SocketPermission(host, "connect");
 526:   }
 527: 
 528:   /**
 529:    * This method allows the caller to retrieve any data that might have
 530:    * been sent despite the fact that an error occurred.  For example, the
 531:    * HTML page sent along with a 404 File Not Found error.  If the socket
 532:    * is not connected, or if no error occurred or no data was returned,
 533:    * this method returns <code>null</code>.
 534:    *
 535:    * @return An <code>InputStream</code> for reading error data.
 536:    */
 537:   public InputStream getErrorStream()
 538:   {
 539:     if (! connected)
 540:       return null;
 541: 
 542:     int code;
 543:     try
 544:       {
 545:         code = getResponseCode();
 546:       }
 547:     catch (IOException e)
 548:       {
 549:         code = -1;
 550:       }
 551: 
 552:     if (code == -1)
 553:       return null;
 554: 
 555:     if (((code / 100) != 4) || ((code / 100) != 5))
 556:       return null;
 557: 
 558:     try
 559:       {
 560:         PushbackInputStream pbis = new PushbackInputStream(getInputStream());
 561: 
 562:         int i = pbis.read();
 563:         if (i == -1)
 564:           return null;
 565: 
 566:         pbis.unread(i);
 567:         return pbis;
 568:       }
 569:     catch (IOException e)
 570:       {
 571:         return null;
 572:       }
 573:   }
 574: 
 575:   /**
 576:    * Returns the value of the named field parsed as date
 577:    *
 578:    * @param key the key of the header field
 579:    * @param value the default value if the header field is not present
 580:    *
 581:    * @return the value of the header field
 582:    */
 583:   public long getHeaderFieldDate(String key, long value)
 584:   {
 585:     // FIXME: implement this correctly
 586:     // http://www.w3.org/Protocols/HTTP-NG/ng-notes.txt
 587:     return super.getHeaderFieldDate(key, value);
 588:   }
 589: }