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