001: /*
002: * Copyright 1995-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.net.www;
027:
028: import java.net.URL;
029: import java.net.ContentHandler;
030: import java.util.*;
031: import java.io.InputStream;
032: import java.io.OutputStream;
033: import java.io.BufferedInputStream;
034: import java.net.UnknownServiceException;
035:
036: /**
037: * A class to represent an active connection to an object
038: * represented by a URL.
039: * @author James Gosling
040: */
041:
042: abstract public class URLConnection extends java.net.URLConnection {
043:
044: /** The URL that it is connected to */
045:
046: private String contentType;
047: private int contentLength = -1;
048:
049: protected MessageHeader properties;
050:
051: /** Create a URLConnection object. These should not be created directly:
052: instead they should be created by protocol handers in response to
053: URL.openConnection.
054: @param u The URL that this connects to.
055: */
056: public URLConnection(URL u) {
057: super (u);
058: properties = new MessageHeader();
059: }
060:
061: /** Call this routine to get the property list for this object.
062: * Properties (like content-type) that have explicit getXX() methods
063: * associated with them should be accessed using those methods. */
064: public MessageHeader getProperties() {
065: return properties;
066: }
067:
068: /** Call this routine to set the property list for this object. */
069: public void setProperties(MessageHeader properties) {
070: this .properties = properties;
071: }
072:
073: public void setRequestProperty(String key, String value) {
074: if (connected)
075: throw new IllegalAccessError("Already connected");
076: if (key == null)
077: throw new NullPointerException("key cannot be null");
078: properties.set(key, value);
079: }
080:
081: /**
082: * The following three methods addRequestProperty, getRequestProperty,
083: * and getRequestProperties were copied from the superclass implementation
084: * before it was changed by CR:6230836, to maintain backward compatibility.
085: */
086: public void addRequestProperty(String key, String value) {
087: if (connected)
088: throw new IllegalStateException("Already connected");
089: if (key == null)
090: throw new NullPointerException("key is null");
091: }
092:
093: public String getRequestProperty(String key) {
094: if (connected)
095: throw new IllegalStateException("Already connected");
096: return null;
097: }
098:
099: 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
177: || ce != null
178: && !(ce.equalsIgnoreCase("7bit")
179: || ce.equalsIgnoreCase("8bit") || ce
180: .equalsIgnoreCase("binary")))
181: ct = "content/unknown";
182: setContentType(ct);
183: }
184: return contentType;
185: }
186:
187: /**
188: * Set the content type of this URL to a specific value.
189: * @param type The content type to use. One of the
190: * content_* static variables in this
191: * class should be used.
192: * eg. setType(URL.content_html);
193: */
194: public void setContentType(String type) {
195: contentType = type;
196: properties.set("content-type", type);
197: }
198:
199: /** Call this routine to get the content-length associated with this
200: * object.
201: */
202: public int getContentLength() {
203: try {
204: getInputStream();
205: } catch (Exception e) {
206: return -1;
207: }
208: int l = contentLength;
209: if (l < 0) {
210: try {
211: l = Integer.parseInt(properties
212: .findValue("content-length"));
213: setContentLength(l);
214: } catch (Exception e) {
215: }
216: }
217: return l;
218: }
219:
220: /** Call this routine to set the content-length associated with this
221: * object.
222: */
223: protected void setContentLength(int length) {
224: contentLength = length;
225: properties.set("content-length", String.valueOf(length));
226: }
227:
228: /**
229: * Returns true if the data associated with this URL can be cached.
230: */
231: public boolean canCache() {
232: return url.getFile().indexOf('?') < 0 /* && url.postData == null
233: REMIND */;
234: }
235:
236: /**
237: * Call this to close the connection and flush any remaining data.
238: * Overriders must remember to call super.close()
239: */
240: public void close() {
241: url = null;
242: }
243: }
|