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