/** Copyright (c) 1995, 2017, Oracle and/or its affiliates. All rights reserved.* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.*********************/package java.net;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.security.PrivilegedAction;import java.util.Hashtable;import java.util.concurrent.ConcurrentHashMap;import java.util.Date;import java.util.Iterator;import java.util.Locale;import java.util.Objects;import java.util.ServiceConfigurationError;import java.util.ServiceLoader;import java.util.StringTokenizer;import java.util.Collections;import java.util.Map;import java.util.List;import java.security.Permission;import java.security.AccessController;import sun.security.util.SecurityConstants;import sun.net.www.MessageHeader;import sun.security.action.GetPropertyAction;/*** The abstract class {@code URLConnection} is the superclass* of all classes that represent a communications link between the* application and a URL. Instances of this class can be used both to* read from and to write to the resource referenced by the URL.** <p>* In general, creating a connection to a URL is a multistep process:* <ol>* <li>The connection object is created by invoking the* {@link URL#openConnection() openConnection} method on a URL.* <li>The setup parameters and general request properties are manipulated.* <li>The actual connection to the remote object is made, using the* {@link #connect() connect} method.* <li>The remote object becomes available. The header fields and the contents* of the remote object can be accessed.* </ol>* <p>* The setup parameters are modified using the following methods:* <ul>* <li>{@code setAllowUserInteraction}* <li>{@code setDoInput}* <li>{@code setDoOutput}* <li>{@code setIfModifiedSince}* <li>{@code setUseCaches}* </ul>* <p>* and the general request properties are modified using the method:* <ul>* <li>{@code setRequestProperty}* </ul>* <p>* Default values for the {@code AllowUserInteraction} and* {@code UseCaches} parameters can be set using the methods* {@code setDefaultAllowUserInteraction} and* {@code setDefaultUseCaches}.* <p>* Each of the above {@code set} methods has a corresponding* {@code get} method to retrieve the value of the parameter or* general request property. The specific parameters and general* request properties that are applicable are protocol specific.* <p>* The following methods are used to access the header fields and* the contents after the connection is made to the remote object:* <ul>* <li>{@code getContent}* <li>{@code getHeaderField}* <li>{@code getInputStream}* <li>{@code getOutputStream}* </ul>* <p>* Certain header fields are accessed frequently. The methods:* <ul>* <li>{@code getContentEncoding}* <li>{@code getContentLength}* <li>{@code getContentType}* <li>{@code getDate}* <li>{@code getExpiration}* <li>{@code getLastModified}* </ul>* <p>* provide convenient access to these fields. The* {@code getContentType} method is used by the* {@code getContent} method to determine the type of the remote* object; subclasses may find it convenient to override the* {@code getContentType} method.* <p>* In the common case, all of the pre-connection parameters and* general request properties can be ignored: the pre-connection* parameters and request properties default to sensible values. For* most clients of this interface, there are only two interesting* methods: {@code getInputStream} and {@code getContent},* which are mirrored in the {@code URL} class by convenience methods.* <p>* More information on the request properties and header fields of* an {@code http} connection can be found at:* <blockquote><pre>* <a href="http://www.ietf.org/rfc/rfc2616.txt">http://www.ietf.org/rfc/rfc2616.txt</a>* </pre></blockquote>** Invoking the {@code close()} methods on the {@code InputStream} or {@code OutputStream} of an* {@code URLConnection} after a request may free network resources associated with this* instance, unless particular protocol specifications specify different behaviours* for it.** @author James Gosling* @see java.net.URL#openConnection()* @see java.net.URLConnection#connect()* @see java.net.URLConnection#getContent()* @see java.net.URLConnection#getContentEncoding()* @see java.net.URLConnection#getContentLength()* @see java.net.URLConnection#getContentType()* @see java.net.URLConnection#getDate()* @see java.net.URLConnection#getExpiration()* @see java.net.URLConnection#getHeaderField(int)* @see java.net.URLConnection#getHeaderField(java.lang.String)* @see java.net.URLConnection#getInputStream()* @see java.net.URLConnection#getLastModified()* @see java.net.URLConnection#getOutputStream()* @see java.net.URLConnection#setAllowUserInteraction(boolean)* @see java.net.URLConnection#setDefaultUseCaches(boolean)* @see java.net.URLConnection#setDoInput(boolean)* @see java.net.URLConnection#setDoOutput(boolean)* @see java.net.URLConnection#setIfModifiedSince(long)* @see java.net.URLConnection#setRequestProperty(java.lang.String, java.lang.String)* @see java.net.URLConnection#setUseCaches(boolean)* @since 1.0*/public abstract class URLConnection {/*** The URL represents the remote object on the World Wide Web to* which this connection is opened.* <p>* The value of this field can be accessed by the* {@code getURL} method.* <p>* The default value of this variable is the value of the URL* argument in the {@code URLConnection} constructor.** @see java.net.URLConnection#getURL()* @see java.net.URLConnection#url*/protected URL url;/*** This variable is set by the {@code setDoInput} method. Its* value is returned by the {@code getDoInput} method.* <p>* A URL connection can be used for input and/or output. Setting the* {@code doInput} flag to {@code true} indicates that* the application intends to read data from the URL connection.* <p>* The default value of this field is {@code true}.** @see java.net.URLConnection#getDoInput()* @see java.net.URLConnection#setDoInput(boolean)*/protected boolean doInput = true;/*** This variable is set by the {@code setDoOutput} method. Its* value is returned by the {@code getDoOutput} method.* <p>* A URL connection can be used for input and/or output. Setting the* {@code doOutput} flag to {@code true} indicates* that the application intends to write data to the URL connection.* <p>* The default value of this field is {@code false}.** @see java.net.URLConnection#getDoOutput()* @see java.net.URLConnection#setDoOutput(boolean)*/protected boolean doOutput = false;private static boolean defaultAllowUserInteraction = false;/*** If {@code true}, this {@code URL} is being examined in* a context in which it makes sense to allow user interactions such* as popping up an authentication dialog. If {@code false},* then no user interaction is allowed.* <p>* The value of this field can be set by the* {@code setAllowUserInteraction} method.* Its value is returned by the* {@code getAllowUserInteraction} method.* Its default value is the value of the argument in the last invocation* of the {@code setDefaultAllowUserInteraction} method.** @see java.net.URLConnection#getAllowUserInteraction()* @see java.net.URLConnection#setAllowUserInteraction(boolean)* @see java.net.URLConnection#setDefaultAllowUserInteraction(boolean)*/protected boolean allowUserInteraction = defaultAllowUserInteraction;private static volatile boolean defaultUseCaches = true;/*** If {@code true}, the protocol is allowed to use caching* whenever it can. If {@code false}, the protocol must always* try to get a fresh copy of the object.* <p>* This field is set by the {@code setUseCaches} method. Its* value is returned by the {@code getUseCaches} method.* <p>* Its default value is the value given in the last invocation of the* {@code setDefaultUseCaches} method.* <p>* The default setting may be overridden per protocol with* {@link #setDefaultUseCaches(String,boolean)}.** @see java.net.URLConnection#setUseCaches(boolean)* @see java.net.URLConnection#getUseCaches()* @see java.net.URLConnection#setDefaultUseCaches(boolean)*/protected boolean useCaches;private static final ConcurrentHashMap<String,Boolean> defaultCaching =new ConcurrentHashMap<>();/*** Some protocols support skipping the fetching of the object unless* the object has been modified more recently than a certain time.* <p>* A nonzero value gives a time as the number of milliseconds since* January 1, 1970, GMT. The object is fetched only if it has been* modified more recently than that time.* <p>* This variable is set by the {@code setIfModifiedSince}* method. Its value is returned by the* {@code getIfModifiedSince} method.* <p>* The default value of this field is {@code 0}, indicating* that the fetching must always occur.** @see java.net.URLConnection#getIfModifiedSince()* @see java.net.URLConnection#setIfModifiedSince(long)*/protected long ifModifiedSince = 0;/*** If {@code false}, this connection object has not created a* communications link to the specified URL. If {@code true},* the communications link has been established.*/protected boolean connected = false;/*** @since 1.5*/private int connectTimeout;private int readTimeout;/*** @since 1.6*/private MessageHeader requests;/*** @since 1.1*/private static volatile FileNameMap fileNameMap;/*** Loads filename map (a mimetable) from a data file. It will* first try to load the user-specific table, defined* by "content.types.user.table" property. If that fails,* it tries to load the default built-in table.** @return the FileNameMap* @since 1.2* @see #setFileNameMap(java.net.FileNameMap)*/public static FileNameMap getFileNameMap() {FileNameMap map = fileNameMap;if (map == null) {fileNameMap = map = new FileNameMap() {private FileNameMap internalMap =sun.net.www.MimeTable.loadTable();public String getContentTypeFor(String fileName) {return internalMap.getContentTypeFor(fileName);}};}return map;}/*** Sets the FileNameMap.* <p>* If there is a security manager, this method first calls* the security manager's {@code checkSetFactory} method* to ensure the operation is allowed.* This could result in a SecurityException.** @param map the FileNameMap to be set* @exception SecurityException if a security manager exists and its* {@code checkSetFactory} method doesn't allow the operation.* @see SecurityManager#checkSetFactory* @see #getFileNameMap()* @since 1.2*/public static void setFileNameMap(FileNameMap map) {SecurityManager sm = System.getSecurityManager();if (sm != null) sm.checkSetFactory();fileNameMap = map;}/*** Opens a communications link to the resource referenced by this* URL, if such a connection has not already been established.* <p>* If the {@code connect} method is called when the connection* has already been opened (indicated by the {@code connected}* field having the value {@code true}), the call is ignored.* <p>* URLConnection objects go through two phases: first they are* created, then they are connected. After being created, and* before being connected, various options can be specified* (e.g., doInput and UseCaches). After connecting, it is an* error to try to set them. Operations that depend on being* connected, like getContentLength, will implicitly perform the* connection, if necessary.** @throws SocketTimeoutException if the timeout expires before* the connection can be established* @exception IOException if an I/O error occurs while opening the* connection.* @see java.net.URLConnection#connected* @see #getConnectTimeout()* @see #setConnectTimeout(int)*/public abstract void connect() throws IOException;/*** Sets a specified timeout value, in milliseconds, to be used* when opening a communications link to the resource referenced* by this URLConnection. If the timeout expires before the* connection can be established, a* java.net.SocketTimeoutException is raised. A timeout of zero is* interpreted as an infinite timeout.* <p> Some non-standard implementation of this method may ignore* the specified timeout. To see the connect timeout set, please* call getConnectTimeout().** @param timeout an {@code int} that specifies the connect* timeout value in milliseconds* @throws IllegalArgumentException if the timeout parameter is negative** @see #getConnectTimeout()* @see #connect()* @since 1.5*/public void setConnectTimeout(int timeout) {if (timeout < 0) {throw new IllegalArgumentException("timeout can not be negative");}connectTimeout = timeout;}/*** Returns setting for connect timeout.* <p>* 0 return implies that the option is disabled* (i.e., timeout of infinity).** @return an {@code int} that indicates the connect timeout* value in milliseconds* @see #setConnectTimeout(int)* @see #connect()* @since 1.5*/public int getConnectTimeout() {return connectTimeout;}/*** Sets the read timeout to a specified timeout, in* milliseconds. A non-zero value specifies the timeout when* reading from Input stream when a connection is established to a* resource. If the timeout expires before there is data available* for read, a java.net.SocketTimeoutException is raised. A* timeout of zero is interpreted as an infinite timeout.**<p> Some non-standard implementation of this method ignores the* specified timeout. To see the read timeout set, please call* getReadTimeout().** @param timeout an {@code int} that specifies the timeout* value to be used in milliseconds* @throws IllegalArgumentException if the timeout parameter is negative** @see #getReadTimeout()* @see InputStream#read()* @since 1.5*/public void setReadTimeout(int timeout) {if (timeout < 0) {throw new IllegalArgumentException("timeout can not be negative");}readTimeout = timeout;}/*** Returns setting for read timeout. 0 return implies that the* option is disabled (i.e., timeout of infinity).** @return an {@code int} that indicates the read timeout* value in milliseconds** @see #setReadTimeout(int)* @see InputStream#read()* @since 1.5*/public int getReadTimeout() {return readTimeout;}/*** Constructs a URL connection to the specified URL. A connection to* the object referenced by the URL is not created.** @param url the specified URL.*/protected URLConnection(URL url) {this.url = url;if (url == null) {this.useCaches = defaultUseCaches;} else {this.useCaches = getDefaultUseCaches(url.getProtocol());}}/*** Returns the value of this {@code URLConnection}'s {@code URL}* field.** @return the value of this {@code URLConnection}'s {@code URL}* field.* @see java.net.URLConnection#url*/public URL getURL() {return url;}/*** Returns the value of the {@code content-length} header field.* <P>* <B>Note</B>: {@link #getContentLengthLong() getContentLengthLong()}* should be preferred over this method, since it returns a {@code long}* instead and is therefore more portable.</P>** @return the content length of the resource that this connection's URL* references, {@code -1} if the content length is not known,* or if the content length is greater than Integer.MAX_VALUE.*/public int getContentLength() {long l = getContentLengthLong();if (l > Integer.MAX_VALUE)return -1;return (int) l;}/*** Returns the value of the {@code content-length} header field as a* long.** @return the content length of the resource that this connection's URL* references, or {@code -1} if the content length is* not known.* @since 1.7*/public long getContentLengthLong() {return getHeaderFieldLong("content-length", -1);}/*** Returns the value of the {@code content-type} header field.** @return the content type of the resource that the URL references,* or {@code null} if not known.* @see java.net.URLConnection#getHeaderField(java.lang.String)*/public String getContentType() {return getHeaderField("content-type");}/*** Returns the value of the {@code content-encoding} header field.** @return the content encoding of the resource that the URL references,* or {@code null} if not known.* @see java.net.URLConnection#getHeaderField(java.lang.String)*/public String getContentEncoding() {return getHeaderField("content-encoding");}/*** Returns the value of the {@code expires} header field.** @return the expiration date of the resource that this URL references,* or 0 if not known. The value is the number of milliseconds since* January 1, 1970 GMT.* @see java.net.URLConnection#getHeaderField(java.lang.String)*/public long getExpiration() {return getHeaderFieldDate("expires", 0);}/*** Returns the value of the {@code date} header field.** @return the sending date of the resource that the URL references,* or {@code 0} if not known. The value returned is the* number of milliseconds since January 1, 1970 GMT.* @see java.net.URLConnection#getHeaderField(java.lang.String)*/public long getDate() {return getHeaderFieldDate("date", 0);}/*** Returns the value of the {@code last-modified} header field.* The result is the number of milliseconds since January 1, 1970 GMT.** @return the date the resource referenced by this* {@code URLConnection} was last modified, or 0 if not known.* @see java.net.URLConnection#getHeaderField(java.lang.String)*/public long getLastModified() {return getHeaderFieldDate("last-modified", 0);}/*** Returns the value of the named header field.* <p>* If called on a connection that sets the same header multiple times* with possibly different values, only the last value is returned.*** @param name the name of a header field.* @return the value of the named header field, or {@code null}* if there is no such field in the header.*/public String getHeaderField(String name) {return null;}/*** Returns an unmodifiable Map of the header fields.* The Map keys are Strings that represent the* response-header field names. Each Map value is an* unmodifiable List of Strings that represents* the corresponding field values.** @return a Map of header fields* @since 1.4*/public Map<String,List<String>> getHeaderFields() {return Collections.emptyMap();}/*** Returns the value of the named field parsed as a number.* <p>* This form of {@code getHeaderField} exists because some* connection types (e.g., {@code http-ng}) have pre-parsed* headers. Classes for that connection type can override this method* and short-circuit the parsing.** @param name the name of the header field.* @param Default the default value.* @return the value of the named field, parsed as an integer. The* {@code Default} value is returned if the field is* missing or malformed.*/public int getHeaderFieldInt(String name, int Default) {String value = getHeaderField(name);try {return Integer.parseInt(value);} catch (Exception e) { }return Default;}/*** Returns the value of the named field parsed as a number.* <p>* This form of {@code getHeaderField} exists because some* connection types (e.g., {@code http-ng}) have pre-parsed* headers. Classes for that connection type can override this method* and short-circuit the parsing.** @param name the name of the header field.* @param Default the default value.* @return the value of the named field, parsed as a long. The* {@code Default} value is returned if the field is* missing or malformed.* @since 1.7*/public long getHeaderFieldLong(String name, long Default) {String value = getHeaderField(name);try {return Long.parseLong(value);} catch (Exception e) { }return Default;}/*** Returns the value of the named field parsed as date.* The result is the number of milliseconds since January 1, 1970 GMT* represented by the named field.* <p>* This form of {@code getHeaderField} exists because some* connection types (e.g., {@code http-ng}) have pre-parsed* headers. Classes for that connection type can override this method* and short-circuit the parsing.** @param name the name of the header field.* @param Default a default value.* @return the value of the field, parsed as a date. The value of the* {@code Default} argument is returned if the field is* missing or malformed.*/@SuppressWarnings("deprecation")public long getHeaderFieldDate(String name, long Default) {String value = getHeaderField(name);try {return Date.parse(value);} catch (Exception e) { }return Default;}/*** Returns the key for the {@code n}<sup>th</sup> header field.* It returns {@code null} if there are fewer than {@code n+1} fields.** @param n an index, where {@code n>=0}* @return the key for the {@code n}<sup>th</sup> header field,* or {@code null} if there are fewer than {@code n+1}* fields.*/public String getHeaderFieldKey(int n) {return null;}/*** Returns the value for the {@code n}<sup>th</sup> header field.* It returns {@code null} if there are fewer than* {@code n+1}fields.* <p>* This method can be used in conjunction with the* {@link #getHeaderFieldKey(int) getHeaderFieldKey} method to iterate through all* the headers in the message.** @param n an index, where {@code n>=0}* @return the value of the {@code n}<sup>th</sup> header field* or {@code null} if there are fewer than {@code n+1} fields* @see java.net.URLConnection#getHeaderFieldKey(int)*/public String getHeaderField(int n) {return null;}/*** Retrieves the contents of this URL connection.* <p>* This method first determines the content type of the object by* calling the {@code getContentType} method. If this is* the first time that the application has seen that specific content* type, a content handler for that content type is created.* <p> This is done as follows:* <ol>* <li>If the application has set up a content handler factory instance* using the {@code setContentHandlerFactory} method, the* {@code createContentHandler} method of that instance is called* with the content type as an argument; the result is a content* handler for that content type.* <li>If no {@code ContentHandlerFactory} has yet been set up,* or if the factory's {@code createContentHandler} method* returns {@code null}, then the {@linkplain java.util.ServiceLoader* ServiceLoader} mechanism is used to locate {@linkplain* java.net.ContentHandlerFactory ContentHandlerFactory}* implementations using the system class* loader. The order that factories are located is implementation* specific, and an implementation is free to cache the located* factories. A {@linkplain java.util.ServiceConfigurationError* ServiceConfigurationError}, {@code Error} or {@code RuntimeException}* thrown from the {@code createContentHandler}, if encountered, will* be propagated to the calling thread. The {@code* createContentHandler} method of each factory, if instantiated, is* invoked, with the content type, until a factory returns non-null,* or all factories have been exhausted.* <li>Failing that, this method tries to load a content handler* class as defined by {@link java.net.ContentHandler ContentHandler}.* If the class does not exist, or is not a subclass of {@code* ContentHandler}, then an {@code UnknownServiceException} is thrown.* </ol>** @return the object fetched. The {@code instanceof} operator* should be used to determine the specific kind of object* returned.* @exception IOException if an I/O error occurs while* getting the content.* @exception UnknownServiceException if the protocol does not support* the content type.* @see java.net.ContentHandlerFactory#createContentHandler(java.lang.String)* @see java.net.URLConnection#getContentType()* @see java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory)*/public Object getContent() throws IOException {// Must call getInputStream before GetHeaderField gets called// so that FileNotFoundException has a chance to be thrown up// from here without being caught.getInputStream();return getContentHandler().getContent(this);}/*** Retrieves the contents of this URL connection.** @param classes the {@code Class} array* indicating the requested types* @return the object fetched that is the first match of the type* specified in the classes array. null if none of* the requested types are supported.* The {@code instanceof} operator should be used to* determine the specific kind of object returned.* @exception IOException if an I/O error occurs while* getting the content.* @exception UnknownServiceException if the protocol does not support* the content type.* @see java.net.URLConnection#getContent()* @see java.net.ContentHandlerFactory#createContentHandler(java.lang.String)* @see java.net.URLConnection#getContent(java.lang.Class[])* @see java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory)* @since 1.3*/public Object getContent(Class<?>[] classes) throws IOException {// Must call getInputStream before GetHeaderField gets called// so that FileNotFoundException has a chance to be thrown up// from here without being caught.getInputStream();return getContentHandler().getContent(this, classes);}/*** Returns a permission object representing the permission* necessary to make the connection represented by this* object. This method returns null if no permission is* required to make the connection. By default, this method* returns {@code java.security.AllPermission}. Subclasses* should override this method and return the permission* that best represents the permission required to make* a connection to the URL. For example, a {@code URLConnection}* representing a {@code file:} URL would return a* {@code java.io.FilePermission} object.** <p>The permission returned may dependent upon the state of the* connection. For example, the permission before connecting may be* different from that after connecting. For example, an HTTP* sever, say foo.com, may redirect the connection to a different* host, say bar.com. Before connecting the permission returned by* the connection will represent the permission needed to connect* to foo.com, while the permission returned after connecting will* be to bar.com.** <p>Permissions are generally used for two purposes: to protect* caches of objects obtained through URLConnections, and to check* the right of a recipient to learn about a particular URL. In* the first case, the permission should be obtained* <em>after</em> the object has been obtained. For example, in an* HTTP connection, this will represent the permission to connect* to the host from which the data was ultimately fetched. In the* second case, the permission should be obtained and tested* <em>before</em> connecting.** @return the permission object representing the permission* necessary to make the connection represented by this* URLConnection.** @exception IOException if the computation of the permission* requires network or file I/O and an exception occurs while* computing it.*/public Permission getPermission() throws IOException {return SecurityConstants.ALL_PERMISSION;}/*** Returns an input stream that reads from this open connection.** A SocketTimeoutException can be thrown when reading from the* returned input stream if the read timeout expires before data* is available for read.** @return an input stream that reads from this open connection.* @exception IOException if an I/O error occurs while* creating the input stream.* @exception UnknownServiceException if the protocol does not support* input.* @see #setReadTimeout(int)* @see #getReadTimeout()*/public InputStream getInputStream() throws IOException {throw new UnknownServiceException("protocol doesn't support input");}/*** Returns an output stream that writes to this connection.** @return an output stream that writes to this connection.* @exception IOException if an I/O error occurs while* creating the output stream.* @exception UnknownServiceException if the protocol does not support* output.*/public OutputStream getOutputStream() throws IOException {throw new UnknownServiceException("protocol doesn't support output");}/*** Returns a {@code String} representation of this URL connection.** @return a string representation of this {@code URLConnection}.*/public String toString() {return this.getClass().getName() + ":" + url;}/*** Sets the value of the {@code doInput} field for this* {@code URLConnection} to the specified value.* <p>* A URL connection can be used for input and/or output. Set the doInput* flag to true if you intend to use the URL connection for input,* false if not. The default is true.** @param doinput the new value.* @throws IllegalStateException if already connected* @see java.net.URLConnection#doInput* @see #getDoInput()*/public void setDoInput(boolean doinput) {checkConnected();doInput = doinput;}/*** Returns the value of this {@code URLConnection}'s* {@code doInput} flag.** @return the value of this {@code URLConnection}'s* {@code doInput} flag.* @see #setDoInput(boolean)*/public boolean getDoInput() {return doInput;}/*** Sets the value of the {@code doOutput} field for this* {@code URLConnection} to the specified value.* <p>* A URL connection can be used for input and/or output. Set the doOutput* flag to true if you intend to use the URL connection for output,* false if not. The default is false.** @param dooutput the new value.* @throws IllegalStateException if already connected* @see #getDoOutput()*/public void setDoOutput(boolean dooutput) {checkConnected();doOutput = dooutput;}/*** Returns the value of this {@code URLConnection}'s* {@code doOutput} flag.** @return the value of this {@code URLConnection}'s* {@code doOutput} flag.* @see #setDoOutput(boolean)*/public boolean getDoOutput() {return doOutput;}/*** Set the value of the {@code allowUserInteraction} field of* this {@code URLConnection}.** @param allowuserinteraction the new value.* @throws IllegalStateException if already connected* @see #getAllowUserInteraction()*/public void setAllowUserInteraction(boolean allowuserinteraction) {checkConnected();allowUserInteraction = allowuserinteraction;}/*** Returns the value of the {@code allowUserInteraction} field for* this object.** @return the value of the {@code allowUserInteraction} field for* this object.* @see #setAllowUserInteraction(boolean)*/public boolean getAllowUserInteraction() {return allowUserInteraction;}/*** Sets the default value of the* {@code allowUserInteraction} field for all future* {@code URLConnection} objects to the specified value.** @param defaultallowuserinteraction the new value.* @see #getDefaultAllowUserInteraction()*/public static void setDefaultAllowUserInteraction(boolean defaultallowuserinteraction) {defaultAllowUserInteraction = defaultallowuserinteraction;}/*** Returns the default value of the {@code allowUserInteraction}* field.* <p>* This default is "sticky", being a part of the static state of all* URLConnections. This flag applies to the next, and all following* URLConnections that are created.** @return the default value of the {@code allowUserInteraction}* field.* @see #setDefaultAllowUserInteraction(boolean)*/public static boolean getDefaultAllowUserInteraction() {return defaultAllowUserInteraction;}/*** Sets the value of the {@code useCaches} field of this* {@code URLConnection} to the specified value.* <p>* Some protocols do caching of documents. Occasionally, it is important* to be able to "tunnel through" and ignore the caches (e.g., the* "reload" button in a browser). If the UseCaches flag on a connection* is true, the connection is allowed to use whatever caches it can.* If false, caches are to be ignored.* The default value comes from defaultUseCaches, which defaults to* true. A default value can also be set per-protocol using* {@link #setDefaultUseCaches(String,boolean)}.** @param usecaches a {@code boolean} indicating whether* or not to allow caching* @throws IllegalStateException if already connected* @see #getUseCaches()*/public void setUseCaches(boolean usecaches) {checkConnected();useCaches = usecaches;}/*** Returns the value of this {@code URLConnection}'s* {@code useCaches} field.** @return the value of this {@code URLConnection}'s* {@code useCaches} field.* @see #setUseCaches(boolean)*/public boolean getUseCaches() {return useCaches;}/*** Sets the value of the {@code ifModifiedSince} field of* this {@code URLConnection} to the specified value.** @param ifmodifiedsince the new value.* @throws IllegalStateException if already connected* @see #getIfModifiedSince()*/public void setIfModifiedSince(long ifmodifiedsince) {checkConnected();ifModifiedSince = ifmodifiedsince;}/*** Returns the value of this object's {@code ifModifiedSince} field.** @return the value of this object's {@code ifModifiedSince} field.* @see #setIfModifiedSince(long)*/public long getIfModifiedSince() {return ifModifiedSince;}/*** Returns the default value of a {@code URLConnection}'s* {@code useCaches} flag.* <p>* This default is "sticky", being a part of the static state of all* URLConnections. This flag applies to the next, and all following* URLConnections that are created. This default value can be over-ridden* per protocol using {@link #setDefaultUseCaches(String,boolean)}** @return the default value of a {@code URLConnection}'s* {@code useCaches} flag.* @see #setDefaultUseCaches(boolean)*/public boolean getDefaultUseCaches() {return defaultUseCaches;}/*** Sets the default value of the {@code useCaches} field to the* specified value. This default value can be over-ridden* per protocol using {@link #setDefaultUseCaches(String,boolean)}** @param defaultusecaches the new value.* @see #getDefaultUseCaches()*/public void setDefaultUseCaches(boolean defaultusecaches) {defaultUseCaches = defaultusecaches;}/*** Sets the default value of the {@code useCaches} field for the named* protocol to the given value. This value overrides any default setting* set by {@link #setDefaultUseCaches(boolean)} for the given protocol.* Successive calls to this method change the setting and affect the* default value for all future connections of that protocol. The protocol* name is case insensitive.** @param protocol the protocol to set the default for* @param defaultVal whether caching is enabled by default for the given protocol* @since 9*/public static void setDefaultUseCaches(String protocol, boolean defaultVal) {protocol = protocol.toLowerCase(Locale.US);defaultCaching.put(protocol, defaultVal);}/*** Returns the default value of the {@code useCaches} flag for the given protocol. If* {@link #setDefaultUseCaches(String,boolean)} was called for the given protocol,* then that value is returned. Otherwise, if {@link #setDefaultUseCaches(boolean)}* was called, then that value is returned. If neither method was called,* the return value is {@code true}. The protocol name is case insensitive.** @param protocol the protocol whose defaultUseCaches setting is required* @return the default value of the {@code useCaches} flag for the given protocol.* @since 9*/public static boolean getDefaultUseCaches(String protocol) {Boolean protoDefault = defaultCaching.get(protocol.toLowerCase(Locale.US));if (protoDefault != null) {return protoDefault.booleanValue();} else {return defaultUseCaches;}}/*** Sets the general request property. If a property with the key already* exists, overwrite its value with the new value.** <p> NOTE: HTTP requires all request properties which can* legally have multiple instances with the same key* to use a comma-separated list syntax which enables multiple* properties to be appended into a single property.** @param key the keyword by which the request is known* (e.g., "{@code Accept}").* @param value the value associated with it.* @throws IllegalStateException if already connected* @throws NullPointerException if key is {@code null}* @see #getRequestProperty(java.lang.String)*/public void setRequestProperty(String key, String value) {checkConnected();if (key == null)throw new NullPointerException ("key is null");if (requests == null)requests = new MessageHeader();requests.set(key, value);}/*** Adds a general request property specified by a* key-value pair. This method will not overwrite* existing values associated with the same key.** @param key the keyword by which the request is known* (e.g., "{@code Accept}").* @param value the value associated with it.* @throws IllegalStateException if already connected* @throws NullPointerException if key is null* @see #getRequestProperties()* @since 1.4*/public void addRequestProperty(String key, String value) {checkConnected();if (key == null)throw new NullPointerException ("key is null");if (requests == null)requests = new MessageHeader();requests.add(key, value);}/*** Returns the value of the named general request property for this* connection.** @param key the keyword by which the request is known (e.g., "Accept").* @return the value of the named general request property for this* connection. If key is null, then null is returned.* @throws IllegalStateException if already connected* @see #setRequestProperty(java.lang.String, java.lang.String)*/public String getRequestProperty(String key) {checkConnected();if (requests == null)return null;return requests.findValue(key);}/*** Returns an unmodifiable Map of general request* properties for this connection. The Map keys* are Strings that represent the request-header* field names. Each Map value is a unmodifiable List* of Strings that represents the corresponding* field values.** @return a Map of the general request properties for this connection.* @throws IllegalStateException if already connected* @since 1.4*/public Map<String,List<String>> getRequestProperties() {checkConnected();if (requests == null)return Collections.emptyMap();return requests.getHeaders(null);}/*** Sets the default value of a general request property. When a* {@code URLConnection} is created, it is initialized with* these properties.** @param key the keyword by which the request is known* (e.g., "{@code Accept}").* @param value the value associated with the key.** @see java.net.URLConnection#setRequestProperty(java.lang.String,java.lang.String)** @deprecated The instance specific setRequestProperty method* should be used after an appropriate instance of URLConnection* is obtained. Invoking this method will have no effect.** @see #getDefaultRequestProperty(java.lang.String)*/@Deprecatedpublic static void setDefaultRequestProperty(String key, String value) {}/*** Returns the value of the default request property. Default request* properties are set for every connection.** @param key the keyword by which the request is known (e.g., "Accept").* @return the value of the default request property* for the specified key.** @see java.net.URLConnection#getRequestProperty(java.lang.String)** @deprecated The instance specific getRequestProperty method* should be used after an appropriate instance of URLConnection* is obtained.** @see #setDefaultRequestProperty(java.lang.String, java.lang.String)*/@Deprecatedpublic static String getDefaultRequestProperty(String key) {return null;}/*** The ContentHandler factory.*/private static volatile ContentHandlerFactory factory;/*** Sets the {@code ContentHandlerFactory} of an* application. It can be called at most once by an application.* <p>* The {@code ContentHandlerFactory} instance is used to* construct a content handler from a content type.* <p>* If there is a security manager, this method first calls* the security manager's {@code checkSetFactory} method* to ensure the operation is allowed.* This could result in a SecurityException.** @param fac the desired factory.* @exception Error if the factory has already been defined.* @exception SecurityException if a security manager exists and its* {@code checkSetFactory} method doesn't allow the operation.* @see java.net.ContentHandlerFactory* @see java.net.URLConnection#getContent()* @see SecurityManager#checkSetFactory*/public static synchronized void setContentHandlerFactory(ContentHandlerFactory fac) {if (factory != null) {throw new Error("factory already defined");}SecurityManager security = System.getSecurityManager();if (security != null) {security.checkSetFactory();}factory = fac;}private static final Hashtable<String, ContentHandler> handlers = new Hashtable<>();/*** Gets the Content Handler appropriate for this connection.*/private ContentHandler getContentHandler() throws UnknownServiceException {String contentType = stripOffParameters(getContentType());if (contentType == null) {throw new UnknownServiceException("no content-type");}ContentHandler handler = handlers.get(contentType);if (handler != null)return handler;if (factory != null) {handler = factory.createContentHandler(contentType);if (handler != null)return handler;}handler = lookupContentHandlerViaProvider(contentType);if (handler != null) {ContentHandler h = handlers.putIfAbsent(contentType, handler);return Objects.requireNonNullElse(h, handler);}try {handler = lookupContentHandlerClassFor(contentType);} catch (Exception e) {e.printStackTrace();handler = UnknownContentHandler.INSTANCE;}assert handler != null;ContentHandler h = handlers.putIfAbsent(contentType, handler);return Objects.requireNonNullElse(h, handler);}/** Media types are in the format: type/subtype*(; parameter).* For looking up the content handler, we should ignore those* parameters.*/private String stripOffParameters(String contentType){if (contentType == null)return null;int index = contentType.indexOf(';');if (index > 0)return contentType.substring(0, index);elsereturn contentType;}private static final String contentClassPrefix = "sun.net.www.content";private static final String contentPathProp = "java.content.handler.pkgs";/*** Looks for a content handler in a user-definable set of places.* By default it looks in {@value #contentClassPrefix}, but users can define* a vertical-bar delimited set of class prefixes to search through in* addition by defining the {@value #contentPathProp} property.* The class name must be of the form:* <pre>* {package-prefix}.{major}.{minor}* e.g.* YoyoDyne.experimental.text.plain* </pre>*/private ContentHandler lookupContentHandlerClassFor(String contentType) {String contentHandlerClassName = typeToPackageName(contentType);String contentHandlerPkgPrefixes = getContentHandlerPkgPrefixes();StringTokenizer packagePrefixIter =new StringTokenizer(contentHandlerPkgPrefixes, "|");while (packagePrefixIter.hasMoreTokens()) {String packagePrefix = packagePrefixIter.nextToken().trim();try {String clsName = packagePrefix + "." + contentHandlerClassName;Class<?> cls = null;try {cls = Class.forName(clsName);} catch (ClassNotFoundException e) {ClassLoader cl = ClassLoader.getSystemClassLoader();if (cl != null) {cls = cl.loadClass(clsName);}}if (cls != null) {@SuppressWarnings("deprecation")Object tmp = cls.newInstance();return (ContentHandler) tmp;}} catch(Exception ignored) { }}return UnknownContentHandler.INSTANCE;}private ContentHandler lookupContentHandlerViaProvider(String contentType) {return AccessController.doPrivileged(new PrivilegedAction<>() {@Overridepublic ContentHandler run() {ClassLoader cl = ClassLoader.getSystemClassLoader();ServiceLoader<ContentHandlerFactory> sl =ServiceLoader.load(ContentHandlerFactory.class, cl);Iterator<ContentHandlerFactory> iterator = sl.iterator();ContentHandler handler = null;while (iterator.hasNext()) {ContentHandlerFactory f;try {f = iterator.next();} catch (ServiceConfigurationError e) {if (e.getCause() instanceof SecurityException) {continue;}throw e;}handler = f.createContentHandler(contentType);if (handler != null) {break;}}return handler;}});}/*** Utility function to map a MIME content type into an equivalent* pair of class name components. For example: "text/html" would* be returned as "text.html"*/private String typeToPackageName(String contentType) {// make sure we canonicalize the class name: all lower casecontentType = contentType.toLowerCase();int len = contentType.length();char nm[] = new char[len];contentType.getChars(0, len, nm, 0);for (int i = 0; i < len; i++) {char c = nm[i];if (c == '/') {nm[i] = '.';} else if (!('A' <= c && c <= 'Z' ||'a' <= c && c <= 'z' ||'0' <= c && c <= '9')) {nm[i] = '_';}}return new String(nm);}/*** Returns a vertical bar separated list of package prefixes for potential* content handlers. Tries to get the java.content.handler.pkgs property* to use as a set of package prefixes to search. Whether or not* that property has been defined, the {@value #contentClassPrefix}* is always the last one on the returned package list.*/private String getContentHandlerPkgPrefixes() {String packagePrefixList =GetPropertyAction.privilegedGetProperty(contentPathProp, "");if (packagePrefixList != "") {packagePrefixList += "|";}return packagePrefixList + contentClassPrefix;}/*** Tries to determine the content type of an object, based* on the specified "file" component of a URL.* This is a convenience method that can be used by* subclasses that override the {@code getContentType} method.** @param fname a filename.* @return a guess as to what the content type of the object is,* based upon its file name.* @see java.net.URLConnection#getContentType()*/public static String guessContentTypeFromName(String fname) {return getFileNameMap().getContentTypeFor(fname);}/*** Tries to determine the type of an input stream based on the* characters at the beginning of the input stream. This method can* be used by subclasses that override the* {@code getContentType} method.* <p>* Ideally, this routine would not be needed. But many* {@code http} servers return the incorrect content type; in* addition, there are many nonstandard extensions. Direct inspection* of the bytes to determine the content type is often more accurate* than believing the content type claimed by the {@code http} server.** @param is an input stream that supports marks.* @return a guess at the content type, or {@code null} if none* can be determined.* @exception IOException if an I/O error occurs while reading the* input stream.* @see java.io.InputStream#mark(int)* @see java.io.InputStream#markSupported()* @see java.net.URLConnection#getContentType()*/public static String guessContentTypeFromStream(InputStream is)throws IOException {// If we can't read ahead safely, just give up on guessingif (!is.markSupported())return null;is.mark(16);int c1 = is.read();int c2 = is.read();int c3 = is.read();int c4 = is.read();int c5 = is.read();int c6 = is.read();int c7 = is.read();int c8 = is.read();int c9 = is.read();int c10 = is.read();int c11 = is.read();int c12 = is.read();int c13 = is.read();int c14 = is.read();int c15 = is.read();int c16 = is.read();is.reset();if (c1 == 0xCA && c2 == 0xFE && c3 == 0xBA && c4 == 0xBE) {return "application/java-vm";}if (c1 == 0xAC && c2 == 0xED) {// next two bytes are version number, currently 0x00 0x05return "application/x-java-serialized-object";}if (c1 == '<') {if (c2 == '!'|| ((c2 == 'h' && (c3 == 't' && c4 == 'm' && c5 == 'l' ||c3 == 'e' && c4 == 'a' && c5 == 'd') ||(c2 == 'b' && c3 == 'o' && c4 == 'd' && c5 == 'y'))) ||((c2 == 'H' && (c3 == 'T' && c4 == 'M' && c5 == 'L' ||c3 == 'E' && c4 == 'A' && c5 == 'D') ||(c2 == 'B' && c3 == 'O' && c4 == 'D' && c5 == 'Y')))) {return "text/html";}if (c2 == '?' && c3 == 'x' && c4 == 'm' && c5 == 'l' && c6 == ' ') {return "application/xml";}}// big and little (identical) endian UTF-8 encodings, with BOMif (c1 == 0xef && c2 == 0xbb && c3 == 0xbf) {if (c4 == '<' && c5 == '?' && c6 == 'x') {return "application/xml";}}// big and little endian UTF-16 encodings, with byte order markif (c1 == 0xfe && c2 == 0xff) {if (c3 == 0 && c4 == '<' && c5 == 0 && c6 == '?' &&c7 == 0 && c8 == 'x') {return "application/xml";}}if (c1 == 0xff && c2 == 0xfe) {if (c3 == '<' && c4 == 0 && c5 == '?' && c6 == 0 &&c7 == 'x' && c8 == 0) {return "application/xml";}}// big and little endian UTF-32 encodings, with BOMif (c1 == 0x00 && c2 == 0x00 && c3 == 0xfe && c4 == 0xff) {if (c5 == 0 && c6 == 0 && c7 == 0 && c8 == '<' &&c9 == 0 && c10 == 0 && c11 == 0 && c12 == '?' &&c13 == 0 && c14 == 0 && c15 == 0 && c16 == 'x') {return "application/xml";}}if (c1 == 0xff && c2 == 0xfe && c3 == 0x00 && c4 == 0x00) {if (c5 == '<' && c6 == 0 && c7 == 0 && c8 == 0 &&c9 == '?' && c10 == 0 && c11 == 0 && c12 == 0 &&c13 == 'x' && c14 == 0 && c15 == 0 && c16 == 0) {return "application/xml";}}if (c1 == 'G' && c2 == 'I' && c3 == 'F' && c4 == '8') {return "image/gif";}if (c1 == '#' && c2 == 'd' && c3 == 'e' && c4 == 'f') {return "image/x-bitmap";}if (c1 == '!' && c2 == ' ' && c3 == 'X' && c4 == 'P' &&c5 == 'M' && c6 == '2') {return "image/x-pixmap";}if (c1 == 137 && c2 == 80 && c3 == 78 &&c4 == 71 && c5 == 13 && c6 == 10 &&c7 == 26 && c8 == 10) {return "image/png";}if (c1 == 0xFF && c2 == 0xD8 && c3 == 0xFF) {if (c4 == 0xE0 || c4 == 0xEE) {return "image/jpeg";}/*** File format used by digital cameras to store images.* Exif Format can be read by any application supporting* JPEG. Exif Spec can be found at:* http://www.pima.net/standards/it10/PIMA15740/Exif_2-1.PDF*/if ((c4 == 0xE1) &&(c7 == 'E' && c8 == 'x' && c9 == 'i' && c10 =='f' &&c11 == 0)) {return "image/jpeg";}}if ((c1 == 0x49 && c2 == 0x49 && c3 == 0x2a && c4 == 0x00)|| (c1 == 0x4d && c2 == 0x4d && c3 == 0x00 && c4 == 0x2a)) {return "image/tiff";}if (c1 == 0xD0 && c2 == 0xCF && c3 == 0x11 && c4 == 0xE0 &&c5 == 0xA1 && c6 == 0xB1 && c7 == 0x1A && c8 == 0xE1) {/* Above is signature of Microsoft Structured Storage.* Below this, could have tests for various SS entities.* For now, just test for FlashPix.*/if (checkfpx(is)) {return "image/vnd.fpx";}}if (c1 == 0x2E && c2 == 0x73 && c3 == 0x6E && c4 == 0x64) {return "audio/basic"; // .au format, big endian}if (c1 == 0x64 && c2 == 0x6E && c3 == 0x73 && c4 == 0x2E) {return "audio/basic"; // .au format, little endian}if (c1 == 'R' && c2 == 'I' && c3 == 'F' && c4 == 'F') {/* I don't know if this is official but evidence* suggests that .wav files start with "RIFF" - brown*/return "audio/x-wav";}return null;}/*** Check for FlashPix image data in InputStream is. Return true if* the stream has FlashPix data, false otherwise. Before calling this* method, the stream should have already been checked to be sure it* contains Microsoft Structured Storage data.*/private static boolean checkfpx(InputStream is) throws IOException {/* Test for FlashPix image data in Microsoft Structured Storage format.* In general, should do this with calls to an SS implementation.* Lacking that, need to dig via offsets to get to the FlashPix* ClassID. Details:** Offset to Fpx ClsID from beginning of stream should be:** FpxClsidOffset = rootEntryOffset + clsidOffset** where: clsidOffset = 0x50.* rootEntryOffset = headerSize + sectorSize*sectDirStart* + 128*rootEntryDirectory** where: headerSize = 0x200 (always)* sectorSize = 2 raised to power of uSectorShift,* which is found in the header at* offset 0x1E.* sectDirStart = found in the header at offset 0x30.* rootEntryDirectory = in general, should search for* directory labelled as root.* We will assume value of 0 (i.e.,* rootEntry is in first directory)*/// Mark the stream so we can reset it. 0x100 is enough for the first// few reads, but the mark will have to be reset and set again once// the offset to the root directory entry is computed. That offset// can be very large and isn't know until the stream has been read fromis.mark(0x100);// Get the byte ordering located at 0x1E. 0xFE is Intel,// 0xFF is otherlong toSkip = (long)0x1C;long posn;if ((posn = skipForward(is, toSkip)) < toSkip) {is.reset();return false;}int c[] = new int[16];if (readBytes(c, 2, is) < 0) {is.reset();return false;}int byteOrder = c[0];posn+=2;int uSectorShift;if (readBytes(c, 2, is) < 0) {is.reset();return false;}if(byteOrder == 0xFE) {uSectorShift = c[0];uSectorShift += c[1] << 8;}else {uSectorShift = c[0] << 8;uSectorShift += c[1];}posn += 2;toSkip = (long)0x30 - posn;long skipped = 0;if ((skipped = skipForward(is, toSkip)) < toSkip) {is.reset();return false;}posn += skipped;if (readBytes(c, 4, is) < 0) {is.reset();return false;}int sectDirStart;if(byteOrder == 0xFE) {sectDirStart = c[0];sectDirStart += c[1] << 8;sectDirStart += c[2] << 16;sectDirStart += c[3] << 24;} else {sectDirStart = c[0] << 24;sectDirStart += c[1] << 16;sectDirStart += c[2] << 8;sectDirStart += c[3];}posn += 4;is.reset(); // Reset back to the beginningtoSkip = 0x200L + (long)(1<<uSectorShift)*sectDirStart + 0x50L;// Sanity check!if (toSkip < 0) {return false;}/** How far can we skip? Is there any performance problem here?* This skip can be fairly long, at least 0x4c650 in at least* one case. Have to assume that the skip will fit in an int.* Leave room to read whole root dir*/is.mark((int)toSkip+0x30);if ((skipForward(is, toSkip)) < toSkip) {is.reset();return false;}/* should be at beginning of ClassID, which is as follows* (in Intel byte order):* 00 67 61 56 54 C1 CE 11 85 53 00 AA 00 A1 F9 5B** This is stored from Windows as long,short,short,char[8]* so for byte order changes, the order only changes for* the first 8 bytes in the ClassID.** Test against this, ignoring second byte (Intel) since* this could change depending on part of Fpx file we have.*/if (readBytes(c, 16, is) < 0) {is.reset();return false;}// intel byte orderif (byteOrder == 0xFE &&c[0] == 0x00 && c[2] == 0x61 && c[3] == 0x56 &&c[4] == 0x54 && c[5] == 0xC1 && c[6] == 0xCE &&c[7] == 0x11 && c[8] == 0x85 && c[9] == 0x53 &&c[10]== 0x00 && c[11]== 0xAA && c[12]== 0x00 &&c[13]== 0xA1 && c[14]== 0xF9 && c[15]== 0x5B) {is.reset();return true;}// non-intel byte orderelse if (c[3] == 0x00 && c[1] == 0x61 && c[0] == 0x56 &&c[5] == 0x54 && c[4] == 0xC1 && c[7] == 0xCE &&c[6] == 0x11 && c[8] == 0x85 && c[9] == 0x53 &&c[10]== 0x00 && c[11]== 0xAA && c[12]== 0x00 &&c[13]== 0xA1 && c[14]== 0xF9 && c[15]== 0x5B) {is.reset();return true;}is.reset();return false;}/*** Tries to read the specified number of bytes from the stream* Returns -1, If EOF is reached before len bytes are read, returns 0* otherwise*/private static int readBytes(int c[], int len, InputStream is)throws IOException {byte buf[] = new byte[len];if (is.read(buf, 0, len) < len) {return -1;}// fill the passed in int arrayfor (int i = 0; i < len; i++) {c[i] = buf[i] & 0xff;}return 0;}/*** Skips through the specified number of bytes from the stream* until either EOF is reached, or the specified* number of bytes have been skipped*/private static long skipForward(InputStream is, long toSkip)throws IOException {long eachSkip = 0;long skipped = 0;while (skipped != toSkip) {eachSkip = is.skip(toSkip - skipped);// check if EOF is reachedif (eachSkip <= 0) {if (is.read() == -1) {return skipped ;} else {skipped++;}}skipped += eachSkip;}return skipped;}private void checkConnected() {if (connected)throw new IllegalStateException("Already connected");}}class UnknownContentHandler extends ContentHandler {static final ContentHandler INSTANCE = new UnknownContentHandler();public Object getContent(URLConnection uc) throws IOException {return uc.getInputStream();}}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。