1 /* 2 * Copyright (c) 1995, 2014, 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 this method tries to load a content handler 708 * class as defined by {@link java.net.ContentHandler ContentHandler}. 709 * If the class does not exist, or is not a subclass of {@code 710 * ContentHandler}, then an {@code UnknownServiceException} is thrown. 711 * </ol> 712 * 713 * @return the object fetched. The {@code instanceof} operator 714 * should be used to determine the specific kind of object 715 * returned. 716 * @exception IOException if an I/O error occurs while 717 * getting the content. 718 * @exception UnknownServiceException if the protocol does not support 719 * the content type. 720 * @see java.net.ContentHandlerFactory#createContentHandler(java.lang.String) 721 * @see java.net.URLConnection#getContentType() 722 * @see java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory) 723 */ 724 public Object getContent() throws IOException { 725 // Must call getInputStream before GetHeaderField gets called 726 // so that FileNotFoundException has a chance to be thrown up 727 // from here without being caught. 728 getInputStream(); 729 return getContentHandler().getContent(this); 730 } 731 732 /** 733 * Retrieves the contents of this URL connection. 734 * 735 * @param classes the {@code Class} array 736 * indicating the requested types 737 * @return the object fetched that is the first match of the type 738 * specified in the classes array. null if none of 739 * the requested types are supported. 740 * The {@code instanceof} operator should be used to 741 * determine the specific kind of object returned. 742 * @exception IOException if an I/O error occurs while 743 * getting the content. 744 * @exception UnknownServiceException if the protocol does not support 745 * the content type. 746 * @see java.net.URLConnection#getContent() 747 * @see java.net.ContentHandlerFactory#createContentHandler(java.lang.String) 748 * @see java.net.URLConnection#getContent(java.lang.Class[]) 749 * @see java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory) 750 * @since 1.3 751 */ 752 public Object getContent(Class<?>[] classes) throws IOException { 753 // Must call getInputStream before GetHeaderField gets called 754 // so that FileNotFoundException has a chance to be thrown up 755 // from here without being caught. 756 getInputStream(); 757 return getContentHandler().getContent(this, classes); 758 } 759 760 /** 761 * Returns a permission object representing the permission 762 * necessary to make the connection represented by this 763 * object. This method returns null if no permission is 764 * required to make the connection. By default, this method 765 * returns {@code java.security.AllPermission}. Subclasses 766 * should override this method and return the permission 767 * that best represents the permission required to make a 768 * a connection to the URL. For example, a {@code URLConnection} 769 * representing a {@code file:} URL would return a 770 * {@code java.io.FilePermission} object. 771 * 772 * <p>The permission returned may dependent upon the state of the 773 * connection. For example, the permission before connecting may be 774 * different from that after connecting. For example, an HTTP 775 * sever, say foo.com, may redirect the connection to a different 776 * host, say bar.com. Before connecting the permission returned by 777 * the connection will represent the permission needed to connect 778 * to foo.com, while the permission returned after connecting will 779 * be to bar.com. 780 * 781 * <p>Permissions are generally used for two purposes: to protect 782 * caches of objects obtained through URLConnections, and to check 783 * the right of a recipient to learn about a particular URL. In 784 * the first case, the permission should be obtained 785 * <em>after</em> the object has been obtained. For example, in an 786 * HTTP connection, this will represent the permission to connect 787 * to the host from which the data was ultimately fetched. In the 788 * second case, the permission should be obtained and tested 789 * <em>before</em> connecting. 790 * 791 * @return the permission object representing the permission 792 * necessary to make the connection represented by this 793 * URLConnection. 794 * 795 * @exception IOException if the computation of the permission 796 * requires network or file I/O and an exception occurs while 797 * computing it. 798 */ 799 public Permission getPermission() throws IOException { 800 return SecurityConstants.ALL_PERMISSION; 801 } 802 803 /** 804 * Returns an input stream that reads from this open connection. 805 * 806 * A SocketTimeoutException can be thrown when reading from the 807 * returned input stream if the read timeout expires before data 808 * is available for read. 809 * 810 * @return an input stream that reads from this open connection. 811 * @exception IOException if an I/O error occurs while 812 * creating the input stream. 813 * @exception UnknownServiceException if the protocol does not support 814 * input. 815 * @see #setReadTimeout(int) 816 * @see #getReadTimeout() 817 */ 818 public InputStream getInputStream() throws IOException { 819 throw new UnknownServiceException("protocol doesn't support input"); 820 } 821 822 /** 823 * Returns an output stream that writes to this connection. 824 * 825 * @return an output stream that writes to this connection. 826 * @exception IOException if an I/O error occurs while 827 * creating the output stream. 828 * @exception UnknownServiceException if the protocol does not support 829 * output. 830 */ 831 public OutputStream getOutputStream() throws IOException { 832 throw new UnknownServiceException("protocol doesn't support output"); 833 } 834 835 /** 836 * Returns a {@code String} representation of this URL connection. 837 * 838 * @return a string representation of this {@code URLConnection}. 839 */ 840 public String toString() { 841 return this.getClass().getName() + ":" + url; 842 } 843 844 /** 845 * Sets the value of the {@code doInput} field for this 846 * {@code URLConnection} to the specified value. 847 * <p> 848 * A URL connection can be used for input and/or output. Set the DoInput 849 * flag to true if you intend to use the URL connection for input, 850 * false if not. The default is true. 851 * 852 * @param doinput the new value. 853 * @throws IllegalStateException if already connected 854 * @see java.net.URLConnection#doInput 855 * @see #getDoInput() 856 */ 857 public void setDoInput(boolean doinput) { 858 if (connected) 859 throw new IllegalStateException("Already connected"); 860 doInput = doinput; 861 } 862 863 /** 864 * Returns the value of this {@code URLConnection}'s 865 * {@code doInput} flag. 866 * 867 * @return the value of this {@code URLConnection}'s 868 * {@code doInput} flag. 869 * @see #setDoInput(boolean) 870 */ 871 public boolean getDoInput() { 872 return doInput; 873 } 874 875 /** 876 * Sets the value of the {@code doOutput} field for this 877 * {@code URLConnection} to the specified value. 878 * <p> 879 * A URL connection can be used for input and/or output. Set the DoOutput 880 * flag to true if you intend to use the URL connection for output, 881 * false if not. The default is false. 882 * 883 * @param dooutput the new value. 884 * @throws IllegalStateException if already connected 885 * @see #getDoOutput() 886 */ 887 public void setDoOutput(boolean dooutput) { 888 if (connected) 889 throw new IllegalStateException("Already connected"); 890 doOutput = dooutput; 891 } 892 893 /** 894 * Returns the value of this {@code URLConnection}'s 895 * {@code doOutput} flag. 896 * 897 * @return the value of this {@code URLConnection}'s 898 * {@code doOutput} flag. 899 * @see #setDoOutput(boolean) 900 */ 901 public boolean getDoOutput() { 902 return doOutput; 903 } 904 905 /** 906 * Set the value of the {@code allowUserInteraction} field of 907 * this {@code URLConnection}. 908 * 909 * @param allowuserinteraction the new value. 910 * @throws IllegalStateException if already connected 911 * @see #getAllowUserInteraction() 912 */ 913 public void setAllowUserInteraction(boolean allowuserinteraction) { 914 if (connected) 915 throw new IllegalStateException("Already connected"); 916 allowUserInteraction = allowuserinteraction; 917 } 918 919 /** 920 * Returns the value of the {@code allowUserInteraction} field for 921 * this object. 922 * 923 * @return the value of the {@code allowUserInteraction} field for 924 * this object. 925 * @see #setAllowUserInteraction(boolean) 926 */ 927 public boolean getAllowUserInteraction() { 928 return allowUserInteraction; 929 } 930 931 /** 932 * Sets the default value of the 933 * {@code allowUserInteraction} field for all future 934 * {@code URLConnection} objects to the specified value. 935 * 936 * @param defaultallowuserinteraction the new value. 937 * @see #getDefaultAllowUserInteraction() 938 */ 939 public static void setDefaultAllowUserInteraction(boolean defaultallowuserinteraction) { 940 defaultAllowUserInteraction = defaultallowuserinteraction; 941 } 942 943 /** 944 * Returns the default value of the {@code allowUserInteraction} 945 * field. 946 * <p> 947 * Ths default is "sticky", being a part of the static state of all 948 * URLConnections. This flag applies to the next, and all following 949 * URLConnections that are created. 950 * 951 * @return the default value of the {@code allowUserInteraction} 952 * field. 953 * @see #setDefaultAllowUserInteraction(boolean) 954 */ 955 public static boolean getDefaultAllowUserInteraction() { 956 return defaultAllowUserInteraction; 957 } 958 959 /** 960 * Sets the value of the {@code useCaches} field of this 961 * {@code URLConnection} to the specified value. 962 * <p> 963 * Some protocols do caching of documents. Occasionally, it is important 964 * to be able to "tunnel through" and ignore the caches (e.g., the 965 * "reload" button in a browser). If the UseCaches flag on a connection 966 * is true, the connection is allowed to use whatever caches it can. 967 * If false, caches are to be ignored. 968 * The default value comes from DefaultUseCaches, which defaults to 969 * true. 970 * 971 * @param usecaches a {@code boolean} indicating whether 972 * or not to allow caching 973 * @throws IllegalStateException if already connected 974 * @see #getUseCaches() 975 */ 976 public void setUseCaches(boolean usecaches) { 977 if (connected) 978 throw new IllegalStateException("Already connected"); 979 useCaches = usecaches; 980 } 981 982 /** 983 * Returns the value of this {@code URLConnection}'s 984 * {@code useCaches} field. 985 * 986 * @return the value of this {@code URLConnection}'s 987 * {@code useCaches} field. 988 * @see #setUseCaches(boolean) 989 */ 990 public boolean getUseCaches() { 991 return useCaches; 992 } 993 994 /** 995 * Sets the value of the {@code ifModifiedSince} field of 996 * this {@code URLConnection} to the specified value. 997 * 998 * @param ifmodifiedsince the new value. 999 * @throws IllegalStateException if already connected 1000 * @see #getIfModifiedSince() 1001 */ 1002 public void setIfModifiedSince(long ifmodifiedsince) { 1003 if (connected) 1004 throw new IllegalStateException("Already connected"); 1005 ifModifiedSince = ifmodifiedsince; 1006 } 1007 1008 /** 1009 * Returns the value of this object's {@code ifModifiedSince} field. 1010 * 1011 * @return the value of this object's {@code ifModifiedSince} field. 1012 * @see #setIfModifiedSince(long) 1013 */ 1014 public long getIfModifiedSince() { 1015 return ifModifiedSince; 1016 } 1017 1018 /** 1019 * Returns the default value of a {@code URLConnection}'s 1020 * {@code useCaches} flag. 1021 * <p> 1022 * Ths default is "sticky", being a part of the static state of all 1023 * URLConnections. This flag applies to the next, and all following 1024 * URLConnections that are created. 1025 * 1026 * @return the default value of a {@code URLConnection}'s 1027 * {@code useCaches} flag. 1028 * @see #setDefaultUseCaches(boolean) 1029 */ 1030 public boolean getDefaultUseCaches() { 1031 return defaultUseCaches; 1032 } 1033 1034 /** 1035 * Sets the default value of the {@code useCaches} field to the 1036 * specified value. 1037 * 1038 * @param defaultusecaches the new value. 1039 * @see #getDefaultUseCaches() 1040 */ 1041 public void setDefaultUseCaches(boolean defaultusecaches) { 1042 defaultUseCaches = defaultusecaches; 1043 } 1044 1045 /** 1046 * Sets the general request property. If a property with the key already 1047 * exists, overwrite its value with the new value. 1048 * 1049 * <p> NOTE: HTTP requires all request properties which can 1050 * legally have multiple instances with the same key 1051 * to use a comma-separated list syntax which enables multiple 1052 * properties to be appended into a single property. 1053 * 1054 * @param key the keyword by which the request is known 1055 * (e.g., "{@code Accept}"). 1056 * @param value the value associated with it. 1057 * @throws IllegalStateException if already connected 1058 * @throws NullPointerException if key is <CODE>null</CODE> 1059 * @see #getRequestProperty(java.lang.String) 1060 */ 1061 public void setRequestProperty(String key, String value) { 1062 if (connected) 1063 throw new IllegalStateException("Already connected"); 1064 if (key == null) 1065 throw new NullPointerException ("key is null"); 1066 1067 if (requests == null) 1068 requests = new MessageHeader(); 1069 1070 requests.set(key, value); 1071 } 1072 1073 /** 1074 * Adds a general request property specified by a 1075 * key-value pair. This method will not overwrite 1076 * existing values associated with the same key. 1077 * 1078 * @param key the keyword by which the request is known 1079 * (e.g., "{@code Accept}"). 1080 * @param value the value associated with it. 1081 * @throws IllegalStateException if already connected 1082 * @throws NullPointerException if key is null 1083 * @see #getRequestProperties() 1084 * @since 1.4 1085 */ 1086 public void addRequestProperty(String key, String value) { 1087 if (connected) 1088 throw new IllegalStateException("Already connected"); 1089 if (key == null) 1090 throw new NullPointerException ("key is null"); 1091 1092 if (requests == null) 1093 requests = new MessageHeader(); 1094 1095 requests.add(key, value); 1096 } 1097 1098 1099 /** 1100 * Returns the value of the named general request property for this 1101 * connection. 1102 * 1103 * @param key the keyword by which the request is known (e.g., "Accept"). 1104 * @return the value of the named general request property for this 1105 * connection. If key is null, then null is returned. 1106 * @throws IllegalStateException if already connected 1107 * @see #setRequestProperty(java.lang.String, java.lang.String) 1108 */ 1109 public String getRequestProperty(String key) { 1110 if (connected) 1111 throw new IllegalStateException("Already connected"); 1112 1113 if (requests == null) 1114 return null; 1115 1116 return requests.findValue(key); 1117 } 1118 1119 /** 1120 * Returns an unmodifiable Map of general request 1121 * properties for this connection. The Map keys 1122 * are Strings that represent the request-header 1123 * field names. Each Map value is a unmodifiable List 1124 * of Strings that represents the corresponding 1125 * field values. 1126 * 1127 * @return a Map of the general request properties for this connection. 1128 * @throws IllegalStateException if already connected 1129 * @since 1.4 1130 */ 1131 public Map<String,List<String>> getRequestProperties() { 1132 if (connected) 1133 throw new IllegalStateException("Already connected"); 1134 1135 if (requests == null) 1136 return Collections.emptyMap(); 1137 1138 return requests.getHeaders(null); 1139 } 1140 1141 /** 1142 * Sets the default value of a general request property. When a 1143 * {@code URLConnection} is created, it is initialized with 1144 * these properties. 1145 * 1146 * @param key the keyword by which the request is known 1147 * (e.g., "{@code Accept}"). 1148 * @param value the value associated with the key. 1149 * 1150 * @see java.net.URLConnection#setRequestProperty(java.lang.String,java.lang.String) 1151 * 1152 * @deprecated The instance specific setRequestProperty method 1153 * should be used after an appropriate instance of URLConnection 1154 * is obtained. Invoking this method will have no effect. 1155 * 1156 * @see #getDefaultRequestProperty(java.lang.String) 1157 */ 1158 @Deprecated 1159 public static void setDefaultRequestProperty(String key, String value) { 1160 } 1161 1162 /** 1163 * Returns the value of the default request property. Default request 1164 * properties are set for every connection. 1165 * 1166 * @param key the keyword by which the request is known (e.g., "Accept"). 1167 * @return the value of the default request property 1168 * for the specified key. 1169 * 1170 * @see java.net.URLConnection#getRequestProperty(java.lang.String) 1171 * 1172 * @deprecated The instance specific getRequestProperty method 1173 * should be used after an appropriate instance of URLConnection 1174 * is obtained. 1175 * 1176 * @see #setDefaultRequestProperty(java.lang.String, java.lang.String) 1177 */ 1178 @Deprecated 1179 public static String getDefaultRequestProperty(String key) { 1180 return null; 1181 } 1182 1183 /** 1184 * The ContentHandler factory. 1185 */ 1186 static ContentHandlerFactory factory; 1187 1188 /** 1189 * Sets the {@code ContentHandlerFactory} of an 1190 * application. It can be called at most once by an application. 1191 * <p> 1192 * The {@code ContentHandlerFactory} instance is used to 1193 * construct a content handler from a content type 1194 * <p> 1195 * If there is a security manager, this method first calls 1196 * the security manager's {@code checkSetFactory} method 1197 * to ensure the operation is allowed. 1198 * This could result in a SecurityException. 1199 * 1200 * @param fac the desired factory. 1201 * @exception Error if the factory has already been defined. 1202 * @exception SecurityException if a security manager exists and its 1203 * {@code checkSetFactory} method doesn't allow the operation. 1204 * @see java.net.ContentHandlerFactory 1205 * @see java.net.URLConnection#getContent() 1206 * @see SecurityManager#checkSetFactory 1207 */ 1208 public static synchronized void setContentHandlerFactory(ContentHandlerFactory fac) { 1209 if (factory != null) { 1210 throw new Error("factory already defined"); 1211 } 1212 SecurityManager security = System.getSecurityManager(); 1213 if (security != null) { 1214 security.checkSetFactory(); 1215 } 1216 factory = fac; 1217 } 1218 1219 private static Hashtable<String, ContentHandler> handlers = new Hashtable<>(); 1220 1221 /** 1222 * Gets the Content Handler appropriate for this connection. 1223 */ 1224 synchronized ContentHandler getContentHandler() 1225 throws UnknownServiceException 1226 { 1227 String contentType = stripOffParameters(getContentType()); 1228 ContentHandler handler = null; 1229 if (contentType == null) 1230 throw new UnknownServiceException("no content-type"); 1231 try { 1232 handler = handlers.get(contentType); 1233 if (handler != null) 1234 return handler; 1235 } catch(Exception e) { 1236 } 1237 1238 if (factory != null) 1239 handler = factory.createContentHandler(contentType); 1240 if (handler == null) { 1241 try { 1242 handler = lookupContentHandlerClassFor(contentType); 1243 } catch(Exception e) { 1244 e.printStackTrace(); 1245 handler = UnknownContentHandler.INSTANCE; 1246 } 1247 handlers.put(contentType, handler); 1248 } 1249 return handler; 1250 } 1251 1252 /* 1253 * Media types are in the format: type/subtype*(; parameter). 1254 * For looking up the content handler, we should ignore those 1255 * parameters. 1256 */ 1257 private String stripOffParameters(String contentType) 1258 { 1259 if (contentType == null) 1260 return null; 1261 int index = contentType.indexOf(';'); 1262 1263 if (index > 0) 1264 return contentType.substring(0, index); 1265 else 1266 return contentType; 1267 } 1268 1269 private static final String contentClassPrefix = "sun.net.www.content"; 1270 private static final String contentPathProp = "java.content.handler.pkgs"; 1271 1272 /** 1273 * Looks for a content handler in a user-defineable set of places. 1274 * By default it looks in sun.net.www.content, but users can define a 1275 * vertical-bar delimited set of class prefixes to search through in 1276 * addition by defining the java.content.handler.pkgs property. 1277 * The class name must be of the form: 1278 * <pre> 1279 * {package-prefix}.{major}.{minor} 1280 * e.g. 1281 * YoyoDyne.experimental.text.plain 1282 * </pre> 1283 */ 1284 private ContentHandler lookupContentHandlerClassFor(String contentType) 1285 throws InstantiationException, IllegalAccessException, ClassNotFoundException { 1286 String contentHandlerClassName = typeToPackageName(contentType); 1287 1288 String contentHandlerPkgPrefixes =getContentHandlerPkgPrefixes(); 1289 1290 StringTokenizer packagePrefixIter = 1291 new StringTokenizer(contentHandlerPkgPrefixes, "|"); 1292 1293 while (packagePrefixIter.hasMoreTokens()) { 1294 String packagePrefix = packagePrefixIter.nextToken().trim(); 1295 1296 try { 1297 String clsName = packagePrefix + "." + contentHandlerClassName; 1298 Class<?> cls = null; 1299 try { 1300 cls = Class.forName(clsName); 1301 } catch (ClassNotFoundException e) { 1302 ClassLoader cl = ClassLoader.getSystemClassLoader(); 1303 if (cl != null) { 1304 cls = cl.loadClass(clsName); 1305 } 1306 } 1307 if (cls != null) { 1308 ContentHandler handler = 1309 (ContentHandler)cls.newInstance(); 1310 return handler; 1311 } 1312 } catch(Exception e) { 1313 } 1314 } 1315 1316 return UnknownContentHandler.INSTANCE; 1317 } 1318 1319 /** 1320 * Utility function to map a MIME content type into an equivalent 1321 * pair of class name components. For example: "text/html" would 1322 * be returned as "text.html" 1323 */ 1324 private String typeToPackageName(String contentType) { 1325 // make sure we canonicalize the class name: all lower case 1326 contentType = contentType.toLowerCase(); 1327 int len = contentType.length(); 1328 char nm[] = new char[len]; 1329 contentType.getChars(0, len, nm, 0); 1330 for (int i = 0; i < len; i++) { 1331 char c = nm[i]; 1332 if (c == '/') { 1333 nm[i] = '.'; 1334 } else if (!('A' <= c && c <= 'Z' || 1335 'a' <= c && c <= 'z' || 1336 '0' <= c && c <= '9')) { 1337 nm[i] = '_'; 1338 } 1339 } 1340 return new String(nm); 1341 } 1342 1343 1344 /** 1345 * Returns a vertical bar separated list of package prefixes for potential 1346 * content handlers. Tries to get the java.content.handler.pkgs property 1347 * to use as a set of package prefixes to search. Whether or not 1348 * that property has been defined, the sun.net.www.content is always 1349 * the last one on the returned package list. 1350 */ 1351 private String getContentHandlerPkgPrefixes() { 1352 String packagePrefixList = AccessController.doPrivileged( 1353 new sun.security.action.GetPropertyAction(contentPathProp, "")); 1354 1355 if (packagePrefixList != "") { 1356 packagePrefixList += "|"; 1357 } 1358 1359 return packagePrefixList + contentClassPrefix; 1360 } 1361 1362 /** 1363 * Tries to determine the content type of an object, based 1364 * on the specified "file" component of a URL. 1365 * This is a convenience method that can be used by 1366 * subclasses that override the {@code getContentType} method. 1367 * 1368 * @param fname a filename. 1369 * @return a guess as to what the content type of the object is, 1370 * based upon its file name. 1371 * @see java.net.URLConnection#getContentType() 1372 */ 1373 public static String guessContentTypeFromName(String fname) { 1374 return getFileNameMap().getContentTypeFor(fname); 1375 } 1376 1377 /** 1378 * Tries to determine the type of an input stream based on the 1379 * characters at the beginning of the input stream. This method can 1380 * be used by subclasses that override the 1381 * {@code getContentType} method. 1382 * <p> 1383 * Ideally, this routine would not be needed. But many 1384 * {@code http} servers return the incorrect content type; in 1385 * addition, there are many nonstandard extensions. Direct inspection 1386 * of the bytes to determine the content type is often more accurate 1387 * than believing the content type claimed by the {@code http} server. 1388 * 1389 * @param is an input stream that supports marks. 1390 * @return a guess at the content type, or {@code null} if none 1391 * can be determined. 1392 * @exception IOException if an I/O error occurs while reading the 1393 * input stream. 1394 * @see java.io.InputStream#mark(int) 1395 * @see java.io.InputStream#markSupported() 1396 * @see java.net.URLConnection#getContentType() 1397 */ 1398 static public String guessContentTypeFromStream(InputStream is) 1399 throws IOException { 1400 // If we can't read ahead safely, just give up on guessing 1401 if (!is.markSupported()) 1402 return null; 1403 1404 is.mark(16); 1405 int c1 = is.read(); 1406 int c2 = is.read(); 1407 int c3 = is.read(); 1408 int c4 = is.read(); 1409 int c5 = is.read(); 1410 int c6 = is.read(); 1411 int c7 = is.read(); 1412 int c8 = is.read(); 1413 int c9 = is.read(); 1414 int c10 = is.read(); 1415 int c11 = is.read(); 1416 int c12 = is.read(); 1417 int c13 = is.read(); 1418 int c14 = is.read(); 1419 int c15 = is.read(); 1420 int c16 = is.read(); 1421 is.reset(); 1422 1423 if (c1 == 0xCA && c2 == 0xFE && c3 == 0xBA && c4 == 0xBE) { 1424 return "application/java-vm"; 1425 } 1426 1427 if (c1 == 0xAC && c2 == 0xED) { 1428 // next two bytes are version number, currently 0x00 0x05 1429 return "application/x-java-serialized-object"; 1430 } 1431 1432 if (c1 == '<') { 1433 if (c2 == '!' 1434 || ((c2 == 'h' && (c3 == 't' && c4 == 'm' && c5 == 'l' || 1435 c3 == 'e' && c4 == 'a' && c5 == 'd') || 1436 (c2 == 'b' && c3 == 'o' && c4 == 'd' && c5 == 'y'))) || 1437 ((c2 == 'H' && (c3 == 'T' && c4 == 'M' && c5 == 'L' || 1438 c3 == 'E' && c4 == 'A' && c5 == 'D') || 1439 (c2 == 'B' && c3 == 'O' && c4 == 'D' && c5 == 'Y')))) { 1440 return "text/html"; 1441 } 1442 1443 if (c2 == '?' && c3 == 'x' && c4 == 'm' && c5 == 'l' && c6 == ' ') { 1444 return "application/xml"; 1445 } 1446 } 1447 1448 // big and little (identical) endian UTF-8 encodings, with BOM 1449 if (c1 == 0xef && c2 == 0xbb && c3 == 0xbf) { 1450 if (c4 == '<' && c5 == '?' && c6 == 'x') { 1451 return "application/xml"; 1452 } 1453 } 1454 1455 // big and little endian UTF-16 encodings, with byte order mark 1456 if (c1 == 0xfe && c2 == 0xff) { 1457 if (c3 == 0 && c4 == '<' && c5 == 0 && c6 == '?' && 1458 c7 == 0 && c8 == 'x') { 1459 return "application/xml"; 1460 } 1461 } 1462 1463 if (c1 == 0xff && c2 == 0xfe) { 1464 if (c3 == '<' && c4 == 0 && c5 == '?' && c6 == 0 && 1465 c7 == 'x' && c8 == 0) { 1466 return "application/xml"; 1467 } 1468 } 1469 1470 // big and little endian UTF-32 encodings, with BOM 1471 if (c1 == 0x00 && c2 == 0x00 && c3 == 0xfe && c4 == 0xff) { 1472 if (c5 == 0 && c6 == 0 && c7 == 0 && c8 == '<' && 1473 c9 == 0 && c10 == 0 && c11 == 0 && c12 == '?' && 1474 c13 == 0 && c14 == 0 && c15 == 0 && c16 == 'x') { 1475 return "application/xml"; 1476 } 1477 } 1478 1479 if (c1 == 0xff && c2 == 0xfe && c3 == 0x00 && c4 == 0x00) { 1480 if (c5 == '<' && c6 == 0 && c7 == 0 && c8 == 0 && 1481 c9 == '?' && c10 == 0 && c11 == 0 && c12 == 0 && 1482 c13 == 'x' && c14 == 0 && c15 == 0 && c16 == 0) { 1483 return "application/xml"; 1484 } 1485 } 1486 1487 if (c1 == 'G' && c2 == 'I' && c3 == 'F' && c4 == '8') { 1488 return "image/gif"; 1489 } 1490 1491 if (c1 == '#' && c2 == 'd' && c3 == 'e' && c4 == 'f') { 1492 return "image/x-bitmap"; 1493 } 1494 1495 if (c1 == '!' && c2 == ' ' && c3 == 'X' && c4 == 'P' && 1496 c5 == 'M' && c6 == '2') { 1497 return "image/x-pixmap"; 1498 } 1499 1500 if (c1 == 137 && c2 == 80 && c3 == 78 && 1501 c4 == 71 && c5 == 13 && c6 == 10 && 1502 c7 == 26 && c8 == 10) { 1503 return "image/png"; 1504 } 1505 1506 if (c1 == 0xFF && c2 == 0xD8 && c3 == 0xFF) { 1507 if (c4 == 0xE0) { 1508 return "image/jpeg"; 1509 } 1510 1511 /** 1512 * File format used by digital cameras to store images. 1513 * Exif Format can be read by any application supporting 1514 * JPEG. Exif Spec can be found at: 1515 * http://www.pima.net/standards/it10/PIMA15740/Exif_2-1.PDF 1516 */ 1517 if ((c4 == 0xE1) && 1518 (c7 == 'E' && c8 == 'x' && c9 == 'i' && c10 =='f' && 1519 c11 == 0)) { 1520 return "image/jpeg"; 1521 } 1522 1523 if (c4 == 0xEE) { 1524 return "image/jpg"; 1525 } 1526 } 1527 1528 if (c1 == 0xD0 && c2 == 0xCF && c3 == 0x11 && c4 == 0xE0 && 1529 c5 == 0xA1 && c6 == 0xB1 && c7 == 0x1A && c8 == 0xE1) { 1530 1531 /* Above is signature of Microsoft Structured Storage. 1532 * Below this, could have tests for various SS entities. 1533 * For now, just test for FlashPix. 1534 */ 1535 if (checkfpx(is)) { 1536 return "image/vnd.fpx"; 1537 } 1538 } 1539 1540 if (c1 == 0x2E && c2 == 0x73 && c3 == 0x6E && c4 == 0x64) { 1541 return "audio/basic"; // .au format, big endian 1542 } 1543 1544 if (c1 == 0x64 && c2 == 0x6E && c3 == 0x73 && c4 == 0x2E) { 1545 return "audio/basic"; // .au format, little endian 1546 } 1547 1548 if (c1 == 'R' && c2 == 'I' && c3 == 'F' && c4 == 'F') { 1549 /* I don't know if this is official but evidence 1550 * suggests that .wav files start with "RIFF" - brown 1551 */ 1552 return "audio/x-wav"; 1553 } 1554 return null; 1555 } 1556 1557 /** 1558 * Check for FlashPix image data in InputStream is. Return true if 1559 * the stream has FlashPix data, false otherwise. Before calling this 1560 * method, the stream should have already been checked to be sure it 1561 * contains Microsoft Structured Storage data. 1562 */ 1563 static private boolean checkfpx(InputStream is) throws IOException { 1564 1565 /* Test for FlashPix image data in Microsoft Structured Storage format. 1566 * In general, should do this with calls to an SS implementation. 1567 * Lacking that, need to dig via offsets to get to the FlashPix 1568 * ClassID. Details: 1569 * 1570 * Offset to Fpx ClsID from beginning of stream should be: 1571 * 1572 * FpxClsidOffset = rootEntryOffset + clsidOffset 1573 * 1574 * where: clsidOffset = 0x50. 1575 * rootEntryOffset = headerSize + sectorSize*sectDirStart 1576 * + 128*rootEntryDirectory 1577 * 1578 * where: headerSize = 0x200 (always) 1579 * sectorSize = 2 raised to power of uSectorShift, 1580 * which is found in the header at 1581 * offset 0x1E. 1582 * sectDirStart = found in the header at offset 0x30. 1583 * rootEntryDirectory = in general, should search for 1584 * directory labelled as root. 1585 * We will assume value of 0 (i.e., 1586 * rootEntry is in first directory) 1587 */ 1588 1589 // Mark the stream so we can reset it. 0x100 is enough for the first 1590 // few reads, but the mark will have to be reset and set again once 1591 // the offset to the root directory entry is computed. That offset 1592 // can be very large and isn't know until the stream has been read from 1593 is.mark(0x100); 1594 1595 // Get the byte ordering located at 0x1E. 0xFE is Intel, 1596 // 0xFF is other 1597 long toSkip = (long)0x1C; 1598 long posn; 1599 1600 if ((posn = skipForward(is, toSkip)) < toSkip) { 1601 is.reset(); 1602 return false; 1603 } 1604 1605 int c[] = new int[16]; 1606 if (readBytes(c, 2, is) < 0) { 1607 is.reset(); 1608 return false; 1609 } 1610 1611 int byteOrder = c[0]; 1612 1613 posn+=2; 1614 int uSectorShift; 1615 if (readBytes(c, 2, is) < 0) { 1616 is.reset(); 1617 return false; 1618 } 1619 1620 if(byteOrder == 0xFE) { 1621 uSectorShift = c[0]; 1622 uSectorShift += c[1] << 8; 1623 } 1624 else { 1625 uSectorShift = c[0] << 8; 1626 uSectorShift += c[1]; 1627 } 1628 1629 posn += 2; 1630 toSkip = (long)0x30 - posn; 1631 long skipped = 0; 1632 if ((skipped = skipForward(is, toSkip)) < toSkip) { 1633 is.reset(); 1634 return false; 1635 } 1636 posn += skipped; 1637 1638 if (readBytes(c, 4, is) < 0) { 1639 is.reset(); 1640 return false; 1641 } 1642 1643 int sectDirStart; 1644 if(byteOrder == 0xFE) { 1645 sectDirStart = c[0]; 1646 sectDirStart += c[1] << 8; 1647 sectDirStart += c[2] << 16; 1648 sectDirStart += c[3] << 24; 1649 } else { 1650 sectDirStart = c[0] << 24; 1651 sectDirStart += c[1] << 16; 1652 sectDirStart += c[2] << 8; 1653 sectDirStart += c[3]; 1654 } 1655 posn += 4; 1656 is.reset(); // Reset back to the beginning 1657 1658 toSkip = 0x200L + (long)(1<<uSectorShift)*sectDirStart + 0x50L; 1659 1660 // Sanity check! 1661 if (toSkip < 0) { 1662 return false; 1663 } 1664 1665 /* 1666 * How far can we skip? Is there any performance problem here? 1667 * This skip can be fairly long, at least 0x4c650 in at least 1668 * one case. Have to assume that the skip will fit in an int. 1669 * Leave room to read whole root dir 1670 */ 1671 is.mark((int)toSkip+0x30); 1672 1673 if ((skipForward(is, toSkip)) < toSkip) { 1674 is.reset(); 1675 return false; 1676 } 1677 1678 /* should be at beginning of ClassID, which is as follows 1679 * (in Intel byte order): 1680 * 00 67 61 56 54 C1 CE 11 85 53 00 AA 00 A1 F9 5B 1681 * 1682 * This is stored from Windows as long,short,short,char[8] 1683 * so for byte order changes, the order only changes for 1684 * the first 8 bytes in the ClassID. 1685 * 1686 * Test against this, ignoring second byte (Intel) since 1687 * this could change depending on part of Fpx file we have. 1688 */ 1689 1690 if (readBytes(c, 16, is) < 0) { 1691 is.reset(); 1692 return false; 1693 } 1694 1695 // intel byte order 1696 if (byteOrder == 0xFE && 1697 c[0] == 0x00 && c[2] == 0x61 && c[3] == 0x56 && 1698 c[4] == 0x54 && c[5] == 0xC1 && c[6] == 0xCE && 1699 c[7] == 0x11 && c[8] == 0x85 && c[9] == 0x53 && 1700 c[10]== 0x00 && c[11]== 0xAA && c[12]== 0x00 && 1701 c[13]== 0xA1 && c[14]== 0xF9 && c[15]== 0x5B) { 1702 is.reset(); 1703 return true; 1704 } 1705 1706 // non-intel byte order 1707 else if (c[3] == 0x00 && c[1] == 0x61 && c[0] == 0x56 && 1708 c[5] == 0x54 && c[4] == 0xC1 && c[7] == 0xCE && 1709 c[6] == 0x11 && c[8] == 0x85 && c[9] == 0x53 && 1710 c[10]== 0x00 && c[11]== 0xAA && c[12]== 0x00 && 1711 c[13]== 0xA1 && c[14]== 0xF9 && c[15]== 0x5B) { 1712 is.reset(); 1713 return true; 1714 } 1715 is.reset(); 1716 return false; 1717 } 1718 1719 /** 1720 * Tries to read the specified number of bytes from the stream 1721 * Returns -1, If EOF is reached before len bytes are read, returns 0 1722 * otherwise 1723 */ 1724 static private int readBytes(int c[], int len, InputStream is) 1725 throws IOException { 1726 1727 byte buf[] = new byte[len]; 1728 if (is.read(buf, 0, len) < len) { 1729 return -1; 1730 } 1731 1732 // fill the passed in int array 1733 for (int i = 0; i < len; i++) { 1734 c[i] = buf[i] & 0xff; 1735 } 1736 return 0; 1737 } 1738 1739 1740 /** 1741 * Skips through the specified number of bytes from the stream 1742 * until either EOF is reached, or the specified 1743 * number of bytes have been skipped 1744 */ 1745 static private long skipForward(InputStream is, long toSkip) 1746 throws IOException { 1747 1748 long eachSkip = 0; 1749 long skipped = 0; 1750 1751 while (skipped != toSkip) { 1752 eachSkip = is.skip(toSkip - skipped); 1753 1754 // check if EOF is reached 1755 if (eachSkip <= 0) { 1756 if (is.read() == -1) { 1757 return skipped ; 1758 } else { 1759 skipped++; 1760 } 1761 } 1762 skipped += eachSkip; 1763 } 1764 return skipped; 1765 } 1766 1767 } 1768 1769 1770 class UnknownContentHandler extends ContentHandler { 1771 static final ContentHandler INSTANCE = new UnknownContentHandler(); 1772 1773 public Object getContent(URLConnection uc) throws IOException { 1774 return uc.getInputStream(); 1775 } 1776 }