/** * Sets the properties of this URL using the provided arguments. Only a {@code URLStreamHandler} * can use this method to set fields of the existing URL instance. A URL is generally constant. * * @param protocol the protocol to be set. * @param host the host name to be set. * @param port the port number to be set. * @param authority the authority to be set. * @param userInfo the user-info to be set. * @param path the path to be set. * @param query the query to be set. * @param ref the reference to be set. */ protected void set( String protocol, String host, int port, String authority, String userInfo, String path, String query, String ref) { String filePart = path; if (query != null && !query.isEmpty()) { if (filePart != null) { filePart = filePart + "?" + query; } else { filePart = "?" + query; } } set(protocol, host, port, filePart, ref); this.authority = authority; this.userInfo = userInfo; this.path = path; this.query = query; }
/** * Creates a new URL to the specified resource {@code spec}. This URL is relative to the given * {@code context}. The {@code handler} will be used to parse the URL string representation. If * this argument is {@code null} the default {@code URLStreamHandler} will be used. If the * protocol of the parsed URL does not match with the protocol of the context URL, then the newly * created URL is absolute and bases only on the given URL represented by {@code spec}. Otherwise * the protocol is defined by the context URL. * * @param context the URL which is used as the context. * @param spec the URL string representation which has to be parsed. * @param handler the specific stream handler to be used by this URL. * @throws IOException if the given string {@code spec} could not be parsed as a URL or an invalid * protocol has been found. */ public URL(URL context, String spec) throws MalformedURLException { if (spec == null) { throw new MalformedURLException(); } spec = spec.trim(); this.spec = spec; // The spec includes a protocol if it includes a colon character // before the first occurrence of a slash character. Note that, // "protocol" is the field which holds this URLs protocol. int index; try { index = spec.indexOf(':'); } catch (NullPointerException e) { throw new MalformedURLException(e.toString()); } int startIPv6Addr = spec.indexOf('['); if (index >= 0) { if ((startIPv6Addr == -1) || (index < startIPv6Addr)) { protocol = spec.substring(0, index); // According to RFC 2396 scheme part should match // the following expression: // alpha *( alpha | digit | "+" | "-" | "." ) char c = protocol.charAt(0); boolean valid = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); for (int i = 1; valid && (i < protocol.length()); i++) { c = protocol.charAt(i); valid = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || (c == '+') || (c == '-') || (c == '.'); } if (!valid) { protocol = null; index = -1; } else { // Ignore case in protocol names. // Scheme is defined by ASCII characters. protocol = protocol.toLowerCase(); } } } if (protocol != null) { // If the context was specified, and it had the same protocol // as the spec, then fill in the receiver's slots from the values // in the context but still allow them to be over-ridden later // by the values in the spec. if (context != null && protocol.equals(context.getProtocol())) { String cPath = context.getPath(); if (cPath != null && cPath.startsWith("/")) { set( protocol, context.getHost(), context.getPort(), context.getAuthority(), context.getUserInfo(), cPath, context.getQuery(), null); } } } else { // If the spec did not include a protocol, then the context // *must* be specified. Fill in the receiver's slots from the // values in the context, but still allow them to be over-ridden // by the values in the ("relative") spec. if (context == null) { throw new MalformedURLException("Protocol not found: " + spec); } set( context.getProtocol(), context.getHost(), context.getPort(), context.getAuthority(), context.getUserInfo(), context.getPath(), context.getQuery(), null); } if (port < -1) { throw new MalformedURLException("Port out of range: " + port); } }