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      */
URLConnection(URL u)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.  */
getProperties()59     public MessageHeader getProperties() {
60         return properties;
61     }
62 
63     /** Call this routine to set the property list for this object. */
setProperties(MessageHeader properties)64     public void setProperties(MessageHeader properties) {
65         this.properties = properties;
66     }
67 
setRequestProperty(String key, String value)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      */
addRequestProperty(String key, String value)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 
getRequestProperty(String key)88     public String getRequestProperty(String key) {
89         if (connected)
90             throw new IllegalStateException("Already connected");
91         return null;
92     }
93 
getRequestProperties()94     public Map<String,List<String>> getRequestProperties() {
95         if (connected)
96             throw new IllegalStateException("Already connected");
97         return Collections.emptyMap();
98     }
99 
getHeaderField(String name)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      */
getHeaderFieldKey(int n)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      */
getHeaderField(int n)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      */
getContentType()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      */
setContentType(String type)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      */
getContentLength()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      */
setContentLength(int length)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      */
canCache()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      */
close()233     public void close() {
234         url = null;
235     }
236 
237     private static HashMap<String,Void> proxiedHosts = new HashMap<>();
238 
setProxiedHost(String host)239     public synchronized static void setProxiedHost(String host) {
240         proxiedHosts.put(host.toLowerCase(), null);
241     }
242 
isProxiedHost(String host)243     public synchronized static boolean isProxiedHost(String host) {
244         return proxiedHosts.containsKey(host.toLowerCase());
245     }
246 }
247