View Javadoc
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 }