/* * Copyright (C) 2015 SoftIndex LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.datakernel.http; import io.datakernel.exception.ParseException; import java.util.Map; import static java.lang.Integer.parseInt; /** * Util for parsing a HTTP URI from a String */ public final class HttpUri { private static final String SCHEMA_DELIM = "://"; private static final String HTTP = "http"; private static final String HTTPS = "https"; private static final char IPV6_OPENING_BRACKET = '['; private static final String IPV6_CLOSING_SECTION_WITH_PORT = "]:"; /** * Parses a string, treats all URIs starting with / as paths * * @param uri URI for parsing * @return new URI */ public static HttpUri ofUrl(String uri) { return new HttpUri(uri, true); } /** * Parses a string without prior scheme * * @param uri URI for parsing * @return new URI */ static HttpUri parseUrl(String uri) throws ParseException { try { return new HttpUri(uri, false); } catch (RuntimeException e) { throw new ParseException(e); } } private final String schema; private final String uri; private final String hostPort; private final String host; private final int port; private final String pathAndQuery; private final String path; private final String query; private Map<String, String> params; private HttpUri(String uri, boolean strict) { this.uri = uri; int index = uri.indexOf(SCHEMA_DELIM); if (index < 0 || index > 5) { if (strict) throw new IllegalArgumentException("Partial URI is not allowed: " + uri); hostPort = null; host = null; port = -1; pathAndQuery = uri.isEmpty() ? "/" : uri; schema = ""; } else { schema = uri.substring(0, index); if (!(schema.equals(HTTP) || schema.equals(HTTPS))) throw new IllegalArgumentException("Unsupported schema: " + schema); index += SCHEMA_DELIM.length(); int slash = uri.indexOf('/', index); hostPort = (slash == -1) ? uri.substring(index) : uri.substring(index, slash); if (uri.charAt(index) == IPV6_OPENING_BRACKET) { // parse IPv6 int closingSection = hostPort.indexOf(IPV6_CLOSING_SECTION_WITH_PORT); if (closingSection != -1) { host = hostPort.substring(0, closingSection + 1); port = parseInt(hostPort.substring(closingSection + 2)); } else { host = hostPort; port = schema.equals(HTTPS) ? 443 : 80; } } else { // parse IPv4 int colon = hostPort.indexOf(':'); if (colon != -1) { host = hostPort.substring(0, colon); port = parseInt(hostPort.substring(colon + 1)); } else { host = hostPort; port = schema.equals(HTTPS) ? 443 : 80; } } pathAndQuery = (slash == -1) ? "/" : uri.substring(slash); } index = pathAndQuery.indexOf('?'); if (index < 0) { path = pathAndQuery; query = ""; } else { path = pathAndQuery.substring(0, index); query = pathAndQuery.substring(index + 1); } } public boolean isPartial() { return host == null; } public String getSchema() { return schema; } public String getUri() { return uri; } public String getHostAndPort() { return hostPort; } public String getHost() { return host; } public int getPort() { return port; } public String getPathAndQuery() { return pathAndQuery; } public String getPath() { return path; } public String getQuery() { return query; } public String getParameter(String name) { parseParams(); return params.get(name); } public Map<String, String> getParameters() { parseParams(); return params; } private void parseParams() { if (params != null) return; params = HttpUtils.extractParameters(query); } @Override public String toString() { return uri; } }