--- a/jdk/src/java.base/share/classes/java/net/URL.java Sat Jul 11 14:54:07 2015 +0300
+++ b/jdk/src/java.base/share/classes/java/net/URL.java Wed Jul 29 13:42:56 2015 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -31,6 +31,10 @@
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Hashtable;
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
+import java.io.ObjectStreamField;
+import java.io.ObjectInputStream.GetField;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.ServiceConfigurationError;
@@ -142,6 +146,7 @@
*/
public final class URL implements java.io.Serializable {
+ static final String BUILTIN_HANDLERS_PREFIX = "sun.net.www.protocol";
static final long serialVersionUID = -7627629688361524110L;
/**
@@ -226,6 +231,8 @@
*/
private int hashCode = -1;
+ private transient UrlDeserializedState tempState;
+
/**
* Creates a {@code URL} object from the specified
* {@code protocol}, {@code host}, {@code port}
@@ -1354,6 +1361,31 @@
}
/**
+ * @serialField protocol String
+ *
+ * @serialField host String
+ *
+ * @serialField port int
+ *
+ * @serialField authority String
+ *
+ * @serialField file String
+ *
+ * @serialField ref String
+ *
+ * @serialField hashCode int
+ *
+ */
+ private static final ObjectStreamField[] serialPersistentFields = {
+ new ObjectStreamField("protocol", String.class),
+ new ObjectStreamField("host", String.class),
+ new ObjectStreamField("port", int.class),
+ new ObjectStreamField("authority", String.class),
+ new ObjectStreamField("file", String.class),
+ new ObjectStreamField("ref", String.class),
+ new ObjectStreamField("hashCode", int.class), };
+
+ /**
* WriteObject is called to save the state of the URL to an
* ObjectOutputStream. The handler is not saved since it is
* specific to this system.
@@ -1375,16 +1407,67 @@
* stream handler.
*/
private synchronized void readObject(java.io.ObjectInputStream s)
- throws IOException, ClassNotFoundException
- {
- s.defaultReadObject(); // read the fields
- if ((handler = getURLStreamHandler(protocol)) == null) {
+ throws IOException, ClassNotFoundException {
+ GetField gf = s.readFields();
+ String protocol = (String)gf.get("protocol", null);
+ if (getURLStreamHandler(protocol) == null) {
throw new IOException("unknown protocol: " + protocol);
}
+ String host = (String)gf.get("host", null);
+ int port = gf.get("port", -1);
+ String authority = (String)gf.get("authority", null);
+ String file = (String)gf.get("file", null);
+ String ref = (String)gf.get("ref", null);
+ int hashCode = gf.get("hashCode", -1);
+ if (authority == null
+ && ((host != null && host.length() > 0) || port != -1)) {
+ if (host == null)
+ host = "";
+ authority = (port == -1) ? host : host + ":" + port;
+ }
+ tempState = new UrlDeserializedState(protocol, host, port, authority,
+ file, ref, hashCode);
+ }
+
+ /**
+ * Replaces the de-serialized object with an URL object.
+ *
+ * @return a newly created object from deserialized data
+ *
+ * @throws ObjectStreamException if a new object replacing this
+ * object could not be created
+ */
+
+ private Object readResolve() throws ObjectStreamException {
+
+ URLStreamHandler handler = null;
+ // already been checked in readObject
+ handler = getURLStreamHandler(tempState.getProtocol());
+
+ URL replacementURL = null;
+ if (isBuiltinStreamHandler(handler.getClass().getName())) {
+ replacementURL = fabricateNewURL();
+ } else {
+ replacementURL = setDeserializedFields(handler);
+ }
+ return replacementURL;
+ }
+
+ private URL setDeserializedFields(URLStreamHandler handler) {
+ URL replacementURL;
+ String userInfo = null;
+ String protocol = tempState.getProtocol();
+ String host = tempState.getHost();
+ int port = tempState.getPort();
+ String authority = tempState.getAuthority();
+ String file = tempState.getFile();
+ String ref = tempState.getRef();
+ int hashCode = tempState.getHashCode();
+
// Construct authority part
- if (authority == null &&
- ((host != null && host.length() > 0) || port != -1)) {
+ if (authority == null
+ && ((host != null && host.length() > 0) || port != -1)) {
if (host == null)
host = "";
authority = (port == -1) ? host : host + ":" + port;
@@ -1403,8 +1486,8 @@
}
// Construct path and query part
- path = null;
- query = null;
+ String path = null;
+ String query = null;
if (file != null) {
// Fix: only do this if hierarchical?
int q = file.lastIndexOf('?');
@@ -1414,6 +1497,67 @@
} else
path = file;
}
+
+ if (port == -1) {
+ port = 0;
+ }
+ // Set the object fields.
+ this.protocol = protocol;
+ this.host = host;
+ this.port = port;
+ this.file = file;
+ this.authority = authority;
+ this.ref = ref;
+ this.hashCode = hashCode;
+ this.handler = handler;
+ this.query = query;
+ this.path = path;
+ this.userInfo = userInfo;
+ replacementURL = this;
+ return replacementURL;
+ }
+
+ private URL fabricateNewURL()
+ throws InvalidObjectException {
+ // create URL string from deserialized object
+ URL replacementURL = null;
+ String urlString = tempState.reconstituteUrlString();
+
+ try {
+ replacementURL = new URL(urlString);
+ } catch (MalformedURLException mEx) {
+ resetState();
+ InvalidObjectException invoEx = new InvalidObjectException(
+ "Malformed URL: " + urlString);
+ invoEx.initCause(mEx);
+ throw invoEx;
+ }
+ replacementURL.setSerializedHashCode(tempState.getHashCode());
+ resetState();
+ return replacementURL;
+ }
+
+ private boolean isBuiltinStreamHandler(String handlerClassName) {
+ return (handlerClassName.startsWith(BUILTIN_HANDLERS_PREFIX));
+ }
+
+ private void resetState() {
+ this.protocol = null;
+ this.host = null;
+ this.port = -1;
+ this.file = null;
+ this.authority = null;
+ this.ref = null;
+ this.hashCode = -1;
+ this.handler = null;
+ this.query = null;
+ this.path = null;
+ this.userInfo = null;
+ this.tempState = null;
+ }
+
+ private void setSerializedHashCode(int hc) {
+ this.hashCode = hc;
}
}
@@ -1445,3 +1589,82 @@
return ref;
}
}
+
+final class UrlDeserializedState {
+ private final String protocol;
+ private final String host;
+ private final int port;
+ private final String authority;
+ private final String file;
+ private final String ref;
+ private final int hashCode;
+
+ public UrlDeserializedState(String protocol,
+ String host, int port,
+ String authority, String file,
+ String ref, int hashCode) {
+ this.protocol = protocol;
+ this.host = host;
+ this.port = port;
+ this.authority = authority;
+ this.file = file;
+ this.ref = ref;
+ this.hashCode = hashCode;
+ }
+
+ String getProtocol() {
+ return protocol;
+ }
+
+ String getHost() {
+ return host;
+ }
+
+ String getAuthority () {
+ return authority;
+ }
+
+ int getPort() {
+ return port;
+ }
+
+ String getFile () {
+ return file;
+ }
+
+ String getRef () {
+ return ref;
+ }
+
+ int getHashCode () {
+ return hashCode;
+ }
+
+ String reconstituteUrlString() {
+
+ // pre-compute length of StringBuffer
+ int len = protocol.length() + 1;
+ if (authority != null && authority.length() > 0)
+ len += 2 + authority.length();
+ if (file != null) {
+ len += file.length();
+ }
+ if (ref != null)
+ len += 1 + ref.length();
+ StringBuilder result = new StringBuilder(len);
+ result.append(protocol);
+ result.append(":");
+ if (authority != null && authority.length() > 0) {
+ result.append("//");
+ result.append(authority);
+ }
+ if (file != null) {
+ result.append(file);
+ }
+ if (ref != null) {
+ result.append("#");
+ result.append(ref);
+ }
+ return result.toString();
+ }
+}