Home | History | Annotate | Download | only in www
      1 /*
      2  * Copyright (c) 1995, 2011, 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 sun.net.www;
     27 
     28 import java.net.URL;
     29 import java.util.*;
     30 
     31 /**
     32  * A class to represent an active connection to an object
     33  * represented by a URL.
     34  * @author  James Gosling
     35  */
     36 
     37 abstract public class URLConnection extends java.net.URLConnection {
     38 
     39     /** The URL that it is connected to */
     40 
     41     private String contentType;
     42     private int contentLength = -1;
     43 
     44     protected MessageHeader properties;
     45 
     46     /** Create a URLConnection object.  These should not be created directly:
     47         instead they should be created by protocol handers in response to
     48         URL.openConnection.
     49         @param  u       The URL that this connects to.
     50      */
     51     public URLConnection (URL u) {
     52         super(u);
     53         properties = new MessageHeader();
     54     }
     55 
     56     /** Call this routine to get the property list for this object.
     57      * Properties (like content-type) that have explicit getXX() methods
     58      * associated with them should be accessed using those methods.  */
     59     public MessageHeader getProperties() {
     60         return properties;
     61     }
     62 
     63     /** Call this routine to set the property list for this object. */
     64     public void setProperties(MessageHeader properties) {
     65         this.properties = properties;
     66     }
     67 
     68     public void setRequestProperty(String key, String value) {
     69         if(connected)
     70             throw new IllegalAccessError("Already connected");
     71         if (key == null)
     72             throw new NullPointerException ("key cannot be null");
     73         properties.set(key, value);
     74     }
     75 
     76     /**
     77      * The following three methods addRequestProperty, getRequestProperty,
     78      * and getRequestProperties were copied from the superclass implementation
     79      * before it was changed by CR:6230836, to maintain backward compatibility.
     80      */
     81     public void addRequestProperty(String key, String value) {
     82         if (connected)
     83             throw new IllegalStateException("Already connected");
     84         if (key == null)
     85             throw new NullPointerException ("key is null");
     86     }
     87 
     88     public String getRequestProperty(String key) {
     89         if (connected)
     90             throw new IllegalStateException("Already connected");
     91         return null;
     92     }
     93 
     94     public Map<String,List<String>> getRequestProperties() {
     95         if (connected)
     96             throw new IllegalStateException("Already connected");
     97         return Collections.emptyMap();
     98     }
     99 
    100     public String getHeaderField(String name) {
    101         try {
    102             getInputStream();
    103         } catch (Exception e) {
    104             return null;
    105         }
    106         return properties == null ? null : properties.findValue(name);
    107     }
    108 
    109     /**
    110      * Return the key for the nth header field. Returns null if
    111      * there are fewer than n fields.  This can be used to iterate
    112      * through all the headers in the message.
    113      */
    114     public String getHeaderFieldKey(int n) {
    115         try {
    116             getInputStream();
    117         } catch (Exception e) {
    118             return null;
    119         }
    120         MessageHeader props = properties;
    121         return props == null ? null : props.getKey(n);
    122     }
    123 
    124     /**
    125      * Return the value for the nth header field. Returns null if
    126      * there are fewer than n fields.  This can be used in conjunction
    127      * with getHeaderFieldKey to iterate through all the headers in the message.
    128      */
    129     public String getHeaderField(int n) {
    130         try {
    131             getInputStream();
    132         } catch (Exception e) {
    133             return null;
    134         }
    135         MessageHeader props = properties;
    136         return props == null ? null : props.getValue(n);
    137     }
    138 
    139     /** Call this routine to get the content-type associated with this
    140      * object.
    141      */
    142     public String getContentType() {
    143         if (contentType == null)
    144             contentType = getHeaderField("content-type");
    145         if (contentType == null) {
    146             String ct = null;
    147             try {
    148                 ct = guessContentTypeFromStream(getInputStream());
    149             } catch(java.io.IOException e) {
    150             }
    151             String ce = properties.findValue("content-encoding");
    152             if (ct == null) {
    153                 ct = properties.findValue("content-type");
    154 
    155                 if (ct == null)
    156                     if (url.getFile().endsWith("/"))
    157                         ct = "text/html";
    158                     else
    159                         ct = guessContentTypeFromName(url.getFile());
    160             }
    161 
    162             /*
    163              * If the Mime header had a Content-encoding field and its value
    164              * was not one of the values that essentially indicate no
    165              * encoding, we force the content type to be unknown. This will
    166              * cause a save dialog to be presented to the user.  It is not
    167              * ideal but is better than what we were previously doing, namely
    168              * bringing up an image tool for compressed tar files.
    169              */
    170 
    171             if (ct == null || ce != null &&
    172                     !(ce.equalsIgnoreCase("7bit")
    173                       || ce.equalsIgnoreCase("8bit")
    174                       || ce.equalsIgnoreCase("binary")))
    175                 ct = "content/unknown";
    176             setContentType(ct);
    177         }
    178         return contentType;
    179     }
    180 
    181     /**
    182      * Set the content type of this URL to a specific value.
    183      * @param   type    The content type to use.  One of the
    184      *                  content_* static variables in this
    185      *                  class should be used.
    186      *                  eg. setType(URL.content_html);
    187      */
    188     public void setContentType(String type) {
    189         contentType = type;
    190         properties.set("content-type", type);
    191     }
    192 
    193     /** Call this routine to get the content-length associated with this
    194      * object.
    195      */
    196     public int getContentLength() {
    197         try {
    198             getInputStream();
    199         } catch (Exception e) {
    200             return -1;
    201         }
    202         int l = contentLength;
    203         if (l < 0) {
    204             try {
    205                 l = Integer.parseInt(properties.findValue("content-length"));
    206                 setContentLength(l);
    207             } catch(Exception e) {
    208             }
    209         }
    210         return l;
    211     }
    212 
    213     /** Call this routine to set the content-length associated with this
    214      * object.
    215      */
    216     protected void setContentLength(int length) {
    217         contentLength = length;
    218         properties.set("content-length", String.valueOf(length));
    219     }
    220 
    221     /**
    222      * Returns true if the data associated with this URL can be cached.
    223      */
    224     public boolean canCache() {
    225         return url.getFile().indexOf('?') < 0   /* && url.postData == null
    226                 REMIND */ ;
    227     }
    228 
    229     /**
    230      * Call this to close the connection and flush any remaining data.
    231      * Overriders must remember to call super.close()
    232      */
    233     public void close() {
    234         url = null;
    235     }
    236 
    237     private static HashMap<String,Void> proxiedHosts = new HashMap<>();
    238 
    239     public synchronized static void setProxiedHost(String host) {
    240         proxiedHosts.put(host.toLowerCase(), null);
    241     }
    242 
    243     public synchronized static boolean isProxiedHost(String host) {
    244         return proxiedHosts.containsKey(host.toLowerCase());
    245     }
    246 }
    247