1 /* 2 * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.net; 27 28 import java.io.IOException; 29 import java.io.InputStream; 30 import java.io.OutputStream; 31 import java.util.Hashtable; 32 import java.util.Date; 33 import java.util.StringTokenizer; 34 import java.util.Collections; 35 import java.util.Map; 36 import java.util.List; 37 import java.security.Permission; 38 import java.security.AccessController; 39 import sun.security.util.SecurityConstants; 40 import sun.net.www.MessageHeader; 41 42 /** 43 * The abstract class {@code URLConnection} is the superclass 44 * of all classes that represent a communications link between the 45 * application and a URL. Instances of this class can be used both to 46 * read from and to write to the resource referenced by the URL. In 47 * general, creating a connection to a URL is a multistep process: 48 * 49 * <center><table border=2 summary="Describes the process of creating a connection to a URL: openConnection() and connect() over time."> 50 * <tr><th>{@code openConnection()}</th> 51 * <th>{@code connect()}</th></tr> 52 * <tr><td>Manipulate parameters that affect the connection to the remote 53 * resource.</td> 54 * <td>Interact with the resource; query header fields and 55 * contents.</td></tr> 56 * </table> 57 * ----------------------------> 58 * <br>time</center> 59 * 60 * <ol> 61 * <li>The connection object is created by invoking the 62 * {@code openConnection} method on a URL. 63 * <li>The setup parameters and general request properties are manipulated. 64 * <li>The actual connection to the remote object is made, using the 65 * {@code connect} method. 66 * <li>The remote object becomes available. The header fields and the contents 67 * of the remote object can be accessed. 68 * </ol> 69 * <p> 70 * The setup parameters are modified using the following methods: 71 * <ul> 72 * <li>{@code setAllowUserInteraction} 73 * <li>{@code setDoInput} 74 * <li>{@code setDoOutput} 75 * <li>{@code setIfModifiedSince} 76 * <li>{@code setUseCaches} 77 * </ul> 78 * <p> 79 * and the general request properties are modified using the method: 80 * <ul> 81 * <li>{@code setRequestProperty} 82 * </ul> 83 * <p> 84 * Default values for the {@code AllowUserInteraction} and 85 * {@code UseCaches} parameters can be set using the methods 86 * {@code setDefaultAllowUserInteraction} and 87 * {@code setDefaultUseCaches}. 88 * <p> 89 * Each of the above {@code set} methods has a corresponding 90 * {@code get} method to retrieve the value of the parameter or 91 * general request property. The specific parameters and general 92 * request properties that are applicable are protocol specific. 93 * <p> 94 * The following methods are used to access the header fields and 95 * the contents after the connection is made to the remote object: 96 * <ul> 97 * <li>{@code getContent} 98 * <li>{@code getHeaderField} 99 * <li>{@code getInputStream} 100 * <li>{@code getOutputStream} 101 * </ul> 102 * <p> 103 * Certain header fields are accessed frequently. The methods: 104 * <ul> 105 * <li>{@code getContentEncoding} 106 * <li>{@code getContentLength} 107 * <li>{@code getContentType} 108 * <li>{@code getDate} 109 * <li>{@code getExpiration} 110 * <li>{@code getLastModifed} 111 * </ul> 112 * <p> 113 * provide convenient access to these fields. The 114 * {@code getContentType} method is used by the 115 * {@code getContent} method to determine the type of the remote 116 * object; subclasses may find it convenient to override the 117 * {@code getContentType} method. 118 * <p> 119 * In the common case, all of the pre-connection parameters and 120 * general request properties can be ignored: the pre-connection 121 * parameters and request properties default to sensible values. For 122 * most clients of this interface, there are only two interesting 123 * methods: {@code getInputStream} and {@code getContent}, 124 * which are mirrored in the {@code URL} class by convenience methods. 125 * <p> 126 * More information on the request properties and header fields of 127 * an {@code http} connection can be found at: 128 * <blockquote><pre> 129 * <a href="http://www.ietf.org/rfc/rfc2616.txt">http://www.ietf.org/rfc/rfc2616.txt</a> 130 * </pre></blockquote> 131 * 132 * Invoking the {@code close()} methods on the {@code InputStream} or {@code OutputStream} of an 133 * {@code URLConnection} after a request may free network resources associated with this 134 * instance, unless particular protocol specifications specify different behaviours 135 * for it. 136 * 137 * @author James Gosling 138 * @see java.net.URL#openConnection() 139 * @see java.net.URLConnection#connect() 140 * @see java.net.URLConnection#getContent() 141 * @see java.net.URLConnection#getContentEncoding() 142 * @see java.net.URLConnection#getContentLength() 143 * @see java.net.URLConnection#getContentType() 144 * @see java.net.URLConnection#getDate() 145 * @see java.net.URLConnection#getExpiration() 146 * @see java.net.URLConnection#getHeaderField(int) 147 * @see java.net.URLConnection#getHeaderField(java.lang.String) 148 * @see java.net.URLConnection#getInputStream() 149 * @see java.net.URLConnection#getLastModified() 150 * @see java.net.URLConnection#getOutputStream() 151 * @see java.net.URLConnection#setAllowUserInteraction(boolean) 152 * @see java.net.URLConnection#setDefaultUseCaches(boolean) 153 * @see java.net.URLConnection#setDoInput(boolean) 154 * @see java.net.URLConnection#setDoOutput(boolean) 155 * @see java.net.URLConnection#setIfModifiedSince(long) 156 * @see java.net.URLConnection#setRequestProperty(java.lang.String, java.lang.String) 157 * @see java.net.URLConnection#setUseCaches(boolean) 158 * @since JDK1.0 159 */ 160 public abstract class URLConnection { 161 162 /** 163 * The URL represents the remote object on the World Wide Web to 164 * which this connection is opened. 165 * <p> 166 * The value of this field can be accessed by the 167 * {@code getURL} method. 168 * <p> 169 * The default value of this variable is the value of the URL 170 * argument in the {@code URLConnection} constructor. 171 * 172 * @see java.net.URLConnection#getURL() 173 * @see java.net.URLConnection#url 174 */ 175 protected URL url; 176 177 /** 178 * This variable is set by the {@code setDoInput} method. Its 179 * value is returned by the {@code getDoInput} method. 180 * <p> 181 * A URL connection can be used for input and/or output. Setting the 182 * {@code doInput} flag to {@code true} indicates that 183 * the application intends to read data from the URL connection. 184 * <p> 185 * The default value of this field is {@code true}. 186 * 187 * @see java.net.URLConnection#getDoInput() 188 * @see java.net.URLConnection#setDoInput(boolean) 189 */ 190 protected boolean doInput = true; 191 192 /** 193 * This variable is set by the {@code setDoOutput} method. Its 194 * value is returned by the {@code getDoOutput} method. 195 * <p> 196 * A URL connection can be used for input and/or output. Setting the 197 * {@code doOutput} flag to {@code true} indicates 198 * that the application intends to write data to the URL connection. 199 * <p> 200 * The default value of this field is {@code false}. 201 * 202 * @see java.net.URLConnection#getDoOutput() 203 * @see java.net.URLConnection#setDoOutput(boolean) 204 */ 205 protected boolean doOutput = false; 206 207 private static boolean defaultAllowUserInteraction = false; 208 209 /** 210 * If {@code true}, this {@code URL} is being examined in 211 * a context in which it makes sense to allow user interactions such 212 * as popping up an authentication dialog. If {@code false}, 213 * then no user interaction is allowed. 214 * <p> 215 * The value of this field can be set by the 216 * {@code setAllowUserInteraction} method. 217 * Its value is returned by the 218 * {@code getAllowUserInteraction} method. 219 * Its default value is the value of the argument in the last invocation 220 * of the {@code setDefaultAllowUserInteraction} method. 221 * 222 * @see java.net.URLConnection#getAllowUserInteraction() 223 * @see java.net.URLConnection#setAllowUserInteraction(boolean) 224 * @see java.net.URLConnection#setDefaultAllowUserInteraction(boolean) 225 */ 226 protected boolean allowUserInteraction = defaultAllowUserInteraction; 227 228 private static boolean defaultUseCaches = true; 229 230 /** 231 * If {@code true}, the protocol is allowed to use caching 232 * whenever it can. If {@code false}, the protocol must always 233 * try to get a fresh copy of the object. 234 * <p> 235 * This field is set by the {@code setUseCaches} method. Its 236 * value is returned by the {@code getUseCaches} method. 237 * <p> 238 * Its default value is the value given in the last invocation of the 239 * {@code setDefaultUseCaches} method. 240 * 241 * @see java.net.URLConnection#setUseCaches(boolean) 242 * @see java.net.URLConnection#getUseCaches() 243 * @see java.net.URLConnection#setDefaultUseCaches(boolean) 244 */ 245 protected boolean useCaches = defaultUseCaches; 246 247 /** 248 * Some protocols support skipping the fetching of the object unless 249 * the object has been modified more recently than a certain time. 250 * <p> 251 * A nonzero value gives a time as the number of milliseconds since 252 * January 1, 1970, GMT. The object is fetched only if it has been 253 * modified more recently than that time. 254 * <p> 255 * This variable is set by the {@code setIfModifiedSince} 256 * method. Its value is returned by the 257 * {@code getIfModifiedSince} method. 258 * <p> 259 * The default value of this field is {@code 0}, indicating 260 * that the fetching must always occur. 261 * 262 * @see java.net.URLConnection#getIfModifiedSince() 263 * @see java.net.URLConnection#setIfModifiedSince(long) 264 */ 265 protected long ifModifiedSince = 0; 266 267 /** 268 * If {@code false}, this connection object has not created a 269 * communications link to the specified URL. If {@code true}, 270 * the communications link has been established. 271 */ 272 protected boolean connected = false; 273 274 /** 275 * @since 1.5 276 */ 277 private int connectTimeout; 278 private int readTimeout; 279 280 /** 281 * @since 1.6 282 */ 283 private MessageHeader requests; 284 285 /** 286 * @since JDK1.1 287 */ 288 private static volatile FileNameMap fileNameMap; 289 290 /** 291 * Loads filename map (a mimetable) from a data file. It will 292 * first try to load the user-specific table, defined 293 * by "content.types.user.table" property. If that fails, 294 * it tries to load the default built-in table. 295 * 296 * @return the FileNameMap 297 * @since 1.2 298 * @see #setFileNameMap(java.net.FileNameMap) 299 */ 300 public static FileNameMap getFileNameMap() { 301 FileNameMap map = fileNameMap; 302 303 if (map == null) { 304 fileNameMap = map = new FileNameMap() { 305 private FileNameMap internalMap = 306 sun.net.www.MimeTable.loadTable(); 307 308 public String getContentTypeFor(String fileName) { 309 return internalMap.getContentTypeFor(fileName); 310 } 311 }; 312 } 313 314 return map; 315 } 316 317 /** 318 * Sets the FileNameMap. 319 * <p> 320 * If there is a security manager, this method first calls 321 * the security manager's {@code checkSetFactory} method 322 * to ensure the operation is allowed. 323 * This could result in a SecurityException. 324 * 325 * @param map the FileNameMap to be set 326 * @exception SecurityException if a security manager exists and its 327 * {@code checkSetFactory} method doesn't allow the operation. 328 * @see SecurityManager#checkSetFactory 329 * @see #getFileNameMap() 330 * @since 1.2 331 */ 332 public static void setFileNameMap(FileNameMap map) { 333 SecurityManager sm = System.getSecurityManager(); 334 if (sm != null) sm.checkSetFactory(); 335 fileNameMap = map; 336 } 337 338 /** 339 * Opens a communications link to the resource referenced by this 340 * URL, if such a connection has not already been established. 341 * <p> 342 * If the {@code connect} method is called when the connection 343 * has already been opened (indicated by the {@code connected} 344 * field having the value {@code true}), the call is ignored. 345 * <p> 346 * URLConnection objects go through two phases: first they are 347 * created, then they are connected. After being created, and 348 * before being connected, various options can be specified 349 * (e.g., doInput and UseCaches). After connecting, it is an 350 * error to try to set them. Operations that depend on being 351 * connected, like getContentLength, will implicitly perform the 352 * connection, if necessary. 353 * 354 * @throws SocketTimeoutException if the timeout expires before 355 * the connection can be established 356 * @exception IOException if an I/O error occurs while opening the 357 * connection. 358 * @see java.net.URLConnection#connected 359 * @see #getConnectTimeout() 360 * @see #setConnectTimeout(int) 361 */ 362 abstract public void connect() throws IOException; 363 364 /** 365 * Sets a specified timeout value, in milliseconds, to be used 366 * when opening a communications link to the resource referenced 367 * by this URLConnection. If the timeout expires before the 368 * connection can be established, a 369 * java.net.SocketTimeoutException is raised. A timeout of zero is 370 * interpreted as an infinite timeout. 371 372 * <p> Some non-standard implementation of this method may ignore 373 * the specified timeout. To see the connect timeout set, please 374 * call getConnectTimeout(). 375 * 376 * @param timeout an {@code int} that specifies the connect 377 * timeout value in milliseconds 378 * @throws IllegalArgumentException if the timeout parameter is negative 379 * 380 * @see #getConnectTimeout() 381 * @see #connect() 382 * @since 1.5 383 */ 384 public void setConnectTimeout(int timeout) { 385 if (timeout < 0) { 386 throw new IllegalArgumentException("timeout can not be negative"); 387 } 388 connectTimeout = timeout; 389 } 390 391 /** 392 * Returns setting for connect timeout. 393 * <p> 394 * 0 return implies that the option is disabled 395 * (i.e., timeout of infinity). 396 * 397 * @return an {@code int} that indicates the connect timeout 398 * value in milliseconds 399 * @see #setConnectTimeout(int) 400 * @see #connect() 401 * @since 1.5 402 */ 403 public int getConnectTimeout() { 404 return connectTimeout; 405 } 406 407 /** 408 * Sets the read timeout to a specified timeout, in 409 * milliseconds. A non-zero value specifies the timeout when 410 * reading from Input stream when a connection is established to a 411 * resource. If the timeout expires before there is data available 412 * for read, a java.net.SocketTimeoutException is raised. A 413 * timeout of zero is interpreted as an infinite timeout. 414 * 415 *<p> Some non-standard implementation of this method ignores the 416 * specified timeout. To see the read timeout set, please call 417 * getReadTimeout(). 418 * 419 * @param timeout an {@code int} that specifies the timeout 420 * value to be used in milliseconds 421 * @throws IllegalArgumentException if the timeout parameter is negative 422 * 423 * @see #getReadTimeout() 424 * @see InputStream#read() 425 * @since 1.5 426 */ 427 public void setReadTimeout(int timeout) { 428 if (timeout < 0) { 429 throw new IllegalArgumentException("timeout can not be negative"); 430 } 431 readTimeout = timeout; 432 } 433 434 /** 435 * Returns setting for read timeout. 0 return implies that the 436 * option is disabled (i.e., timeout of infinity). 437 * 438 * @return an {@code int} that indicates the read timeout 439 * value in milliseconds 440 * 441 * @see #setReadTimeout(int) 442 * @see InputStream#read() 443 * @since 1.5 444 */ 445 public int getReadTimeout() { 446 return readTimeout; 447 } 448 449 /** 450 * Constructs a URL connection to the specified URL. A connection to 451 * the object referenced by the URL is not created. 452 * 453 * @param url the specified URL. 454 */ 455 protected URLConnection(URL url) { 456 this.url = url; 457 } 458 459 /** 460 * Returns the value of this {@code URLConnection}'s {@code URL} 461 * field. 462 * 463 * @return the value of this {@code URLConnection}'s {@code URL} 464 * field. 465 * @see java.net.URLConnection#url 466 */ 467 public URL getURL() { 468 return url; 469 } 470 471 /** 472 * Returns the value of the {@code content-length} header field. 473 * <P> 474 * <B>Note</B>: {@link #getContentLengthLong() getContentLengthLong()} 475 * should be preferred over this method, since it returns a {@code long} 476 * instead and is therefore more portable.</P> 477 * 478 * @return the content length of the resource that this connection's URL 479 * references, {@code -1} if the content length is not known, 480 * or if the content length is greater than Integer.MAX_VALUE. 481 */ 482 public int getContentLength() { 483 long l = getContentLengthLong(); 484 if (l > Integer.MAX_VALUE) 485 return -1; 486 return (int) l; 487 } 488 489 /** 490 * Returns the value of the {@code content-length} header field as a 491 * long. 492 * 493 * @return the content length of the resource that this connection's URL 494 * references, or {@code -1} if the content length is 495 * not known. 496 * @since 7.0 497 */ 498 public long getContentLengthLong() { 499 return getHeaderFieldLong("content-length", -1); 500 } 501 502 /** 503 * Returns the value of the {@code content-type} header field. 504 * 505 * @return the content type of the resource that the URL references, 506 * or {@code null} if not known. 507 * @see java.net.URLConnection#getHeaderField(java.lang.String) 508 */ 509 public String getContentType() { 510 return getHeaderField("content-type"); 511 } 512 513 /** 514 * Returns the value of the {@code content-encoding} header field. 515 * 516 * @return the content encoding of the resource that the URL references, 517 * or {@code null} if not known. 518 * @see java.net.URLConnection#getHeaderField(java.lang.String) 519 */ 520 public String getContentEncoding() { 521 return getHeaderField("content-encoding"); 522 } 523 524 /** 525 * Returns the value of the {@code expires} header field. 526 * 527 * @return the expiration date of the resource that this URL references, 528 * or 0 if not known. The value is the number of milliseconds since 529 * January 1, 1970 GMT. 530 * @see java.net.URLConnection#getHeaderField(java.lang.String) 531 */ 532 public long getExpiration() { 533 return getHeaderFieldDate("expires", 0); 534 } 535 536 /** 537 * Returns the value of the {@code date} header field. 538 * 539 * @return the sending date of the resource that the URL references, 540 * or {@code 0} if not known. The value returned is the 541 * number of milliseconds since January 1, 1970 GMT. 542 * @see java.net.URLConnection#getHeaderField(java.lang.String) 543 */ 544 public long getDate() { 545 return getHeaderFieldDate("date", 0); 546 } 547 548 /** 549 * Returns the value of the {@code last-modified} header field. 550 * The result is the number of milliseconds since January 1, 1970 GMT. 551 * 552 * @return the date the resource referenced by this 553 * {@code URLConnection} was last modified, or 0 if not known. 554 * @see java.net.URLConnection#getHeaderField(java.lang.String) 555 */ 556 public long getLastModified() { 557 return getHeaderFieldDate("last-modified", 0); 558 } 559 560 /** 561 * Returns the value of the named header field. 562 * <p> 563 * If called on a connection that sets the same header multiple times 564 * with possibly different values, only the last value is returned. 565 * 566 * 567 * @param name the name of a header field. 568 * @return the value of the named header field, or {@code null} 569 * if there is no such field in the header. 570 */ 571 public String getHeaderField(String name) { 572 return null; 573 } 574 575 /** 576 * Returns an unmodifiable Map of the header fields. 577 * The Map keys are Strings that represent the 578 * response-header field names. Each Map value is an 579 * unmodifiable List of Strings that represents 580 * the corresponding field values. 581 * 582 * @return a Map of header fields 583 * @since 1.4 584 */ 585 public Map<String,List<String>> getHeaderFields() { 586 return Collections.emptyMap(); 587 } 588 589 /** 590 * Returns the value of the named field parsed as a number. 591 * <p> 592 * This form of {@code getHeaderField} exists because some 593 * connection types (e.g., {@code http-ng}) have pre-parsed 594 * headers. Classes for that connection type can override this method 595 * and short-circuit the parsing. 596 * 597 * @param name the name of the header field. 598 * @param Default the default value. 599 * @return the value of the named field, parsed as an integer. The 600 * {@code Default} value is returned if the field is 601 * missing or malformed. 602 */ 603 public int getHeaderFieldInt(String name, int Default) { 604 String value = getHeaderField(name); 605 try { 606 return Integer.parseInt(value); 607 } catch (Exception e) { } 608 return Default; 609 } 610 611 /** 612 * Returns the value of the named field parsed as a number. 613 * <p> 614 * This form of {@code getHeaderField} exists because some 615 * connection types (e.g., {@code http-ng}) have pre-parsed 616 * headers. Classes for that connection type can override this method 617 * and short-circuit the parsing. 618 * 619 * @param name the name of the header field. 620 * @param Default the default value. 621 * @return the value of the named field, parsed as a long. The 622 * {@code Default} value is returned if the field is 623 * missing or malformed. 624 * @since 7.0 625 */ 626 public long getHeaderFieldLong(String name, long Default) { 627 String value = getHeaderField(name); 628 try { 629 return Long.parseLong(value); 630 } catch (Exception e) { } 631 return Default; 632 } 633 634 /** 635 * Returns the value of the named field parsed as date. 636 * The result is the number of milliseconds since January 1, 1970 GMT 637 * represented by the named field. 638 * <p> 639 * This form of {@code getHeaderField} exists because some 640 * connection types (e.g., {@code http-ng}) have pre-parsed 641 * headers. Classes for that connection type can override this method 642 * and short-circuit the parsing. 643 * 644 * @param name the name of the header field. 645 * @param Default a default value. 646 * @return the value of the field, parsed as a date. The value of the 647 * {@code Default} argument is returned if the field is 648 * missing or malformed. 649 */ 650 @SuppressWarnings("deprecation") 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}<sup>th</sup> header field. 661 * It returns {@code null} if there are fewer than {@code n+1} fields. 662 * 663 * @param n an index, where {@code n>=0} 664 * @return the key for the {@code n}<sup>th</sup> header field, 665 * or {@code null} if there are fewer than {@code n+1} 666 * fields. 667 */ 668 public String getHeaderFieldKey(int n) { 669 return null; 670 } 671 672 /** 673 * Returns the value for the {@code n}<sup>th</sup> header field. 674 * It returns {@code null} if there are fewer than 675 * {@code n+1}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 {@code n>=0} 682 * @return the value of the {@code n}<sup>th</sup> header field 683 * or {@code null} if there are fewer than {@code n+1} 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} 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} method, the 700 * {@code createContentHandler} 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} method returns 705 * {@code null}, 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} ('.'), and all other non-alphanumeric characters 712 * with the underscore character '{@code _}'. The alphanumeric 713 * characters are specifically the 26 uppercase ASCII letters 714 * '{@code A}' through '{@code Z}', the 26 lowercase ASCII 715 * letters '{@code a}' through '{@code z}', and the 10 ASCII 716 * digits '{@code 0}' through '{@code 9}'. If the specified 717 * class does not exist, or is not a subclass of 718 * {@code ContentHandler}, then an 719 * {@code UnknownServiceException} is thrown. 720 * </ol> 721 * 722 * @return the object fetched. The {@code instanceof} 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} 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} 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}. 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} 778 * representing a {@code file:} URL would return a 779 * {@code java.io.FilePermission} 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} representation of this URL connection. 846 * 847 * @return a string representation of this {@code URLConnection}. 848 */ 849 public String toString() { 850 return this.getClass().getName() + ":" + url; 851 } 852 853 /** 854 * Sets the value of the {@code doInput} field for this 855 * {@code URLConnection} 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}'s 874 * {@code doInput} flag. 875 * 876 * @return the value of this {@code URLConnection}'s 877 * {@code doInput} flag. 878 * @see #setDoInput(boolean) 879 */ 880 public boolean getDoInput() { 881 return doInput; 882 } 883 884 /** 885 * Sets the value of the {@code doOutput} field for this 886 * {@code URLConnection} 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}'s 904 * {@code doOutput} flag. 905 * 906 * @return the value of this {@code URLConnection}'s 907 * {@code doOutput} flag. 908 * @see #setDoOutput(boolean) 909 */ 910 public boolean getDoOutput() { 911 return doOutput; 912 } 913 914 /** 915 * Set the value of the {@code allowUserInteraction} field of 916 * this {@code URLConnection}. 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} field for 930 * this object. 931 * 932 * @return the value of the {@code allowUserInteraction} 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} field for all future 943 * {@code URLConnection} 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} 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} 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} field of this 970 * {@code URLConnection} 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} 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}'s 993 * {@code useCaches} field. 994 * 995 * @return the value of this {@code URLConnection}'s 996 * {@code useCaches} field. 997 * @see #setUseCaches(boolean) 998 */ 999 public boolean getUseCaches() { 1000 return useCaches; 1001 } 1002 1003 /** 1004 * Sets the value of the {@code ifModifiedSince} field of 1005 * this {@code URLConnection} 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} field. 1019 * 1020 * @return the value of this object's {@code ifModifiedSince} 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}'s 1029 * {@code useCaches} 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}'s 1036 * {@code useCaches} 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} 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-separated 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}"). 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}"). 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.emptyMap(); 1146 1147 return requests.getHeaders(null); 1148 } 1149 1150 /** 1151 * Sets the default value of a general request property. When a 1152 * {@code URLConnection} 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}"). 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} of an 1199 * application. It can be called at most once by an application. 1200 * <p> 1201 * The {@code ContentHandlerFactory} 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} 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} 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<String, ContentHandler> handlers = new Hashtable<>(); 1229 1230 /** 1231 * Gets the Content Handler appropriate for this connection. 1232 */ 1233 synchronized ContentHandler getContentHandler() 1234 throws UnknownServiceException 1235 { 1236 String contentType = stripOffParameters(getContentType()); 1237 ContentHandler handler = null; 1238 if (contentType == null) 1239 throw new UnknownServiceException("no content-type"); 1240 try { 1241 handler = handlers.get(contentType); 1242 if (handler != null) 1243 return handler; 1244 } catch(Exception e) { 1245 } 1246 1247 if (factory != null) 1248 handler = factory.createContentHandler(contentType); 1249 if (handler == null) { 1250 try { 1251 handler = lookupContentHandlerClassFor(contentType); 1252 } catch(Exception e) { 1253 e.printStackTrace(); 1254 handler = UnknownContentHandler.INSTANCE; 1255 } 1256 handlers.put(contentType, handler); 1257 } 1258 return handler; 1259 } 1260 1261 /* 1262 * Media types are in the format: type/subtype*(; parameter). 1263 * For looking up the content handler, we should ignore those 1264 * parameters. 1265 */ 1266 private String stripOffParameters(String contentType) 1267 { 1268 if (contentType == null) 1269 return null; 1270 int index = contentType.indexOf(';'); 1271 1272 if (index > 0) 1273 return contentType.substring(0, index); 1274 else 1275 return contentType; 1276 } 1277 1278 private static final String contentClassPrefix = "sun.net.www.content"; 1279 private static final String contentPathProp = "java.content.handler.pkgs"; 1280 1281 /** 1282 * Looks for a content handler in a user-defineable set of places. 1283 * By default it looks in sun.net.www.content, but users can define a 1284 * vertical-bar delimited set of class prefixes to search through in 1285 * addition by defining the java.content.handler.pkgs property. 1286 * The class name must be of the form: 1287 * <pre> 1288 * {package-prefix}.{major}.{minor} 1289 * e.g. 1290 * YoyoDyne.experimental.text.plain 1291 * </pre> 1292 */ 1293 private ContentHandler lookupContentHandlerClassFor(String contentType) 1294 throws InstantiationException, IllegalAccessException, ClassNotFoundException { 1295 String contentHandlerClassName = typeToPackageName(contentType); 1296 1297 String contentHandlerPkgPrefixes =getContentHandlerPkgPrefixes(); 1298 1299 StringTokenizer packagePrefixIter = 1300 new StringTokenizer(contentHandlerPkgPrefixes, "|"); 1301 1302 while (packagePrefixIter.hasMoreTokens()) { 1303 String packagePrefix = packagePrefixIter.nextToken().trim(); 1304 1305 try { 1306 String clsName = packagePrefix + "." + contentHandlerClassName; 1307 Class<?> cls = null; 1308 try { 1309 cls = Class.forName(clsName); 1310 } catch (ClassNotFoundException e) { 1311 ClassLoader cl = ClassLoader.getSystemClassLoader(); 1312 if (cl != null) { 1313 cls = cl.loadClass(clsName); 1314 } 1315 } 1316 if (cls != null) { 1317 ContentHandler handler = 1318 (ContentHandler)cls.newInstance(); 1319 return handler; 1320 } 1321 } catch(Exception e) { 1322 } 1323 } 1324 1325 return UnknownContentHandler.INSTANCE; 1326 } 1327 1328 /** 1329 * Utility function to map a MIME content type into an equivalent 1330 * pair of class name components. For example: "text/html" would 1331 * be returned as "text.html" 1332 */ 1333 private String typeToPackageName(String contentType) { 1334 // make sure we canonicalize the class name: all lower case 1335 contentType = contentType.toLowerCase(); 1336 int len = contentType.length(); 1337 char nm[] = new char[len]; 1338 contentType.getChars(0, len, nm, 0); 1339 for (int i = 0; i < len; i++) { 1340 char c = nm[i]; 1341 if (c == '/') { 1342 nm[i] = '.'; 1343 } else if (!('A' <= c && c <= 'Z' || 1344 'a' <= c && c <= 'z' || 1345 '0' <= c && c <= '9')) { 1346 nm[i] = '_'; 1347 } 1348 } 1349 return new String(nm); 1350 } 1351 1352 1353 /** 1354 * Returns a vertical bar separated list of package prefixes for potential 1355 * content handlers. Tries to get the java.content.handler.pkgs property 1356 * to use as a set of package prefixes to search. Whether or not 1357 * that property has been defined, the sun.net.www.content is always 1358 * the last one on the returned package list. 1359 */ 1360 private String getContentHandlerPkgPrefixes() { 1361 String packagePrefixList = AccessController.doPrivileged( 1362 new sun.security.action.GetPropertyAction(contentPathProp, "")); 1363 1364 if (packagePrefixList != "") { 1365 packagePrefixList += "|"; 1366 } 1367 1368 return packagePrefixList + contentClassPrefix; 1369 } 1370 1371 /** 1372 * Tries to determine the content type of an object, based 1373 * on the specified "file" component of a URL. 1374 * This is a convenience method that can be used by 1375 * subclasses that override the {@code getContentType} method. 1376 * 1377 * @param fname a filename. 1378 * @return a guess as to what the content type of the object is, 1379 * based upon its file name. 1380 * @see java.net.URLConnection#getContentType() 1381 */ 1382 public static String guessContentTypeFromName(String fname) { 1383 return getFileNameMap().getContentTypeFor(fname); 1384 } 1385 1386 /** 1387 * Tries to determine the type of an input stream based on the 1388 * characters at the beginning of the input stream. This method can 1389 * be used by subclasses that override the 1390 * {@code getContentType} method. 1391 * <p> 1392 * Ideally, this routine would not be needed. But many 1393 * {@code http} servers return the incorrect content type; in 1394 * addition, there are many nonstandard extensions. Direct inspection 1395 * of the bytes to determine the content type is often more accurate 1396 * than believing the content type claimed by the {@code http} server. 1397 * 1398 * @param is an input stream that supports marks. 1399 * @return a guess at the content type, or {@code null} if none 1400 * can be determined. 1401 * @exception IOException if an I/O error occurs while reading the 1402 * input stream. 1403 * @see java.io.InputStream#mark(int) 1404 * @see java.io.InputStream#markSupported() 1405 * @see java.net.URLConnection#getContentType() 1406 */ 1407 static public String guessContentTypeFromStream(InputStream is) 1408 throws IOException { 1409 // If we can't read ahead safely, just give up on guessing 1410 if (!is.markSupported()) 1411 return null; 1412 1413 is.mark(16); 1414 int c1 = is.read(); 1415 int c2 = is.read(); 1416 int c3 = is.read(); 1417 int c4 = is.read(); 1418 int c5 = is.read(); 1419 int c6 = is.read(); 1420 int c7 = is.read(); 1421 int c8 = is.read(); 1422 int c9 = is.read(); 1423 int c10 = is.read(); 1424 int c11 = is.read(); 1425 int c12 = is.read(); 1426 int c13 = is.read(); 1427 int c14 = is.read(); 1428 int c15 = is.read(); 1429 int c16 = is.read(); 1430 is.reset(); 1431 1432 if (c1 == 0xCA && c2 == 0xFE && c3 == 0xBA && c4 == 0xBE) { 1433 return "application/java-vm"; 1434 } 1435 1436 if (c1 == 0xAC && c2 == 0xED) { 1437 // next two bytes are version number, currently 0x00 0x05 1438 return "application/x-java-serialized-object"; 1439 } 1440 1441 if (c1 == '<') { 1442 if (c2 == '!' 1443 || ((c2 == 'h' && (c3 == 't' && c4 == 'm' && c5 == 'l' || 1444 c3 == 'e' && c4 == 'a' && c5 == 'd') || 1445 (c2 == 'b' && c3 == 'o' && c4 == 'd' && c5 == 'y'))) || 1446 ((c2 == 'H' && (c3 == 'T' && c4 == 'M' && c5 == 'L' || 1447 c3 == 'E' && c4 == 'A' && c5 == 'D') || 1448 (c2 == 'B' && c3 == 'O' && c4 == 'D' && c5 == 'Y')))) { 1449 return "text/html"; 1450 } 1451 1452 if (c2 == '?' && c3 == 'x' && c4 == 'm' && c5 == 'l' && c6 == ' ') { 1453 return "application/xml"; 1454 } 1455 } 1456 1457 // big and little (identical) endian UTF-8 encodings, with BOM 1458 if (c1 == 0xef && c2 == 0xbb && c3 == 0xbf) { 1459 if (c4 == '<' && c5 == '?' && c6 == 'x') { 1460 return "application/xml"; 1461 } 1462 } 1463 1464 // big and little endian UTF-16 encodings, with byte order mark 1465 if (c1 == 0xfe && c2 == 0xff) { 1466 if (c3 == 0 && c4 == '<' && c5 == 0 && c6 == '?' && 1467 c7 == 0 && c8 == 'x') { 1468 return "application/xml"; 1469 } 1470 } 1471 1472 if (c1 == 0xff && c2 == 0xfe) { 1473 if (c3 == '<' && c4 == 0 && c5 == '?' && c6 == 0 && 1474 c7 == 'x' && c8 == 0) { 1475 return "application/xml"; 1476 } 1477 } 1478 1479 // big and little endian UTF-32 encodings, with BOM 1480 if (c1 == 0x00 && c2 == 0x00 && c3 == 0xfe && c4 == 0xff) { 1481 if (c5 == 0 && c6 == 0 && c7 == 0 && c8 == '<' && 1482 c9 == 0 && c10 == 0 && c11 == 0 && c12 == '?' && 1483 c13 == 0 && c14 == 0 && c15 == 0 && c16 == 'x') { 1484 return "application/xml"; 1485 } 1486 } 1487 1488 if (c1 == 0xff && c2 == 0xfe && c3 == 0x00 && c4 == 0x00) { 1489 if (c5 == '<' && c6 == 0 && c7 == 0 && c8 == 0 && 1490 c9 == '?' && c10 == 0 && c11 == 0 && c12 == 0 && 1491 c13 == 'x' && c14 == 0 && c15 == 0 && c16 == 0) { 1492 return "application/xml"; 1493 } 1494 } 1495 1496 if (c1 == 'G' && c2 == 'I' && c3 == 'F' && c4 == '8') { 1497 return "image/gif"; 1498 } 1499 1500 if (c1 == '#' && c2 == 'd' && c3 == 'e' && c4 == 'f') { 1501 return "image/x-bitmap"; 1502 } 1503 1504 if (c1 == '!' && c2 == ' ' && c3 == 'X' && c4 == 'P' && 1505 c5 == 'M' && c6 == '2') { 1506 return "image/x-pixmap"; 1507 } 1508 1509 if (c1 == 137 && c2 == 80 && c3 == 78 && 1510 c4 == 71 && c5 == 13 && c6 == 10 && 1511 c7 == 26 && c8 == 10) { 1512 return "image/png"; 1513 } 1514 1515 if (c1 == 0xFF && c2 == 0xD8 && c3 == 0xFF) { 1516 if (c4 == 0xE0 || c4 == 0xEE) { 1517 return "image/jpeg"; 1518 } 1519 1520 /** 1521 * File format used by digital cameras to store images. 1522 * Exif Format can be read by any application supporting 1523 * JPEG. Exif Spec can be found at: 1524 * http://www.pima.net/standards/it10/PIMA15740/Exif_2-1.PDF 1525 */ 1526 if ((c4 == 0xE1) && 1527 (c7 == 'E' && c8 == 'x' && c9 == 'i' && c10 =='f' && 1528 c11 == 0)) { 1529 return "image/jpeg"; 1530 } 1531 } 1532 1533 if (c1 == 0xD0 && c2 == 0xCF && c3 == 0x11 && c4 == 0xE0 && 1534 c5 == 0xA1 && c6 == 0xB1 && c7 == 0x1A && c8 == 0xE1) { 1535 1536 /* Above is signature of Microsoft Structured Storage. 1537 * Below this, could have tests for various SS entities. 1538 * For now, just test for FlashPix. 1539 */ 1540 if (checkfpx(is)) { 1541 return "image/vnd.fpx"; 1542 } 1543 } 1544 1545 if (c1 == 0x2E && c2 == 0x73 && c3 == 0x6E && c4 == 0x64) { 1546 return "audio/basic"; // .au format, big endian 1547 } 1548 1549 if (c1 == 0x64 && c2 == 0x6E && c3 == 0x73 && c4 == 0x2E) { 1550 return "audio/basic"; // .au format, little endian 1551 } 1552 1553 if (c1 == 'R' && c2 == 'I' && c3 == 'F' && c4 == 'F') { 1554 /* I don't know if this is official but evidence 1555 * suggests that .wav files start with "RIFF" - brown 1556 */ 1557 return "audio/x-wav"; 1558 } 1559 return null; 1560 } 1561 1562 /** 1563 * Check for FlashPix image data in InputStream is. Return true if 1564 * the stream has FlashPix data, false otherwise. Before calling this 1565 * method, the stream should have already been checked to be sure it 1566 * contains Microsoft Structured Storage data. 1567 */ 1568 static private boolean checkfpx(InputStream is) throws IOException { 1569 1570 /* Test for FlashPix image data in Microsoft Structured Storage format. 1571 * In general, should do this with calls to an SS implementation. 1572 * Lacking that, need to dig via offsets to get to the FlashPix 1573 * ClassID. Details: 1574 * 1575 * Offset to Fpx ClsID from beginning of stream should be: 1576 * 1577 * FpxClsidOffset = rootEntryOffset + clsidOffset 1578 * 1579 * where: clsidOffset = 0x50. 1580 * rootEntryOffset = headerSize + sectorSize*sectDirStart 1581 * + 128*rootEntryDirectory 1582 * 1583 * where: headerSize = 0x200 (always) 1584 * sectorSize = 2 raised to power of uSectorShift, 1585 * which is found in the header at 1586 * offset 0x1E. 1587 * sectDirStart = found in the header at offset 0x30. 1588 * rootEntryDirectory = in general, should search for 1589 * directory labelled as root. 1590 * We will assume value of 0 (i.e., 1591 * rootEntry is in first directory) 1592 */ 1593 1594 // Mark the stream so we can reset it. 0x100 is enough for the first 1595 // few reads, but the mark will have to be reset and set again once 1596 // the offset to the root directory entry is computed. That offset 1597 // can be very large and isn't know until the stream has been read from 1598 is.mark(0x100); 1599 1600 // Get the byte ordering located at 0x1E. 0xFE is Intel, 1601 // 0xFF is other 1602 long toSkip = (long)0x1C; 1603 long posn; 1604 1605 if ((posn = skipForward(is, toSkip)) < toSkip) { 1606 is.reset(); 1607 return false; 1608 } 1609 1610 int c[] = new int[16]; 1611 if (readBytes(c, 2, is) < 0) { 1612 is.reset(); 1613 return false; 1614 } 1615 1616 int byteOrder = c[0]; 1617 1618 posn+=2; 1619 int uSectorShift; 1620 if (readBytes(c, 2, is) < 0) { 1621 is.reset(); 1622 return false; 1623 } 1624 1625 if(byteOrder == 0xFE) { 1626 uSectorShift = c[0]; 1627 uSectorShift += c[1] << 8; 1628 } 1629 else { 1630 uSectorShift = c[0] << 8; 1631 uSectorShift += c[1]; 1632 } 1633 1634 posn += 2; 1635 toSkip = (long)0x30 - posn; 1636 long skipped = 0; 1637 if ((skipped = skipForward(is, toSkip)) < toSkip) { 1638 is.reset(); 1639 return false; 1640 } 1641 posn += skipped; 1642 1643 if (readBytes(c, 4, is) < 0) { 1644 is.reset(); 1645 return false; 1646 } 1647 1648 int sectDirStart; 1649 if(byteOrder == 0xFE) { 1650 sectDirStart = c[0]; 1651 sectDirStart += c[1] << 8; 1652 sectDirStart += c[2] << 16; 1653 sectDirStart += c[3] << 24; 1654 } else { 1655 sectDirStart = c[0] << 24; 1656 sectDirStart += c[1] << 16; 1657 sectDirStart += c[2] << 8; 1658 sectDirStart += c[3]; 1659 } 1660 posn += 4; 1661 is.reset(); // Reset back to the beginning 1662 1663 toSkip = 0x200L + (long)(1<<uSectorShift)*sectDirStart + 0x50L; 1664 1665 // Sanity check! 1666 if (toSkip < 0) { 1667 return false; 1668 } 1669 1670 /* 1671 * How far can we skip? Is there any performance problem here? 1672 * This skip can be fairly long, at least 0x4c650 in at least 1673 * one case. Have to assume that the skip will fit in an int. 1674 * Leave room to read whole root dir 1675 */ 1676 is.mark((int)toSkip+0x30); 1677 1678 if ((skipForward(is, toSkip)) < toSkip) { 1679 is.reset(); 1680 return false; 1681 } 1682 1683 /* should be at beginning of ClassID, which is as follows 1684 * (in Intel byte order): 1685 * 00 67 61 56 54 C1 CE 11 85 53 00 AA 00 A1 F9 5B 1686 * 1687 * This is stored from Windows as long,short,short,char[8] 1688 * so for byte order changes, the order only changes for 1689 * the first 8 bytes in the ClassID. 1690 * 1691 * Test against this, ignoring second byte (Intel) since 1692 * this could change depending on part of Fpx file we have. 1693 */ 1694 1695 if (readBytes(c, 16, is) < 0) { 1696 is.reset(); 1697 return false; 1698 } 1699 1700 // intel byte order 1701 if (byteOrder == 0xFE && 1702 c[0] == 0x00 && c[2] == 0x61 && c[3] == 0x56 && 1703 c[4] == 0x54 && c[5] == 0xC1 && c[6] == 0xCE && 1704 c[7] == 0x11 && c[8] == 0x85 && c[9] == 0x53 && 1705 c[10]== 0x00 && c[11]== 0xAA && c[12]== 0x00 && 1706 c[13]== 0xA1 && c[14]== 0xF9 && c[15]== 0x5B) { 1707 is.reset(); 1708 return true; 1709 } 1710 1711 // non-intel byte order 1712 else if (c[3] == 0x00 && c[1] == 0x61 && c[0] == 0x56 && 1713 c[5] == 0x54 && c[4] == 0xC1 && c[7] == 0xCE && 1714 c[6] == 0x11 && c[8] == 0x85 && c[9] == 0x53 && 1715 c[10]== 0x00 && c[11]== 0xAA && c[12]== 0x00 && 1716 c[13]== 0xA1 && c[14]== 0xF9 && c[15]== 0x5B) { 1717 is.reset(); 1718 return true; 1719 } 1720 is.reset(); 1721 return false; 1722 } 1723 1724 /** 1725 * Tries to read the specified number of bytes from the stream 1726 * Returns -1, If EOF is reached before len bytes are read, returns 0 1727 * otherwise 1728 */ 1729 static private int readBytes(int c[], int len, InputStream is) 1730 throws IOException { 1731 1732 byte buf[] = new byte[len]; 1733 if (is.read(buf, 0, len) < len) { 1734 return -1; 1735 } 1736 1737 // fill the passed in int array 1738 for (int i = 0; i < len; i++) { 1739 c[i] = buf[i] & 0xff; 1740 } 1741 return 0; 1742 } 1743 1744 1745 /** 1746 * Skips through the specified number of bytes from the stream 1747 * until either EOF is reached, or the specified 1748 * number of bytes have been skipped 1749 */ 1750 static private long skipForward(InputStream is, long toSkip) 1751 throws IOException { 1752 1753 long eachSkip = 0; 1754 long skipped = 0; 1755 1756 while (skipped != toSkip) { 1757 eachSkip = is.skip(toSkip - skipped); 1758 1759 // check if EOF is reached 1760 if (eachSkip <= 0) { 1761 if (is.read() == -1) { 1762 return skipped ; 1763 } else { 1764 skipped++; 1765 } 1766 } 1767 skipped += eachSkip; 1768 } 1769 return skipped; 1770 } 1771 1772 } 1773 1774 1775 class UnknownContentHandler extends ContentHandler { 1776 static final ContentHandler INSTANCE = new UnknownContentHandler(); 1777 1778 public Object getContent(URLConnection uc) throws IOException { 1779 return uc.getInputStream(); 1780 } 1781 }