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