1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.net; 19 20import java.io.IOException; 21 22import org.apache.harmony.luni.util.Msg; 23 24/** 25 * This abstract subclass of {@code URLConnection} defines methods for managing 26 * HTTP connection according to the description given by RFC 2068. 27 * 28 * @see ContentHandler 29 * @see URL 30 * @see URLConnection 31 * @see URLStreamHandler 32 */ 33public abstract class HttpURLConnection extends URLConnection { 34 @SuppressWarnings("nls") 35 private String methodTokens[] = { "GET", "DELETE", "HEAD", "OPTIONS", 36 "POST", "PUT", "TRACE" }; 37 38 /** 39 * The HTTP request method of this {@code HttpURLConnection}. The default 40 * value is {@code "GET"}. 41 */ 42 protected String method = "GET"; //$NON-NLS-1$ 43 44 /** 45 * The status code of the response obtained from the HTTP request. The 46 * default value is {@code -1}. 47 * <p> 48 * <li>1xx: Informational</li> 49 * <li>2xx: Success</li> 50 * <li>3xx: Relocation/Redirection</li> 51 * <li>4xx: Client Error</li> 52 * <li>5xx: Server Error</li> 53 */ 54 protected int responseCode = -1; 55 56 /** 57 * The HTTP response message which corresponds to the response code. 58 */ 59 protected String responseMessage; 60 61 /** 62 * Flag to define whether the protocol will automatically follow redirects 63 * or not. The default value is {@code true}. 64 */ 65 protected boolean instanceFollowRedirects = followRedirects; 66 67 private static boolean followRedirects = true; 68 69 /** 70 * If the HTTP chunked encoding is enabled this parameter defines the 71 * chunk-length. Default value is {@code -1} that means the chunked encoding 72 * mode is disabled. 73 */ 74 protected int chunkLength = -1; 75 76 /** 77 * If using HTTP fixed-length streaming mode this parameter defines the 78 * fixed length of content. Default value is {@code -1} that means the 79 * fixed-length streaming mode is disabled. 80 */ 81 protected int fixedContentLength = -1; 82 83 private final static int DEFAULT_CHUNK_LENGTH = 1024; 84 85 // 2XX: generally "OK" 86 // 3XX: relocation/redirect 87 // 4XX: client error 88 // 5XX: server error 89 /** 90 * Numeric status code, 202: Accepted 91 */ 92 public final static int HTTP_ACCEPTED = 202; 93 94 /** 95 * Numeric status code, 502: Bad Gateway 96 */ 97 public final static int HTTP_BAD_GATEWAY = 502; 98 99 /** 100 * Numeric status code, 405: Bad Method 101 */ 102 public final static int HTTP_BAD_METHOD = 405; 103 104 /** 105 * Numeric status code, 400: Bad Request 106 */ 107 public final static int HTTP_BAD_REQUEST = 400; 108 109 /** 110 * Numeric status code, 408: Client Timeout 111 */ 112 public final static int HTTP_CLIENT_TIMEOUT = 408; 113 114 /** 115 * Numeric status code, 409: Conflict 116 */ 117 public final static int HTTP_CONFLICT = 409; 118 119 /** 120 * Numeric status code, 201: Created 121 */ 122 public final static int HTTP_CREATED = 201; 123 124 /** 125 * Numeric status code, 413: Entity too large 126 */ 127 public final static int HTTP_ENTITY_TOO_LARGE = 413; 128 129 /** 130 * Numeric status code, 403: Forbidden 131 */ 132 public final static int HTTP_FORBIDDEN = 403; 133 134 /** 135 * Numeric status code, 504: Gateway timeout 136 */ 137 public final static int HTTP_GATEWAY_TIMEOUT = 504; 138 139 /** 140 * Numeric status code, 410: Gone 141 */ 142 public final static int HTTP_GONE = 410; 143 144 /** 145 * Numeric status code, 500: Internal error 146 */ 147 public final static int HTTP_INTERNAL_ERROR = 500; 148 149 /** 150 * Numeric status code, 411: Length required 151 */ 152 public final static int HTTP_LENGTH_REQUIRED = 411; 153 154 /** 155 * Numeric status code, 301 Moved permanently 156 */ 157 public final static int HTTP_MOVED_PERM = 301; 158 159 /** 160 * Numeric status code, 302: Moved temporarily 161 */ 162 public final static int HTTP_MOVED_TEMP = 302; 163 164 /** 165 * Numeric status code, 300: Multiple choices 166 */ 167 public final static int HTTP_MULT_CHOICE = 300; 168 169 /** 170 * Numeric status code, 204: No content 171 */ 172 public final static int HTTP_NO_CONTENT = 204; 173 174 /** 175 * Numeric status code, 406: Not acceptable 176 */ 177 public final static int HTTP_NOT_ACCEPTABLE = 406; 178 179 /** 180 * Numeric status code, 203: Not authoritative 181 */ 182 public final static int HTTP_NOT_AUTHORITATIVE = 203; 183 184 /** 185 * Numeric status code, 404: Not found 186 */ 187 public final static int HTTP_NOT_FOUND = 404; 188 189 /** 190 * Numeric status code, 501: Not implemented 191 */ 192 public final static int HTTP_NOT_IMPLEMENTED = 501; 193 194 /** 195 * Numeric status code, 304: Not modified 196 */ 197 public final static int HTTP_NOT_MODIFIED = 304; 198 199 /** 200 * Numeric status code, 200: OK 201 */ 202 public final static int HTTP_OK = 200; 203 204 /** 205 * Numeric status code, 206: Partial 206 */ 207 public final static int HTTP_PARTIAL = 206; 208 209 /** 210 * Numeric status code, 402: Payment required 211 */ 212 public final static int HTTP_PAYMENT_REQUIRED = 402; 213 214 /** 215 * Numeric status code, 412: Precondition failed 216 */ 217 public final static int HTTP_PRECON_FAILED = 412; 218 219 /** 220 * Numeric status code, 407: Proxy authentication required 221 */ 222 public final static int HTTP_PROXY_AUTH = 407; 223 224 /** 225 * Numeric status code, 414: Request too long 226 */ 227 public final static int HTTP_REQ_TOO_LONG = 414; 228 229 /** 230 * Numeric status code, 205: Reset 231 */ 232 public final static int HTTP_RESET = 205; 233 234 /** 235 * Numeric status code, 303: See other 236 */ 237 public final static int HTTP_SEE_OTHER = 303; 238 239 /** 240 * Numeric status code, 500: Internal error 241 * 242 * @deprecated Use {@link #HTTP_INTERNAL_ERROR} 243 */ 244 @Deprecated 245 public final static int HTTP_SERVER_ERROR = 500; 246 247 /** 248 * Numeric status code, 305: Use proxy 249 */ 250 public final static int HTTP_USE_PROXY = 305; 251 252 /** 253 * Numeric status code, 401: Unauthorized 254 */ 255 public final static int HTTP_UNAUTHORIZED = 401; 256 257 /** 258 * Numeric status code, 415: Unsupported type 259 */ 260 public final static int HTTP_UNSUPPORTED_TYPE = 415; 261 262 /** 263 * Numeric status code, 503: Unavailable 264 */ 265 public final static int HTTP_UNAVAILABLE = 503; 266 267 /** 268 * Numeric status code, 505: Version not supported 269 */ 270 public final static int HTTP_VERSION = 505; 271 272 /** 273 * Constructs a new {@code HttpURLConnection} instance pointing to the 274 * resource specified by the {@code url}. 275 * 276 * @param url 277 * the URL of this connection. 278 * @see URL 279 * @see URLConnection 280 */ 281 protected HttpURLConnection(URL url) { 282 super(url); 283 } 284 285 /** 286 * Closes the connection to the HTTP server. 287 * 288 * @see URLConnection#connect() 289 * @see URLConnection#connected 290 */ 291 public abstract void disconnect(); 292 293 /** 294 * Returns an input stream from the server in the case of an error such as 295 * the requested file has not been found on the remote server. This stream 296 * can be used to read the data the server will send back. 297 * 298 * @return the error input stream returned by the server. 299 */ 300 public java.io.InputStream getErrorStream() { 301 return null; 302 } 303 304 /** 305 * Returns the value of {@code followRedirects} which indicates if this 306 * connection follows a different URL redirected by the server. It is 307 * enabled by default. 308 * 309 * @return the value of the flag. 310 * @see #setFollowRedirects 311 */ 312 public static boolean getFollowRedirects() { 313 return followRedirects; 314 } 315 316 /** 317 * Returns the permission object (in this case {@code SocketPermission}) 318 * with the host and the port number as the target name and {@code 319 * "resolve, connect"} as the action list. If the port number of this URL 320 * instance is lower than {@code 0} the port will be set to {@code 80}. 321 * 322 * @return the permission object required for this connection. 323 * @throws IOException 324 * if an IO exception occurs during the creation of the 325 * permission object. 326 */ 327 @Override 328 public java.security.Permission getPermission() throws IOException { 329 int port = url.getPort(); 330 if (port < 0) { 331 port = 80; 332 } 333 return new SocketPermission(url.getHost() + ":" + port, //$NON-NLS-1$ 334 "connect, resolve"); //$NON-NLS-1$ 335 } 336 337 /** 338 * Returns the request method which will be used to make the request to the 339 * remote HTTP server. All possible methods of this HTTP implementation is 340 * listed in the class definition. 341 * 342 * @return the request method string. 343 * @see #method 344 * @see #setRequestMethod 345 */ 346 public String getRequestMethod() { 347 return method; 348 } 349 350 /** 351 * Returns the response code returned by the remote HTTP server. 352 * 353 * @return the response code, -1 if no valid response code. 354 * @throws IOException 355 * if there is an IO error during the retrieval. 356 * @see #getResponseMessage 357 */ 358 public int getResponseCode() throws IOException { 359 // Call getInputStream() first since getHeaderField() doesn't return 360 // exceptions 361 getInputStream(); 362 String response = getHeaderField(0); 363 if (response == null) { 364 return -1; 365 } 366 response = response.trim(); 367 int mark = response.indexOf(" ") + 1; //$NON-NLS-1$ 368 if (mark == 0) { 369 return -1; 370 } 371 int last = mark + 3; 372 if (last > response.length()) { 373 last = response.length(); 374 } 375 responseCode = Integer.parseInt(response.substring(mark, last)); 376 if (last + 1 <= response.length()) { 377 responseMessage = response.substring(last + 1); 378 } 379 return responseCode; 380 } 381 382 /** 383 * Returns the response message returned by the remote HTTP server. 384 * 385 * @return the response message. {@code null} if no such response exists. 386 * @throws IOException 387 * if there is an error during the retrieval. 388 * @see #getResponseCode() 389 */ 390 public String getResponseMessage() throws IOException { 391 if (responseMessage != null) { 392 return responseMessage; 393 } 394 getResponseCode(); 395 return responseMessage; 396 } 397 398 /** 399 * Sets the flag of whether this connection will follow redirects returned 400 * by the remote server. This method can only be called with the permission 401 * from the security manager. 402 * 403 * @param auto 404 * the value to enable or disable this option. 405 * @see SecurityManager#checkSetFactory() 406 */ 407 public static void setFollowRedirects(boolean auto) { 408 SecurityManager security = System.getSecurityManager(); 409 if (security != null) { 410 security.checkSetFactory(); 411 } 412 followRedirects = auto; 413 } 414 415 /** 416 * Sets the request command which will be sent to the remote HTTP server. 417 * This method can only be called before the connection is made. 418 * 419 * @param method 420 * the string representing the method to be used. 421 * @throws ProtocolException 422 * if this is called after connected, or the method is not 423 * supported by this HTTP implementation. 424 * @see #getRequestMethod() 425 * @see #method 426 */ 427 public void setRequestMethod(String method) throws ProtocolException { 428 if (connected) { 429 throw new ProtocolException(Msg.getString("K0037")); //$NON-NLS-1$ 430 } 431 for (int i = 0; i < methodTokens.length; i++) { 432 if (methodTokens[i].equals(method)) { 433 // if there is a supported method that matches the desired 434 // method, then set the current method and return 435 this.method = methodTokens[i]; 436 return; 437 } 438 } 439 // if none matches, then throw ProtocolException 440 throw new ProtocolException(); 441 } 442 443 /** 444 * Returns whether this connection uses a proxy server or not. 445 * 446 * @return {@code true} if this connection passes a proxy server, false 447 * otherwise. 448 */ 449 public abstract boolean usingProxy(); 450 451 /** 452 * Returns whether this connection follows redirects. 453 * 454 * @return {@code true} if this connection follows redirects, false 455 * otherwise. 456 */ 457 public boolean getInstanceFollowRedirects() { 458 return instanceFollowRedirects; 459 } 460 461 /** 462 * Sets whether this connection follows redirects. 463 * 464 * @param followRedirects 465 * {@code true} if this connection will follows redirects, false 466 * otherwise. 467 */ 468 public void setInstanceFollowRedirects(boolean followRedirects) { 469 instanceFollowRedirects = followRedirects; 470 } 471 472 /** 473 * Returns the date value in milliseconds since {@code 01.01.1970, 00:00h} 474 * corresponding to the header field {@code field}. The {@code defaultValue} 475 * will be returned if no such field can be found in the response header. 476 * 477 * @param field 478 * the header field name. 479 * @param defaultValue 480 * the default value to use if the specified header field wont be 481 * found. 482 * @return the header field represented in milliseconds since January 1, 483 * 1970 GMT. 484 */ 485 @Override 486 public long getHeaderFieldDate(String field, long defaultValue) { 487 return super.getHeaderFieldDate(field, defaultValue); 488 } 489 490 /** 491 * If the length of a HTTP request body is known ahead, sets fixed length to 492 * enable streaming without buffering. Sets after connection will cause an 493 * exception. 494 * 495 * @see #setChunkedStreamingMode 496 * @param contentLength 497 * the fixed length of the HTTP request body. 498 * @throws IllegalStateException 499 * if already connected or an other mode already set. 500 * @throws IllegalArgumentException 501 * if {@code contentLength} is less than zero. 502 */ 503 public void setFixedLengthStreamingMode(int contentLength) { 504 if (super.connected) { 505 throw new IllegalStateException(Msg.getString("K0079")); //$NON-NLS-1$ 506 } 507 if (0 < chunkLength) { 508 throw new IllegalStateException(Msg.getString("KA003")); //$NON-NLS-1$ 509 } 510 if (0 > contentLength) { 511 throw new IllegalArgumentException(Msg.getString("K0051")); //$NON-NLS-1$ 512 } 513 this.fixedContentLength = contentLength; 514 } 515 516 /** 517 * If the length of a HTTP request body is NOT known ahead, enable chunked 518 * transfer encoding to enable streaming with buffering. Notice that not all 519 * http servers support this mode. Sets after connection will cause an 520 * exception. 521 * 522 * @see #setFixedLengthStreamingMode 523 * @param chunklen 524 * the length of a chunk. 525 * @throws IllegalStateException 526 * if already connected or an other mode already set. 527 */ 528 public void setChunkedStreamingMode(int chunklen) { 529 if (super.connected) { 530 throw new IllegalStateException(Msg.getString("K0079")); //$NON-NLS-1$ 531 } 532 if (0 <= fixedContentLength) { 533 throw new IllegalStateException(Msg.getString("KA003")); //$NON-NLS-1$ 534 } 535 if (0 >= chunklen) { 536 chunkLength = DEFAULT_CHUNK_LENGTH; 537 } else { 538 chunkLength = chunklen; 539 } 540 } 541} 542