Path: blob/master/src/java.base/share/classes/sun/net/www/URLConnection.java
41159 views
/*1* Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.net.www;2627import java.io.IOException;28import java.net.URL;29import java.util.*;3031/**32* A class to represent an active connection to an object33* represented by a URL.34* @author James Gosling35*/3637public abstract class URLConnection extends java.net.URLConnection {3839/** The URL that it is connected to */4041private String contentType;42private int contentLength = -1;4344protected MessageHeader properties;4546/**47* Create a URLConnection object. These should not be created directly:48* instead they should be created by protocol handlers in response to49* URL.openConnection.50* @param u The URL that this connects to.51*/52public URLConnection (URL u) {53super(u);54properties = new MessageHeader();55}5657/**58* Call this routine to get the property list for this object.59* Properties (like content-type) that have explicit getXX() methods60* associated with them should be accessed using those methods.61*/62public MessageHeader getProperties() {63return properties;64}6566/** Call this routine to set the property list for this object. */67public void setProperties(MessageHeader properties) {68this.properties = properties;69}7071public void setRequestProperty(String key, String value) {72if(connected)73throw new IllegalStateException("Already connected");74if (key == null)75throw new NullPointerException ("key cannot be null");76properties.set(key, value);77}7879/**80* The following three methods addRequestProperty, getRequestProperty,81* and getRequestProperties were copied from the superclass implementation82* before it was changed by CR:6230836, to maintain backward compatibility.83*/84public void addRequestProperty(String key, String value) {85if (connected)86throw new IllegalStateException("Already connected");87if (key == null)88throw new NullPointerException ("key is null");89}9091public String getRequestProperty(String key) {92if (connected)93throw new IllegalStateException("Already connected");94return null;95}9697public Map<String,List<String>> getRequestProperties() {98if (connected)99throw new IllegalStateException("Already connected");100return Collections.emptyMap();101}102103public String getHeaderField(String name) {104try {105getInputStream();106} catch (Exception e) {107return null;108}109return properties == null ? null : properties.findValue(name);110}111112113Map<String, List<String>> headerFields;114115@Override116public Map<String, List<String>> getHeaderFields() {117if (headerFields == null) {118try {119getInputStream();120if (properties == null) {121headerFields = super.getHeaderFields();122} else {123headerFields = properties.getHeaders();124}125} catch (IOException e) {126return super.getHeaderFields();127}128}129return headerFields;130}131132/**133* Return the key for the nth header field. Returns null if134* there are fewer than n fields. This can be used to iterate135* through all the headers in the message.136*/137public String getHeaderFieldKey(int n) {138try {139getInputStream();140} catch (Exception e) {141return null;142}143MessageHeader props = properties;144return props == null ? null : props.getKey(n);145}146147/**148* Return the value for the nth header field. Returns null if149* there are fewer than n fields. This can be used in conjunction150* with getHeaderFieldKey to iterate through all the headers in the message.151*/152public String getHeaderField(int n) {153try {154getInputStream();155} catch (Exception e) {156return null;157}158MessageHeader props = properties;159return props == null ? null : props.getValue(n);160}161162/**163* Call this routine to get the content-type associated with this164* object.165*/166public String getContentType() {167if (contentType == null)168contentType = getHeaderField("content-type");169if (contentType == null) {170String ct = null;171try {172ct = guessContentTypeFromStream(getInputStream());173} catch(java.io.IOException e) {174}175String ce = properties.findValue("content-encoding");176if (ct == null) {177ct = properties.findValue("content-type");178179if (ct == null)180if (url.getFile().endsWith("/"))181ct = "text/html";182else183ct = guessContentTypeFromName(url.getFile());184}185186/*187* If the Mime header had a Content-encoding field and its value188* was not one of the values that essentially indicate no189* encoding, we force the content type to be unknown. This will190* cause a save dialog to be presented to the user. It is not191* ideal but is better than what we were previously doing, namely192* bringing up an image tool for compressed tar files.193*/194195if (ct == null || ce != null &&196!(ce.equalsIgnoreCase("7bit")197|| ce.equalsIgnoreCase("8bit")198|| ce.equalsIgnoreCase("binary")))199ct = "content/unknown";200setContentType(ct);201}202return contentType;203}204205/**206* Set the content type of this URL to a specific value.207* @param type The content type to use. One of the208* content_* static variables in this209* class should be used.210* e.g. setType(URL.content_html);211*/212public void setContentType(String type) {213contentType = type;214properties.set("content-type", type);215}216217/**218* Call this routine to get the content-length associated with this219* object.220*/221public int getContentLength() {222try {223getInputStream();224} catch (Exception e) {225return -1;226}227int l = contentLength;228if (l < 0) {229try {230l = Integer.parseInt(properties.findValue("content-length"));231setContentLength(l);232} catch(Exception e) {233}234}235return l;236}237238/**239* Call this routine to set the content-length associated with this240* object.241*/242protected void setContentLength(int length) {243contentLength = length;244properties.set("content-length", String.valueOf(length));245}246247/**248* Returns true if the data associated with this URL can be cached.249*/250public boolean canCache() {251return url.getFile().indexOf('?') < 0 /* && url.postData == null252REMIND */ ;253}254255/**256* Call this to close the connection and flush any remaining data.257* Overriders must remember to call super.close()258*/259public void close() {260url = null;261}262263private static HashMap<String,Void> proxiedHosts = new HashMap<>();264265public static synchronized void setProxiedHost(String host) {266proxiedHosts.put(host.toLowerCase(), null);267}268269public static synchronized boolean isProxiedHost(String host) {270return proxiedHosts.containsKey(host.toLowerCase());271}272}273274275