1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. Oracle designates this 9 * particular file as subject to the "Classpath" exception as provided 10 * by Oracle in the LICENSE file that accompanied this code. 11 * 12 * This code is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * version 2 for more details (a copy is included in the LICENSE file that 16 * accompanied this code). 17 * 18 * You should have received a copy of the GNU General Public License version 19 * 2 along with this work; if not, write to the Free Software Foundation, 20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 * or visit www.oracle.com if you need additional information or have any 24 * questions. 25 */ 26 27package java.net; 28 29import java.io.IOException; 30import java.io.InputStream; 31import java.io.OutputStream; 32import java.util.Hashtable; 33import java.util.Date; 34import java.util.StringTokenizer; 35import java.util.Collections; 36import java.util.Map; 37import java.util.List; 38import java.security.Permission; 39import java.security.AccessController; 40import sun.security.util.SecurityConstants; 41import sun.net.www.MessageHeader; 42 43/** 44 * The abstract class <code>URLConnection</code> is the superclass 45 * of all classes that represent a communications link between the 46 * application and a URL. Instances of this class can be used both to 47 * read from and to write to the resource referenced by the URL. In 48 * general, creating a connection to a URL is a multistep process: 49 * <p> 50 * <center><table border=2 summary="Describes the process of creating a connection to a URL: openConnection() and connect() over time."> 51 * <tr><th><code>openConnection()</code></th> 52 * <th><code>connect()</code></th></tr> 53 * <tr><td>Manipulate parameters that affect the connection to the remote 54 * resource.</td> 55 * <td>Interact with the resource; query header fields and 56 * contents.</td></tr> 57 * </table> 58 * ----------------------------> 59 * <br>time</center> 60 * 61 * <ol> 62 * <li>The connection object is created by invoking the 63 * <code>openConnection</code> method on a URL. 64 * <li>The setup parameters and general request properties are manipulated. 65 * <li>The actual connection to the remote object is made, using the 66 * <code>connect</code> method. 67 * <li>The remote object becomes available. The header fields and the contents 68 * of the remote object can be accessed. 69 * </ol> 70 * <p> 71 * The setup parameters are modified using the following methods: 72 * <ul> 73 * <li><code>setAllowUserInteraction</code> 74 * <li><code>setDoInput</code> 75 * <li><code>setDoOutput</code> 76 * <li><code>setIfModifiedSince</code> 77 * <li><code>setUseCaches</code> 78 * </ul> 79 * <p> 80 * and the general request properties are modified using the method: 81 * <ul> 82 * <li><code>setRequestProperty</code> 83 * </ul> 84 * <p> 85 * Default values for the <code>AllowUserInteraction</code> and 86 * <code>UseCaches</code> parameters can be set using the methods 87 * <code>setDefaultAllowUserInteraction</code> and 88 * <code>setDefaultUseCaches</code>. 89 * <p> 90 * Each of the above <code>set</code> methods has a corresponding 91 * <code>get</code> method to retrieve the value of the parameter or 92 * general request property. The specific parameters and general 93 * request properties that are applicable are protocol specific. 94 * <p> 95 * The following methods are used to access the header fields and 96 * the contents after the connection is made to the remote object: 97 * <ul> 98 * <li><code>getContent</code> 99 * <li><code>getHeaderField</code> 100 * <li><code>getInputStream</code> 101 * <li><code>getOutputStream</code> 102 * </ul> 103 * <p> 104 * Certain header fields are accessed frequently. The methods: 105 * <ul> 106 * <li><code>getContentEncoding</code> 107 * <li><code>getContentLength</code> 108 * <li><code>getContentType</code> 109 * <li><code>getDate</code> 110 * <li><code>getExpiration</code> 111 * <li><code>getLastModifed</code> 112 * </ul> 113 * <p> 114 * provide convenient access to these fields. The 115 * <code>getContentType</code> method is used by the 116 * <code>getContent</code> method to determine the type of the remote 117 * object; subclasses may find it convenient to override the 118 * <code>getContentType</code> method. 119 * <p> 120 * In the common case, all of the pre-connection parameters and 121 * general request properties can be ignored: the pre-connection 122 * parameters and request properties default to sensible values. For 123 * most clients of this interface, there are only two interesting 124 * methods: <code>getInputStream</code> and <code>getContent</code>, 125 * which are mirrored in the <code>URL</code> class by convenience methods. 126 * <p> 127 * More information on the request properties and header fields of 128 * an <code>http</code> connection can be found at: 129 * <blockquote><pre> 130 * <a href="http://www.ietf.org/rfc/rfc2616.txt">http://www.ietf.org/rfc/rfc2616.txt</a> 131 * </pre></blockquote> 132 * 133 * Note about <code>fileNameMap</code>: In versions prior to JDK 1.1.6, 134 * field <code>fileNameMap</code> of <code>URLConnection</code> was public. 135 * In JDK 1.1.6 and later, <code>fileNameMap</code> is private; accessor 136 * and mutator methods {@link #getFileNameMap() getFileNameMap} and 137 * {@link #setFileNameMap(java.net.FileNameMap) setFileNameMap} are added 138 * to access it. This change is also described on the <a href= 139 * "http://java.sun.com/products/jdk/1.2/compatibility.html"> 140 * Compatibility</a> page. 141 * 142 * Invoking the <tt>close()</tt> methods on the <tt>InputStream</tt> or <tt>OutputStream</tt> of an 143 * <tt>URLConnection</tt> after a request may free network resources associated with this 144 * instance, unless particular protocol specifications specify different behaviours 145 * for it. 146 * 147 * @author James Gosling 148 * @see java.net.URL#openConnection() 149 * @see java.net.URLConnection#connect() 150 * @see java.net.URLConnection#getContent() 151 * @see java.net.URLConnection#getContentEncoding() 152 * @see java.net.URLConnection#getContentLength() 153 * @see java.net.URLConnection#getContentType() 154 * @see java.net.URLConnection#getDate() 155 * @see java.net.URLConnection#getExpiration() 156 * @see java.net.URLConnection#getHeaderField(int) 157 * @see java.net.URLConnection#getHeaderField(java.lang.String) 158 * @see java.net.URLConnection#getInputStream() 159 * @see java.net.URLConnection#getLastModified() 160 * @see java.net.URLConnection#getOutputStream() 161 * @see java.net.URLConnection#setAllowUserInteraction(boolean) 162 * @see java.net.URLConnection#setDefaultUseCaches(boolean) 163 * @see java.net.URLConnection#setDoInput(boolean) 164 * @see java.net.URLConnection#setDoOutput(boolean) 165 * @see java.net.URLConnection#setIfModifiedSince(long) 166 * @see java.net.URLConnection#setRequestProperty(java.lang.String, java.lang.String) 167 * @see java.net.URLConnection#setUseCaches(boolean) 168 * @since JDK1.0 169 */ 170public abstract class URLConnection { 171 172 /** 173 * The URL represents the remote object on the World Wide Web to 174 * which this connection is opened. 175 * <p> 176 * The value of this field can be accessed by the 177 * <code>getURL</code> method. 178 * <p> 179 * The default value of this variable is the value of the URL 180 * argument in the <code>URLConnection</code> constructor. 181 * 182 * @see java.net.URLConnection#getURL() 183 * @see java.net.URLConnection#url 184 */ 185 protected URL url; 186 187 /** 188 * This variable is set by the <code>setDoInput</code> method. Its 189 * value is returned by the <code>getDoInput</code> method. 190 * <p> 191 * A URL connection can be used for input and/or output. Setting the 192 * <code>doInput</code> flag to <code>true</code> indicates that 193 * the application intends to read data from the URL connection. 194 * <p> 195 * The default value of this field is <code>true</code>. 196 * 197 * @see java.net.URLConnection#getDoInput() 198 * @see java.net.URLConnection#setDoInput(boolean) 199 */ 200 protected boolean doInput = true; 201 202 /** 203 * This variable is set by the <code>setDoOutput</code> method. Its 204 * value is returned by the <code>getDoOutput</code> method. 205 * <p> 206 * A URL connection can be used for input and/or output. Setting the 207 * <code>doOutput</code> flag to <code>true</code> indicates 208 * that the application intends to write data to the URL connection. 209 * <p> 210 * The default value of this field is <code>false</code>. 211 * 212 * @see java.net.URLConnection#getDoOutput() 213 * @see java.net.URLConnection#setDoOutput(boolean) 214 */ 215 protected boolean doOutput = false; 216 217 private static boolean defaultAllowUserInteraction = false; 218 219 /** 220 * If <code>true</code>, this <code>URL</code> is being examined in 221 * a context in which it makes sense to allow user interactions such 222 * as popping up an authentication dialog. If <code>false</code>, 223 * then no user interaction is allowed. 224 * <p> 225 * The value of this field can be set by the 226 * <code>setAllowUserInteraction</code> method. 227 * Its value is returned by the 228 * <code>getAllowUserInteraction</code> method. 229 * Its default value is the value of the argument in the last invocation 230 * of the <code>setDefaultAllowUserInteraction</code> method. 231 * 232 * @see java.net.URLConnection#getAllowUserInteraction() 233 * @see java.net.URLConnection#setAllowUserInteraction(boolean) 234 * @see java.net.URLConnection#setDefaultAllowUserInteraction(boolean) 235 */ 236 protected boolean allowUserInteraction = defaultAllowUserInteraction; 237 238 private static boolean defaultUseCaches = true; 239 240 /** 241 * If <code>true</code>, the protocol is allowed to use caching 242 * whenever it can. If <code>false</code>, the protocol must always 243 * try to get a fresh copy of the object. 244 * <p> 245 * This field is set by the <code>setUseCaches</code> method. Its 246 * value is returned by the <code>getUseCaches</code> method. 247 * <p> 248 * Its default value is the value given in the last invocation of the 249 * <code>setDefaultUseCaches</code> method. 250 * 251 * @see java.net.URLConnection#setUseCaches(boolean) 252 * @see java.net.URLConnection#getUseCaches() 253 * @see java.net.URLConnection#setDefaultUseCaches(boolean) 254 */ 255 protected boolean useCaches = defaultUseCaches; 256 257 /** 258 * Some protocols support skipping the fetching of the object unless 259 * the object has been modified more recently than a certain time. 260 * <p> 261 * A nonzero value gives a time as the number of milliseconds since 262 * January 1, 1970, GMT. The object is fetched only if it has been 263 * modified more recently than that time. 264 * <p> 265 * This variable is set by the <code>setIfModifiedSince</code> 266 * method. Its value is returned by the 267 * <code>getIfModifiedSince</code> method. 268 * <p> 269 * The default value of this field is <code>0</code>, indicating 270 * that the fetching must always occur. 271 * 272 * @see java.net.URLConnection#getIfModifiedSince() 273 * @see java.net.URLConnection#setIfModifiedSince(long) 274 */ 275 protected long ifModifiedSince = 0; 276 277 /** 278 * If <code>false</code>, this connection object has not created a 279 * communications link to the specified URL. If <code>true</code>, 280 * the communications link has been established. 281 */ 282 protected boolean connected = false; 283 284 /** 285 * @since 1.5 286 */ 287 private int connectTimeout; 288 private int readTimeout; 289 290 /** 291 * @since 1.6 292 */ 293 private MessageHeader requests; 294 295 /** 296 * @since JDK1.1 297 */ 298 private static FileNameMap fileNameMap; 299 300 /** 301 * Loads filename map (a mimetable) from a data file. It will 302 * first try to load the user-specific table, defined 303 * by "content.types.user.table" property. If that fails, 304 * it tries to load the default built-in table at 305 * lib/content-types.properties under java home. 306 * 307 * @return the FileNameMap 308 * @since 1.2 309 * @see #setFileNameMap(java.net.FileNameMap) 310 */ 311 public static synchronized FileNameMap getFileNameMap() { 312 if (fileNameMap == null) { 313 fileNameMap = new DefaultFileNameMap(); 314 } 315 return fileNameMap; 316 } 317 318 /** 319 * Sets the FileNameMap. 320 * <p> 321 * If there is a security manager, this method first calls 322 * the security manager's <code>checkSetFactory</code> method 323 * to ensure the operation is allowed. 324 * This could result in a SecurityException. 325 * 326 * @param map the FileNameMap to be set 327 * @exception SecurityException if a security manager exists and its 328 * <code>checkSetFactory</code> method doesn't allow the operation. 329 * @see SecurityManager#checkSetFactory 330 * @see #getFileNameMap() 331 * @since 1.2 332 */ 333 public static void setFileNameMap(FileNameMap map) { 334 SecurityManager sm = System.getSecurityManager(); 335 if (sm != null) sm.checkSetFactory(); 336 fileNameMap = map; 337 } 338 339 /** 340 * Opens a communications link to the resource referenced by this 341 * URL, if such a connection has not already been established. 342 * <p> 343 * If the <code>connect</code> method is called when the connection 344 * has already been opened (indicated by the <code>connected</code> 345 * field having the value <code>true</code>), the call is ignored. 346 * <p> 347 * URLConnection objects go through two phases: first they are 348 * created, then they are connected. After being created, and 349 * before being connected, various options can be specified 350 * (e.g., doInput and UseCaches). After connecting, it is an 351 * error to try to set them. Operations that depend on being 352 * connected, like getContentLength, will implicitly perform the 353 * connection, if necessary. 354 * 355 * @throws SocketTimeoutException if the timeout expires before 356 * the connection can be established 357 * @exception IOException if an I/O error occurs while opening the 358 * connection. 359 * @see java.net.URLConnection#connected 360 * @see #getConnectTimeout() 361 * @see #setConnectTimeout(int) 362 */ 363 abstract public void connect() throws IOException; 364 365 /** 366 * Sets a specified timeout value, in milliseconds, to be used 367 * when opening a communications link to the resource referenced 368 * by this URLConnection. If the timeout expires before the 369 * connection can be established, a 370 * java.net.SocketTimeoutException is raised. A timeout of zero is 371 * interpreted as an infinite timeout. 372 373 * <p> Some non-standard implmentation of this method may ignore 374 * the specified timeout. To see the connect timeout set, please 375 * call getConnectTimeout(). 376 * 377 * @param timeout an <code>int</code> that specifies the connect 378 * timeout value in milliseconds 379 * @throws IllegalArgumentException if the timeout parameter is negative 380 * 381 * @see #getConnectTimeout() 382 * @see #connect() 383 * @since 1.5 384 */ 385 public void setConnectTimeout(int timeout) { 386 if (timeout < 0) { 387 throw new IllegalArgumentException("timeout can not be negative"); 388 } 389 connectTimeout = timeout; 390 } 391 392 /** 393 * Returns setting for connect timeout. 394 * <p> 395 * 0 return implies that the option is disabled 396 * (i.e., timeout of infinity). 397 * 398 * @return an <code>int</code> that indicates the connect timeout 399 * value in milliseconds 400 * @see #setConnectTimeout(int) 401 * @see #connect() 402 * @since 1.5 403 */ 404 public int getConnectTimeout() { 405 return connectTimeout; 406 } 407 408 /** 409 * Sets the read timeout to a specified timeout, in 410 * milliseconds. A non-zero value specifies the timeout when 411 * reading from Input stream when a connection is established to a 412 * resource. If the timeout expires before there is data available 413 * for read, a java.net.SocketTimeoutException is raised. A 414 * timeout of zero is interpreted as an infinite timeout. 415 * 416 *<p> Some non-standard implementation of this method ignores the 417 * specified timeout. To see the read timeout set, please call 418 * getReadTimeout(). 419 * 420 * @param timeout an <code>int</code> that specifies the timeout 421 * value to be used in milliseconds 422 * @throws IllegalArgumentException if the timeout parameter is negative 423 * 424 * @see #getReadTimeout() 425 * @see InputStream#read() 426 * @since 1.5 427 */ 428 public void setReadTimeout(int timeout) { 429 if (timeout < 0) { 430 throw new IllegalArgumentException("timeout can not be negative"); 431 } 432 readTimeout = timeout; 433 } 434 435 /** 436 * Returns setting for read timeout. 0 return implies that the 437 * option is disabled (i.e., timeout of infinity). 438 * 439 * @return an <code>int</code> that indicates the read timeout 440 * value in milliseconds 441 * 442 * @see #setReadTimeout(int) 443 * @see InputStream#read() 444 * @since 1.5 445 */ 446 public int getReadTimeout() { 447 return readTimeout; 448 } 449 450 /** 451 * Constructs a URL connection to the specified URL. A connection to 452 * the object referenced by the URL is not created. 453 * 454 * @param url the specified URL. 455 */ 456 protected URLConnection(URL url) { 457 this.url = url; 458 } 459 460 /** 461 * Returns the value of this <code>URLConnection</code>'s <code>URL</code> 462 * field. 463 * 464 * @return the value of this <code>URLConnection</code>'s <code>URL</code> 465 * field. 466 * @see java.net.URLConnection#url 467 */ 468 public URL getURL() { 469 return url; 470 } 471 472 /** 473 * Returns the value of the <code>content-length</code> header field. 474 * <P> 475 * <B>Note</B>: {@link #getContentLengthLong() getContentLengthLong()} 476 * should be preferred over this method, since it returns a {@code long} 477 * instead and is therefore more portable.</P> 478 * 479 * @return the content length of the resource that this connection's URL 480 * references, {@code -1} if the content length is not known, 481 * or if the content length is greater than Integer.MAX_VALUE. 482 */ 483 public int getContentLength() { 484 long l = getContentLengthLong(); 485 if (l > Integer.MAX_VALUE) 486 return -1; 487 return (int) l; 488 } 489 490 /** 491 * Returns the value of the <code>content-length</code> header field as a 492 * long. 493 * 494 * @return the content length of the resource that this connection's URL 495 * references, or <code>-1</code> if the content length is 496 * not known. 497 * @since 7.0 498 */ 499 public long getContentLengthLong() { 500 return getHeaderFieldLong("content-length", -1); 501 } 502 503 /** 504 * Returns the value of the <code>content-type</code> header field. 505 * 506 * @return the content type of the resource that the URL references, 507 * or <code>null</code> if not known. 508 * @see java.net.URLConnection#getHeaderField(java.lang.String) 509 */ 510 public String getContentType() { 511 return getHeaderField("content-type"); 512 } 513 514 /** 515 * Returns the value of the <code>content-encoding</code> header field. 516 * 517 * @return the content encoding of the resource that the URL references, 518 * or <code>null</code> if not known. 519 * @see java.net.URLConnection#getHeaderField(java.lang.String) 520 */ 521 public String getContentEncoding() { 522 return getHeaderField("content-encoding"); 523 } 524 525 /** 526 * Returns the value of the <code>expires</code> header field. 527 * 528 * @return the expiration date of the resource that this URL references, 529 * or 0 if not known. The value is the number of milliseconds since 530 * January 1, 1970 GMT. 531 * @see java.net.URLConnection#getHeaderField(java.lang.String) 532 */ 533 public long getExpiration() { 534 return getHeaderFieldDate("expires", 0); 535 } 536 537 /** 538 * Returns the value of the <code>date</code> header field. 539 * 540 * @return the sending date of the resource that the URL references, 541 * or <code>0</code> if not known. The value returned is the 542 * number of milliseconds since January 1, 1970 GMT. 543 * @see java.net.URLConnection#getHeaderField(java.lang.String) 544 */ 545 public long getDate() { 546 return getHeaderFieldDate("date", 0); 547 } 548 549 /** 550 * Returns the value of the <code>last-modified</code> header field. 551 * The result is the number of milliseconds since January 1, 1970 GMT. 552 * 553 * @return the date the resource referenced by this 554 * <code>URLConnection</code> was last modified, or 0 if not known. 555 * @see java.net.URLConnection#getHeaderField(java.lang.String) 556 */ 557 public long getLastModified() { 558 return getHeaderFieldDate("last-modified", 0); 559 } 560 561 /** 562 * Returns the value of the named header field. 563 * <p> 564 * If called on a connection that sets the same header multiple times 565 * with possibly different values, only the last value is returned. 566 * 567 * 568 * @param name the name of a header field. 569 * @return the value of the named header field, or <code>null</code> 570 * if there is no such field in the header. 571 */ 572 public String getHeaderField(String name) { 573 return null; 574 } 575 576 /** 577 * Returns an unmodifiable Map of the header fields. 578 * The Map keys are Strings that represent the 579 * response-header field names. Each Map value is an 580 * unmodifiable List of Strings that represents 581 * the corresponding field values. 582 * 583 * @return a Map of header fields 584 * @since 1.4 585 */ 586 public Map<String,List<String>> getHeaderFields() { 587 return Collections.EMPTY_MAP; 588 } 589 590 /** 591 * Returns the value of the named field parsed as a number. 592 * <p> 593 * This form of <code>getHeaderField</code> exists because some 594 * connection types (e.g., <code>http-ng</code>) have pre-parsed 595 * headers. Classes for that connection type can override this method 596 * and short-circuit the parsing. 597 * 598 * @param name the name of the header field. 599 * @param Default the default value. 600 * @return the value of the named field, parsed as an integer. The 601 * <code>Default</code> value is returned if the field is 602 * missing or malformed. 603 */ 604 public int getHeaderFieldInt(String name, int Default) { 605 String value = getHeaderField(name); 606 try { 607 return Integer.parseInt(value); 608 } catch (Exception e) { } 609 return Default; 610 } 611 612 /** 613 * Returns the value of the named field parsed as a number. 614 * <p> 615 * This form of <code>getHeaderField</code> exists because some 616 * connection types (e.g., <code>http-ng</code>) have pre-parsed 617 * headers. Classes for that connection type can override this method 618 * and short-circuit the parsing. 619 * 620 * @param name the name of the header field. 621 * @param Default the default value. 622 * @return the value of the named field, parsed as a long. The 623 * <code>Default</code> value is returned if the field is 624 * missing or malformed. 625 * @since 7.0 626 */ 627 public long getHeaderFieldLong(String name, long Default) { 628 String value = getHeaderField(name); 629 try { 630 return Long.parseLong(value); 631 } catch (Exception e) { } 632 return Default; 633 } 634 635 /** 636 * Returns the value of the named field parsed as date. 637 * The result is the number of milliseconds since January 1, 1970 GMT 638 * represented by the named field. 639 * <p> 640 * This form of <code>getHeaderField</code> exists because some 641 * connection types (e.g., <code>http-ng</code>) have pre-parsed 642 * headers. Classes for that connection type can override this method 643 * and short-circuit the parsing. 644 * 645 * @param name the name of the header field. 646 * @param Default a default value. 647 * @return the value of the field, parsed as a date. The value of the 648 * <code>Default</code> argument is returned if the field is 649 * missing or malformed. 650 */ 651 public long getHeaderFieldDate(String name, long Default) { 652 String value = getHeaderField(name); 653 try { 654 return Date.parse(value); 655 } catch (Exception e) { } 656 return Default; 657 } 658 659 /** 660 * Returns the key for the <code>n</code><sup>th</sup> header field. 661 * It returns <code>null</code> if there are fewer than <code>n+1</code> fields. 662 * 663 * @param n an index, where n>=0 664 * @return the key for the <code>n</code><sup>th</sup> header field, 665 * or <code>null</code> if there are fewer than <code>n+1</code> 666 * fields. 667 */ 668 public String getHeaderFieldKey(int n) { 669 return null; 670 } 671 672 /** 673 * Returns the value for the <code>n</code><sup>th</sup> header field. 674 * It returns <code>null</code> if there are fewer than 675 * <code>n+1</code>fields. 676 * <p> 677 * This method can be used in conjunction with the 678 * {@link #getHeaderFieldKey(int) getHeaderFieldKey} method to iterate through all 679 * the headers in the message. 680 * 681 * @param n an index, where n>=0 682 * @return the value of the <code>n</code><sup>th</sup> header field 683 * or <code>null</code> if there are fewer than <code>n+1</code> fields 684 * @see java.net.URLConnection#getHeaderFieldKey(int) 685 */ 686 public String getHeaderField(int n) { 687 return null; 688 } 689 690 /** 691 * Retrieves the contents of this URL connection. 692 * <p> 693 * This method first determines the content type of the object by 694 * calling the <code>getContentType</code> method. If this is 695 * the first time that the application has seen that specific content 696 * type, a content handler for that content type is created: 697 * <ol> 698 * <li>If the application has set up a content handler factory instance 699 * using the <code>setContentHandlerFactory</code> method, the 700 * <code>createContentHandler</code> method of that instance is called 701 * with the content type as an argument; the result is a content 702 * handler for that content type. 703 * <li>If no content handler factory has yet been set up, or if the 704 * factory's <code>createContentHandler</code> method returns 705 * <code>null</code>, then the application loads the class named: 706 * <blockquote><pre> 707 * sun.net.www.content.<<i>contentType</i>> 708 * </pre></blockquote> 709 * where <<i>contentType</i>> is formed by taking the 710 * content-type string, replacing all slash characters with a 711 * <code>period</code> ('.'), and all other non-alphanumeric characters 712 * with the underscore character '<code>_</code>'. The alphanumeric 713 * characters are specifically the 26 uppercase ASCII letters 714 * '<code>A</code>' through '<code>Z</code>', the 26 lowercase ASCII 715 * letters '<code>a</code>' through '<code>z</code>', and the 10 ASCII 716 * digits '<code>0</code>' through '<code>9</code>'. If the specified 717 * class does not exist, or is not a subclass of 718 * <code>ContentHandler</code>, then an 719 * <code>UnknownServiceException</code> is thrown. 720 * </ol> 721 * 722 * @return the object fetched. The <code>instanceof</code> operator 723 * should be used to determine the specific kind of object 724 * returned. 725 * @exception IOException if an I/O error occurs while 726 * getting the content. 727 * @exception UnknownServiceException if the protocol does not support 728 * the content type. 729 * @see java.net.ContentHandlerFactory#createContentHandler(java.lang.String) 730 * @see java.net.URLConnection#getContentType() 731 * @see java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory) 732 */ 733 public Object getContent() throws IOException { 734 // Must call getInputStream before GetHeaderField gets called 735 // so that FileNotFoundException has a chance to be thrown up 736 // from here without being caught. 737 getInputStream(); 738 return getContentHandler().getContent(this); 739 } 740 741 /** 742 * Retrieves the contents of this URL connection. 743 * 744 * @param classes the <code>Class</code> array 745 * indicating the requested types 746 * @return the object fetched that is the first match of the type 747 * specified in the classes array. null if none of 748 * the requested types are supported. 749 * The <code>instanceof</code> operator should be used to 750 * determine the specific kind of object returned. 751 * @exception IOException if an I/O error occurs while 752 * getting the content. 753 * @exception UnknownServiceException if the protocol does not support 754 * the content type. 755 * @see java.net.URLConnection#getContent() 756 * @see java.net.ContentHandlerFactory#createContentHandler(java.lang.String) 757 * @see java.net.URLConnection#getContent(java.lang.Class[]) 758 * @see java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory) 759 * @since 1.3 760 */ 761 public Object getContent(Class[] classes) throws IOException { 762 // Must call getInputStream before GetHeaderField gets called 763 // so that FileNotFoundException has a chance to be thrown up 764 // from here without being caught. 765 getInputStream(); 766 return getContentHandler().getContent(this, classes); 767 } 768 769 /** 770 * Returns a permission object representing the permission 771 * necessary to make the connection represented by this 772 * object. This method returns null if no permission is 773 * required to make the connection. By default, this method 774 * returns <code>java.security.AllPermission</code>. Subclasses 775 * should override this method and return the permission 776 * that best represents the permission required to make a 777 * a connection to the URL. For example, a <code>URLConnection</code> 778 * representing a <code>file:</code> URL would return a 779 * <code>java.io.FilePermission</code> object. 780 * 781 * <p>The permission returned may dependent upon the state of the 782 * connection. For example, the permission before connecting may be 783 * different from that after connecting. For example, an HTTP 784 * sever, say foo.com, may redirect the connection to a different 785 * host, say bar.com. Before connecting the permission returned by 786 * the connection will represent the permission needed to connect 787 * to foo.com, while the permission returned after connecting will 788 * be to bar.com. 789 * 790 * <p>Permissions are generally used for two purposes: to protect 791 * caches of objects obtained through URLConnections, and to check 792 * the right of a recipient to learn about a particular URL. In 793 * the first case, the permission should be obtained 794 * <em>after</em> the object has been obtained. For example, in an 795 * HTTP connection, this will represent the permission to connect 796 * to the host from which the data was ultimately fetched. In the 797 * second case, the permission should be obtained and tested 798 * <em>before</em> connecting. 799 * 800 * @return the permission object representing the permission 801 * necessary to make the connection represented by this 802 * URLConnection. 803 * 804 * @exception IOException if the computation of the permission 805 * requires network or file I/O and an exception occurs while 806 * computing it. 807 */ 808 public Permission getPermission() throws IOException { 809 return SecurityConstants.ALL_PERMISSION; 810 } 811 812 /** 813 * Returns an input stream that reads from this open connection. 814 * 815 * A SocketTimeoutException can be thrown when reading from the 816 * returned input stream if the read timeout expires before data 817 * is available for read. 818 * 819 * @return an input stream that reads from this open connection. 820 * @exception IOException if an I/O error occurs while 821 * creating the input stream. 822 * @exception UnknownServiceException if the protocol does not support 823 * input. 824 * @see #setReadTimeout(int) 825 * @see #getReadTimeout() 826 */ 827 public InputStream getInputStream() throws IOException { 828 throw new UnknownServiceException("protocol doesn't support input"); 829 } 830 831 /** 832 * Returns an output stream that writes to this connection. 833 * 834 * @return an output stream that writes to this connection. 835 * @exception IOException if an I/O error occurs while 836 * creating the output stream. 837 * @exception UnknownServiceException if the protocol does not support 838 * output. 839 */ 840 public OutputStream getOutputStream() throws IOException { 841 throw new UnknownServiceException("protocol doesn't support output"); 842 } 843 844 /** 845 * Returns a <code>String</code> representation of this URL connection. 846 * 847 * @return a string representation of this <code>URLConnection</code>. 848 */ 849 public String toString() { 850 return this.getClass().getName() + ":" + url; 851 } 852 853 /** 854 * Sets the value of the <code>doInput</code> field for this 855 * <code>URLConnection</code> to the specified value. 856 * <p> 857 * A URL connection can be used for input and/or output. Set the DoInput 858 * flag to true if you intend to use the URL connection for input, 859 * false if not. The default is true. 860 * 861 * @param doinput the new value. 862 * @throws IllegalStateException if already connected 863 * @see java.net.URLConnection#doInput 864 * @see #getDoInput() 865 */ 866 public void setDoInput(boolean doinput) { 867 if (connected) 868 throw new IllegalStateException("Already connected"); 869 doInput = doinput; 870 } 871 872 /** 873 * Returns the value of this <code>URLConnection</code>'s 874 * <code>doInput</code> flag. 875 * 876 * @return the value of this <code>URLConnection</code>'s 877 * <code>doInput</code> flag. 878 * @see #setDoInput(boolean) 879 */ 880 public boolean getDoInput() { 881 return doInput; 882 } 883 884 /** 885 * Sets the value of the <code>doOutput</code> field for this 886 * <code>URLConnection</code> to the specified value. 887 * <p> 888 * A URL connection can be used for input and/or output. Set the DoOutput 889 * flag to true if you intend to use the URL connection for output, 890 * false if not. The default is false. 891 * 892 * @param dooutput the new value. 893 * @throws IllegalStateException if already connected 894 * @see #getDoOutput() 895 */ 896 public void setDoOutput(boolean dooutput) { 897 if (connected) 898 throw new IllegalStateException("Already connected"); 899 doOutput = dooutput; 900 } 901 902 /** 903 * Returns the value of this <code>URLConnection</code>'s 904 * <code>doOutput</code> flag. 905 * 906 * @return the value of this <code>URLConnection</code>'s 907 * <code>doOutput</code> flag. 908 * @see #setDoOutput(boolean) 909 */ 910 public boolean getDoOutput() { 911 return doOutput; 912 } 913 914 /** 915 * Set the value of the <code>allowUserInteraction</code> field of 916 * this <code>URLConnection</code>. 917 * 918 * @param allowuserinteraction the new value. 919 * @throws IllegalStateException if already connected 920 * @see #getAllowUserInteraction() 921 */ 922 public void setAllowUserInteraction(boolean allowuserinteraction) { 923 if (connected) 924 throw new IllegalStateException("Already connected"); 925 allowUserInteraction = allowuserinteraction; 926 } 927 928 /** 929 * Returns the value of the <code>allowUserInteraction</code> field for 930 * this object. 931 * 932 * @return the value of the <code>allowUserInteraction</code> field for 933 * this object. 934 * @see #setAllowUserInteraction(boolean) 935 */ 936 public boolean getAllowUserInteraction() { 937 return allowUserInteraction; 938 } 939 940 /** 941 * Sets the default value of the 942 * <code>allowUserInteraction</code> field for all future 943 * <code>URLConnection</code> objects to the specified value. 944 * 945 * @param defaultallowuserinteraction the new value. 946 * @see #getDefaultAllowUserInteraction() 947 */ 948 public static void setDefaultAllowUserInteraction(boolean defaultallowuserinteraction) { 949 defaultAllowUserInteraction = defaultallowuserinteraction; 950 } 951 952 /** 953 * Returns the default value of the <code>allowUserInteraction</code> 954 * field. 955 * <p> 956 * Ths default is "sticky", being a part of the static state of all 957 * URLConnections. This flag applies to the next, and all following 958 * URLConnections that are created. 959 * 960 * @return the default value of the <code>allowUserInteraction</code> 961 * field. 962 * @see #setDefaultAllowUserInteraction(boolean) 963 */ 964 public static boolean getDefaultAllowUserInteraction() { 965 return defaultAllowUserInteraction; 966 } 967 968 /** 969 * Sets the value of the <code>useCaches</code> field of this 970 * <code>URLConnection</code> to the specified value. 971 * <p> 972 * Some protocols do caching of documents. Occasionally, it is important 973 * to be able to "tunnel through" and ignore the caches (e.g., the 974 * "reload" button in a browser). If the UseCaches flag on a connection 975 * is true, the connection is allowed to use whatever caches it can. 976 * If false, caches are to be ignored. 977 * The default value comes from DefaultUseCaches, which defaults to 978 * true. 979 * 980 * @param usecaches a <code>boolean</code> indicating whether 981 * or not to allow caching 982 * @throws IllegalStateException if already connected 983 * @see #getUseCaches() 984 */ 985 public void setUseCaches(boolean usecaches) { 986 if (connected) 987 throw new IllegalStateException("Already connected"); 988 useCaches = usecaches; 989 } 990 991 /** 992 * Returns the value of this <code>URLConnection</code>'s 993 * <code>useCaches</code> field. 994 * 995 * @return the value of this <code>URLConnection</code>'s 996 * <code>useCaches</code> field. 997 * @see #setUseCaches(boolean) 998 */ 999 public boolean getUseCaches() { 1000 return useCaches; 1001 } 1002 1003 /** 1004 * Sets the value of the <code>ifModifiedSince</code> field of 1005 * this <code>URLConnection</code> to the specified value. 1006 * 1007 * @param ifmodifiedsince the new value. 1008 * @throws IllegalStateException if already connected 1009 * @see #getIfModifiedSince() 1010 */ 1011 public void setIfModifiedSince(long ifmodifiedsince) { 1012 if (connected) 1013 throw new IllegalStateException("Already connected"); 1014 ifModifiedSince = ifmodifiedsince; 1015 } 1016 1017 /** 1018 * Returns the value of this object's <code>ifModifiedSince</code> field. 1019 * 1020 * @return the value of this object's <code>ifModifiedSince</code> field. 1021 * @see #setIfModifiedSince(long) 1022 */ 1023 public long getIfModifiedSince() { 1024 return ifModifiedSince; 1025 } 1026 1027 /** 1028 * Returns the default value of a <code>URLConnection</code>'s 1029 * <code>useCaches</code> flag. 1030 * <p> 1031 * Ths default is "sticky", being a part of the static state of all 1032 * URLConnections. This flag applies to the next, and all following 1033 * URLConnections that are created. 1034 * 1035 * @return the default value of a <code>URLConnection</code>'s 1036 * <code>useCaches</code> flag. 1037 * @see #setDefaultUseCaches(boolean) 1038 */ 1039 public boolean getDefaultUseCaches() { 1040 return defaultUseCaches; 1041 } 1042 1043 /** 1044 * Sets the default value of the <code>useCaches</code> field to the 1045 * specified value. 1046 * 1047 * @param defaultusecaches the new value. 1048 * @see #getDefaultUseCaches() 1049 */ 1050 public void setDefaultUseCaches(boolean defaultusecaches) { 1051 defaultUseCaches = defaultusecaches; 1052 } 1053 1054 /** 1055 * Sets the general request property. If a property with the key already 1056 * exists, overwrite its value with the new value. 1057 * 1058 * <p> NOTE: HTTP requires all request properties which can 1059 * legally have multiple instances with the same key 1060 * to use a comma-seperated list syntax which enables multiple 1061 * properties to be appended into a single property. 1062 * 1063 * @param key the keyword by which the request is known 1064 * (e.g., "<code>Accept</code>"). 1065 * @param value the value associated with it. 1066 * @throws IllegalStateException if already connected 1067 * @throws NullPointerException if key is <CODE>null</CODE> 1068 * @see #getRequestProperty(java.lang.String) 1069 */ 1070 public void setRequestProperty(String key, String value) { 1071 if (connected) 1072 throw new IllegalStateException("Already connected"); 1073 if (key == null) 1074 throw new NullPointerException ("key is null"); 1075 1076 if (requests == null) 1077 requests = new MessageHeader(); 1078 1079 requests.set(key, value); 1080 } 1081 1082 /** 1083 * Adds a general request property specified by a 1084 * key-value pair. This method will not overwrite 1085 * existing values associated with the same key. 1086 * 1087 * @param key the keyword by which the request is known 1088 * (e.g., "<code>Accept</code>"). 1089 * @param value the value associated with it. 1090 * @throws IllegalStateException if already connected 1091 * @throws NullPointerException if key is null 1092 * @see #getRequestProperties() 1093 * @since 1.4 1094 */ 1095 public void addRequestProperty(String key, String value) { 1096 if (connected) 1097 throw new IllegalStateException("Already connected"); 1098 if (key == null) 1099 throw new NullPointerException ("key is null"); 1100 1101 if (requests == null) 1102 requests = new MessageHeader(); 1103 1104 requests.add(key, value); 1105 } 1106 1107 1108 /** 1109 * Returns the value of the named general request property for this 1110 * connection. 1111 * 1112 * @param key the keyword by which the request is known (e.g., "Accept"). 1113 * @return the value of the named general request property for this 1114 * connection. If key is null, then null is returned. 1115 * @throws IllegalStateException if already connected 1116 * @see #setRequestProperty(java.lang.String, java.lang.String) 1117 */ 1118 public String getRequestProperty(String key) { 1119 if (connected) 1120 throw new IllegalStateException("Already connected"); 1121 1122 if (requests == null) 1123 return null; 1124 1125 return requests.findValue(key); 1126 } 1127 1128 /** 1129 * Returns an unmodifiable Map of general request 1130 * properties for this connection. The Map keys 1131 * are Strings that represent the request-header 1132 * field names. Each Map value is a unmodifiable List 1133 * of Strings that represents the corresponding 1134 * field values. 1135 * 1136 * @return a Map of the general request properties for this connection. 1137 * @throws IllegalStateException if already connected 1138 * @since 1.4 1139 */ 1140 public Map<String,List<String>> getRequestProperties() { 1141 if (connected) 1142 throw new IllegalStateException("Already connected"); 1143 1144 if (requests == null) 1145 return Collections.EMPTY_MAP; 1146 1147 return requests.getHeaders(null); 1148 } 1149 1150 /** 1151 * Sets the default value of a general request property. When a 1152 * <code>URLConnection</code> is created, it is initialized with 1153 * these properties. 1154 * 1155 * @param key the keyword by which the request is known 1156 * (e.g., "<code>Accept</code>"). 1157 * @param value the value associated with the key. 1158 * 1159 * @see java.net.URLConnection#setRequestProperty(java.lang.String,java.lang.String) 1160 * 1161 * @deprecated The instance specific setRequestProperty method 1162 * should be used after an appropriate instance of URLConnection 1163 * is obtained. Invoking this method will have no effect. 1164 * 1165 * @see #getDefaultRequestProperty(java.lang.String) 1166 */ 1167 @Deprecated 1168 public static void setDefaultRequestProperty(String key, String value) { 1169 } 1170 1171 /** 1172 * Returns the value of the default request property. Default request 1173 * properties are set for every connection. 1174 * 1175 * @param key the keyword by which the request is known (e.g., "Accept"). 1176 * @return the value of the default request property 1177 * for the specified key. 1178 * 1179 * @see java.net.URLConnection#getRequestProperty(java.lang.String) 1180 * 1181 * @deprecated The instance specific getRequestProperty method 1182 * should be used after an appropriate instance of URLConnection 1183 * is obtained. 1184 * 1185 * @see #setDefaultRequestProperty(java.lang.String, java.lang.String) 1186 */ 1187 @Deprecated 1188 public static String getDefaultRequestProperty(String key) { 1189 return null; 1190 } 1191 1192 /** 1193 * The ContentHandler factory. 1194 */ 1195 static ContentHandlerFactory factory; 1196 1197 /** 1198 * Sets the <code>ContentHandlerFactory</code> of an 1199 * application. It can be called at most once by an application. 1200 * <p> 1201 * The <code>ContentHandlerFactory</code> instance is used to 1202 * construct a content handler from a content type 1203 * <p> 1204 * If there is a security manager, this method first calls 1205 * the security manager's <code>checkSetFactory</code> method 1206 * to ensure the operation is allowed. 1207 * This could result in a SecurityException. 1208 * 1209 * @param fac the desired factory. 1210 * @exception Error if the factory has already been defined. 1211 * @exception SecurityException if a security manager exists and its 1212 * <code>checkSetFactory</code> method doesn't allow the operation. 1213 * @see java.net.ContentHandlerFactory 1214 * @see java.net.URLConnection#getContent() 1215 * @see SecurityManager#checkSetFactory 1216 */ 1217 public static synchronized void setContentHandlerFactory(ContentHandlerFactory fac) { 1218 if (factory != null) { 1219 throw new Error("factory already defined"); 1220 } 1221 SecurityManager security = System.getSecurityManager(); 1222 if (security != null) { 1223 security.checkSetFactory(); 1224 } 1225 factory = fac; 1226 } 1227 1228 private static Hashtable handlers = new Hashtable(); 1229 1230 /** 1231 * Gets the Content Handler appropriate for this connection. 1232 * @param connection the connection to use. 1233 */ 1234 synchronized ContentHandler getContentHandler() 1235 throws IOException 1236 { 1237 String contentType = stripOffParameters(getContentType()); 1238 ContentHandler handler = null; 1239 if (contentType == null) { 1240 if ((contentType = guessContentTypeFromName(url.getFile())) == null) { 1241 contentType = guessContentTypeFromStream(getInputStream()); 1242 } 1243 } 1244 1245 if (contentType == null) { 1246 return UnknownContentHandler.INSTANCE; 1247 } 1248 try { 1249 handler = (ContentHandler) handlers.get(contentType); 1250 if (handler != null) 1251 return handler; 1252 } catch(Exception e) { 1253 } 1254 1255 if (factory != null) 1256 handler = factory.createContentHandler(contentType); 1257 if (handler == null) { 1258 try { 1259 handler = lookupContentHandlerClassFor(contentType); 1260 } catch(Exception e) { 1261 e.printStackTrace(); 1262 handler = UnknownContentHandler.INSTANCE; 1263 } 1264 handlers.put(contentType, handler); 1265 } 1266 return handler; 1267 } 1268 1269 /* 1270 * Media types are in the format: type/subtype*(; parameter). 1271 * For looking up the content handler, we should ignore those 1272 * parameters. 1273 */ 1274 private String stripOffParameters(String contentType) 1275 { 1276 if (contentType == null) 1277 return null; 1278 int index = contentType.indexOf(';'); 1279 1280 if (index > 0) 1281 return contentType.substring(0, index); 1282 else 1283 return contentType; 1284 } 1285 1286 private static final String contentClassPrefix = "sun.net.www.content"; 1287 private static final String contentPathProp = "java.content.handler.pkgs"; 1288 1289 /** 1290 * Looks for a content handler in a user-defineable set of places. 1291 * By default it looks in sun.net.www.content, but users can define a 1292 * vertical-bar delimited set of class prefixes to search through in 1293 * addition by defining the java.content.handler.pkgs property. 1294 * The class name must be of the form: 1295 * <pre> 1296 * {package-prefix}.{major}.{minor} 1297 * e.g. 1298 * YoyoDyne.experimental.text.plain 1299 * </pre> 1300 */ 1301 private ContentHandler lookupContentHandlerClassFor(String contentType) 1302 throws InstantiationException, IllegalAccessException, ClassNotFoundException { 1303 String contentHandlerClassName = typeToPackageName(contentType); 1304 1305 String contentHandlerPkgPrefixes =getContentHandlerPkgPrefixes(); 1306 1307 StringTokenizer packagePrefixIter = 1308 new StringTokenizer(contentHandlerPkgPrefixes, "|"); 1309 1310 while (packagePrefixIter.hasMoreTokens()) { 1311 String packagePrefix = packagePrefixIter.nextToken().trim(); 1312 1313 try { 1314 String clsName = packagePrefix + "." + contentHandlerClassName; 1315 Class cls = null; 1316 try { 1317 cls = Class.forName(clsName); 1318 } catch (ClassNotFoundException e) { 1319 ClassLoader cl = ClassLoader.getSystemClassLoader(); 1320 if (cl != null) { 1321 cls = cl.loadClass(clsName); 1322 } 1323 } 1324 if (cls != null) { 1325 ContentHandler handler = 1326 (ContentHandler)cls.newInstance(); 1327 return handler; 1328 } 1329 } catch(Exception e) { 1330 } 1331 } 1332 1333 return UnknownContentHandler.INSTANCE; 1334 } 1335 1336 /** 1337 * Utility function to map a MIME content type into an equivalent 1338 * pair of class name components. For example: "text/html" would 1339 * be returned as "text.html" 1340 */ 1341 private String typeToPackageName(String contentType) { 1342 // make sure we canonicalize the class name: all lower case 1343 contentType = contentType.toLowerCase(); 1344 int len = contentType.length(); 1345 char nm[] = new char[len]; 1346 contentType.getChars(0, len, nm, 0); 1347 for (int i = 0; i < len; i++) { 1348 char c = nm[i]; 1349 if (c == '/') { 1350 nm[i] = '.'; 1351 } else if (!('A' <= c && c <= 'Z' || 1352 'a' <= c && c <= 'z' || 1353 '0' <= c && c <= '9')) { 1354 nm[i] = '_'; 1355 } 1356 } 1357 return new String(nm); 1358 } 1359 1360 1361 /** 1362 * Returns a vertical bar separated list of package prefixes for potential 1363 * content handlers. Tries to get the java.content.handler.pkgs property 1364 * to use as a set of package prefixes to search. Whether or not 1365 * that property has been defined, the sun.net.www.content is always 1366 * the last one on the returned package list. 1367 */ 1368 private String getContentHandlerPkgPrefixes() { 1369 String packagePrefixList = AccessController.doPrivileged( 1370 new sun.security.action.GetPropertyAction(contentPathProp, "")); 1371 1372 if (packagePrefixList != "") { 1373 packagePrefixList += "|"; 1374 } 1375 1376 return packagePrefixList + contentClassPrefix; 1377 } 1378 1379 /** 1380 * Tries to determine the content type of an object, based 1381 * on the specified "file" component of a URL. 1382 * This is a convenience method that can be used by 1383 * subclasses that override the <code>getContentType</code> method. 1384 * 1385 * @param fname a filename. 1386 * @return a guess as to what the content type of the object is, 1387 * based upon its file name. 1388 * @see java.net.URLConnection#getContentType() 1389 */ 1390 public static String guessContentTypeFromName(String fname) { 1391 return getFileNameMap().getContentTypeFor(fname); 1392 } 1393 1394 /** 1395 * Tries to determine the type of an input stream based on the 1396 * characters at the beginning of the input stream. This method can 1397 * be used by subclasses that override the 1398 * <code>getContentType</code> method. 1399 * <p> 1400 * Ideally, this routine would not be needed. But many 1401 * <code>http</code> servers return the incorrect content type; in 1402 * addition, there are many nonstandard extensions. Direct inspection 1403 * of the bytes to determine the content type is often more accurate 1404 * than believing the content type claimed by the <code>http</code> server. 1405 * 1406 * @param is an input stream that supports marks. 1407 * @return a guess at the content type, or <code>null</code> if none 1408 * can be determined. 1409 * @exception IOException if an I/O error occurs while reading the 1410 * input stream. 1411 * @see java.io.InputStream#mark(int) 1412 * @see java.io.InputStream#markSupported() 1413 * @see java.net.URLConnection#getContentType() 1414 */ 1415 static public String guessContentTypeFromStream(InputStream is) 1416 throws IOException { 1417 // If we can't read ahead safely, just give up on guessing 1418 if (!is.markSupported()) 1419 return null; 1420 1421 is.mark(16); 1422 int c1 = is.read(); 1423 int c2 = is.read(); 1424 int c3 = is.read(); 1425 int c4 = is.read(); 1426 int c5 = is.read(); 1427 int c6 = is.read(); 1428 int c7 = is.read(); 1429 int c8 = is.read(); 1430 int c9 = is.read(); 1431 int c10 = is.read(); 1432 int c11 = is.read(); 1433 int c12 = is.read(); 1434 int c13 = is.read(); 1435 int c14 = is.read(); 1436 int c15 = is.read(); 1437 int c16 = is.read(); 1438 is.reset(); 1439 1440 if (c1 == 0xCA && c2 == 0xFE && c3 == 0xBA && c4 == 0xBE) { 1441 return "application/java-vm"; 1442 } 1443 1444 if (c1 == 0xAC && c2 == 0xED) { 1445 // next two bytes are version number, currently 0x00 0x05 1446 return "application/x-java-serialized-object"; 1447 } 1448 1449 if (c1 == '<') { 1450 if (c2 == '!' 1451 || ((c2 == 'h' && (c3 == 't' && c4 == 'm' && c5 == 'l' || 1452 c3 == 'e' && c4 == 'a' && c5 == 'd') || 1453 (c2 == 'b' && c3 == 'o' && c4 == 'd' && c5 == 'y'))) || 1454 ((c2 == 'H' && (c3 == 'T' && c4 == 'M' && c5 == 'L' || 1455 c3 == 'E' && c4 == 'A' && c5 == 'D') || 1456 (c2 == 'B' && c3 == 'O' && c4 == 'D' && c5 == 'Y')))) { 1457 return "text/html"; 1458 } 1459 1460 if (c2 == '?' && c3 == 'x' && c4 == 'm' && c5 == 'l' && c6 == ' ') { 1461 return "application/xml"; 1462 } 1463 } 1464 1465 // big and little (identical) endian UTF-8 encodings, with BOM 1466 if (c1 == 0xef && c2 == 0xbb && c3 == 0xbf) { 1467 if (c4 == '<' && c5 == '?' && c6 == 'x') { 1468 return "application/xml"; 1469 } 1470 } 1471 1472 // big and little endian UTF-16 encodings, with byte order mark 1473 if (c1 == 0xfe && c2 == 0xff) { 1474 if (c3 == 0 && c4 == '<' && c5 == 0 && c6 == '?' && 1475 c7 == 0 && c8 == 'x') { 1476 return "application/xml"; 1477 } 1478 } 1479 1480 if (c1 == 0xff && c2 == 0xfe) { 1481 if (c3 == '<' && c4 == 0 && c5 == '?' && c6 == 0 && 1482 c7 == 'x' && c8 == 0) { 1483 return "application/xml"; 1484 } 1485 } 1486 1487 // big and little endian UTF-32 encodings, with BOM 1488 if (c1 == 0x00 && c2 == 0x00 && c3 == 0xfe && c4 == 0xff) { 1489 if (c5 == 0 && c6 == 0 && c7 == 0 && c8 == '<' && 1490 c9 == 0 && c10 == 0 && c11 == 0 && c12 == '?' && 1491 c13 == 0 && c14 == 0 && c15 == 0 && c16 == 'x') { 1492 return "application/xml"; 1493 } 1494 } 1495 1496 if (c1 == 0xff && c2 == 0xfe && c3 == 0x00 && c4 == 0x00) { 1497 if (c5 == '<' && c6 == 0 && c7 == 0 && c8 == 0 && 1498 c9 == '?' && c10 == 0 && c11 == 0 && c12 == 0 && 1499 c13 == 'x' && c14 == 0 && c15 == 0 && c16 == 0) { 1500 return "application/xml"; 1501 } 1502 } 1503 1504 if (c1 == 'G' && c2 == 'I' && c3 == 'F' && c4 == '8') { 1505 return "image/gif"; 1506 } 1507 1508 if (c1 == '#' && c2 == 'd' && c3 == 'e' && c4 == 'f') { 1509 return "image/x-bitmap"; 1510 } 1511 1512 if (c1 == '!' && c2 == ' ' && c3 == 'X' && c4 == 'P' && 1513 c5 == 'M' && c6 == '2') { 1514 return "image/x-pixmap"; 1515 } 1516 1517 if (c1 == 137 && c2 == 80 && c3 == 78 && 1518 c4 == 71 && c5 == 13 && c6 == 10 && 1519 c7 == 26 && c8 == 10) { 1520 return "image/png"; 1521 } 1522 1523 if (c1 == 0xFF && c2 == 0xD8 && c3 == 0xFF) { 1524 if (c4 == 0xE0) { 1525 return "image/jpeg"; 1526 } 1527 1528 /** 1529 * File format used by digital cameras to store images. 1530 * Exif Format can be read by any application supporting 1531 * JPEG. Exif Spec can be found at: 1532 * http://www.pima.net/standards/it10/PIMA15740/Exif_2-1.PDF 1533 */ 1534 if ((c4 == 0xE1) && 1535 (c7 == 'E' && c8 == 'x' && c9 == 'i' && c10 =='f' && 1536 c11 == 0)) { 1537 return "image/jpeg"; 1538 } 1539 1540 if (c4 == 0xEE) { 1541 return "image/jpg"; 1542 } 1543 } 1544 1545 if (c1 == 0xD0 && c2 == 0xCF && c3 == 0x11 && c4 == 0xE0 && 1546 c5 == 0xA1 && c6 == 0xB1 && c7 == 0x1A && c8 == 0xE1) { 1547 1548 /* Above is signature of Microsoft Structured Storage. 1549 * Below this, could have tests for various SS entities. 1550 * For now, just test for FlashPix. 1551 */ 1552 if (checkfpx(is)) { 1553 return "image/vnd.fpx"; 1554 } 1555 } 1556 1557 if (c1 == 0x2E && c2 == 0x73 && c3 == 0x6E && c4 == 0x64) { 1558 return "audio/basic"; // .au format, big endian 1559 } 1560 1561 if (c1 == 0x64 && c2 == 0x6E && c3 == 0x73 && c4 == 0x2E) { 1562 return "audio/basic"; // .au format, little endian 1563 } 1564 1565 if (c1 == 'R' && c2 == 'I' && c3 == 'F' && c4 == 'F') { 1566 /* I don't know if this is official but evidence 1567 * suggests that .wav files start with "RIFF" - brown 1568 */ 1569 return "audio/x-wav"; 1570 } 1571 return null; 1572 } 1573 1574 /** 1575 * Check for FlashPix image data in InputStream is. Return true if 1576 * the stream has FlashPix data, false otherwise. Before calling this 1577 * method, the stream should have already been checked to be sure it 1578 * contains Microsoft Structured Storage data. 1579 */ 1580 static private boolean checkfpx(InputStream is) throws IOException { 1581 1582 /* Test for FlashPix image data in Microsoft Structured Storage format. 1583 * In general, should do this with calls to an SS implementation. 1584 * Lacking that, need to dig via offsets to get to the FlashPix 1585 * ClassID. Details: 1586 * 1587 * Offset to Fpx ClsID from beginning of stream should be: 1588 * 1589 * FpxClsidOffset = rootEntryOffset + clsidOffset 1590 * 1591 * where: clsidOffset = 0x50. 1592 * rootEntryOffset = headerSize + sectorSize*sectDirStart 1593 * + 128*rootEntryDirectory 1594 * 1595 * where: headerSize = 0x200 (always) 1596 * sectorSize = 2 raised to power of uSectorShift, 1597 * which is found in the header at 1598 * offset 0x1E. 1599 * sectDirStart = found in the header at offset 0x30. 1600 * rootEntryDirectory = in general, should search for 1601 * directory labelled as root. 1602 * We will assume value of 0 (i.e., 1603 * rootEntry is in first directory) 1604 */ 1605 1606 // Mark the stream so we can reset it. 0x100 is enough for the first 1607 // few reads, but the mark will have to be reset and set again once 1608 // the offset to the root directory entry is computed. That offset 1609 // can be very large and isn't know until the stream has been read from 1610 is.mark(0x100); 1611 1612 // Get the byte ordering located at 0x1E. 0xFE is Intel, 1613 // 0xFF is other 1614 long toSkip = (long)0x1C; 1615 long posn; 1616 1617 if ((posn = skipForward(is, toSkip)) < toSkip) { 1618 is.reset(); 1619 return false; 1620 } 1621 1622 int c[] = new int[16]; 1623 if (readBytes(c, 2, is) < 0) { 1624 is.reset(); 1625 return false; 1626 } 1627 1628 int byteOrder = c[0]; 1629 1630 posn+=2; 1631 int uSectorShift; 1632 if (readBytes(c, 2, is) < 0) { 1633 is.reset(); 1634 return false; 1635 } 1636 1637 if(byteOrder == 0xFE) { 1638 uSectorShift = c[0]; 1639 uSectorShift += c[1] << 8; 1640 } 1641 else { 1642 uSectorShift = c[0] << 8; 1643 uSectorShift += c[1]; 1644 } 1645 1646 posn += 2; 1647 toSkip = (long)0x30 - posn; 1648 long skipped = 0; 1649 if ((skipped = skipForward(is, toSkip)) < toSkip) { 1650 is.reset(); 1651 return false; 1652 } 1653 posn += skipped; 1654 1655 if (readBytes(c, 4, is) < 0) { 1656 is.reset(); 1657 return false; 1658 } 1659 1660 int sectDirStart; 1661 if(byteOrder == 0xFE) { 1662 sectDirStart = c[0]; 1663 sectDirStart += c[1] << 8; 1664 sectDirStart += c[2] << 16; 1665 sectDirStart += c[3] << 24; 1666 } else { 1667 sectDirStart = c[0] << 24; 1668 sectDirStart += c[1] << 16; 1669 sectDirStart += c[2] << 8; 1670 sectDirStart += c[3]; 1671 } 1672 posn += 4; 1673 is.reset(); // Reset back to the beginning 1674 1675 toSkip = 0x200L + (long)(1<<uSectorShift)*sectDirStart + 0x50L; 1676 1677 // Sanity check! 1678 if (toSkip < 0) { 1679 return false; 1680 } 1681 1682 /* 1683 * How far can we skip? Is there any performance problem here? 1684 * This skip can be fairly long, at least 0x4c650 in at least 1685 * one case. Have to assume that the skip will fit in an int. 1686 * Leave room to read whole root dir 1687 */ 1688 is.mark((int)toSkip+0x30); 1689 1690 if ((skipForward(is, toSkip)) < toSkip) { 1691 is.reset(); 1692 return false; 1693 } 1694 1695 /* should be at beginning of ClassID, which is as follows 1696 * (in Intel byte order): 1697 * 00 67 61 56 54 C1 CE 11 85 53 00 AA 00 A1 F9 5B 1698 * 1699 * This is stored from Windows as long,short,short,char[8] 1700 * so for byte order changes, the order only changes for 1701 * the first 8 bytes in the ClassID. 1702 * 1703 * Test against this, ignoring second byte (Intel) since 1704 * this could change depending on part of Fpx file we have. 1705 */ 1706 1707 if (readBytes(c, 16, is) < 0) { 1708 is.reset(); 1709 return false; 1710 } 1711 1712 // intel byte order 1713 if (byteOrder == 0xFE && 1714 c[0] == 0x00 && c[2] == 0x61 && c[3] == 0x56 && 1715 c[4] == 0x54 && c[5] == 0xC1 && c[6] == 0xCE && 1716 c[7] == 0x11 && c[8] == 0x85 && c[9] == 0x53 && 1717 c[10]== 0x00 && c[11]== 0xAA && c[12]== 0x00 && 1718 c[13]== 0xA1 && c[14]== 0xF9 && c[15]== 0x5B) { 1719 is.reset(); 1720 return true; 1721 } 1722 1723 // non-intel byte order 1724 else if (c[3] == 0x00 && c[1] == 0x61 && c[0] == 0x56 && 1725 c[5] == 0x54 && c[4] == 0xC1 && c[7] == 0xCE && 1726 c[6] == 0x11 && c[8] == 0x85 && c[9] == 0x53 && 1727 c[10]== 0x00 && c[11]== 0xAA && c[12]== 0x00 && 1728 c[13]== 0xA1 && c[14]== 0xF9 && c[15]== 0x5B) { 1729 is.reset(); 1730 return true; 1731 } 1732 is.reset(); 1733 return false; 1734 } 1735 1736 /** 1737 * Tries to read the specified number of bytes from the stream 1738 * Returns -1, If EOF is reached before len bytes are read, returns 0 1739 * otherwise 1740 */ 1741 static private int readBytes(int c[], int len, InputStream is) 1742 throws IOException { 1743 1744 byte buf[] = new byte[len]; 1745 if (is.read(buf, 0, len) < len) { 1746 return -1; 1747 } 1748 1749 // fill the passed in int array 1750 for (int i = 0; i < len; i++) { 1751 c[i] = buf[i] & 0xff; 1752 } 1753 return 0; 1754 } 1755 1756 1757 /** 1758 * Skips through the specified number of bytes from the stream 1759 * until either EOF is reached, or the specified 1760 * number of bytes have been skipped 1761 */ 1762 static private long skipForward(InputStream is, long toSkip) 1763 throws IOException { 1764 1765 long eachSkip = 0; 1766 long skipped = 0; 1767 1768 while (skipped != toSkip) { 1769 eachSkip = is.skip(toSkip - skipped); 1770 1771 // check if EOF is reached 1772 if (eachSkip <= 0) { 1773 if (is.read() == -1) { 1774 return skipped ; 1775 } else { 1776 skipped++; 1777 } 1778 } 1779 skipped += eachSkip; 1780 } 1781 return skipped; 1782 } 1783 1784} 1785 1786 1787class UnknownContentHandler extends ContentHandler { 1788 static final ContentHandler INSTANCE = new UnknownContentHandler(); 1789 1790 public Object getContent(URLConnection uc) throws IOException { 1791 return uc.getInputStream(); 1792 } 1793} 1794