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