/******************************************************************************* * Copyright (c) 2012-2016 Codenvy, S.A. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.everrest.core.impl.uri; import org.everrest.core.util.StringUtils; import static org.everrest.core.impl.uri.UriComponent.PORT; import static org.everrest.core.impl.uri.UriComponent.isUriComponentContainsValidCharacters; import static org.everrest.core.util.StringUtils.charAtIs; import static org.everrest.core.util.StringUtils.charAtIsNot; class UriParser { private final String uri; private String scheme; private String authority; private String userInfo; private String host; private String port; private String path; private String query; private String fragment; private String schemeSpecificPart; UriParser(String uri) { this.uri = uri; } String getUri() { return uri; } String getScheme() { return scheme; } String getAuthority() { return authority; } String getUserInfo() { return userInfo; } String getHost() { return host; } String getPort() { return port; } String getPath() { return path; } String getQuery() { return query; } String getFragment() { return fragment; } String getSchemeSpecificPart() { return schemeSpecificPart; } boolean isOpaque() { return path == null; } void parse() { int sspStart = 0; int p = parseScheme(); if (scheme != null) { ++p; sspStart = p; if (charAtIs(uri, p, '/')) { p = parseHierarchical(p); } else { p = StringUtils.scan(uri, p, '#'); } } else { p = parseHierarchical(p); } schemeSpecificPart = uri.substring(sspStart, p); parseFragment(p); } private int parseHierarchical(int begin) { int p = begin; if (charAtIs(uri, p, '/') && charAtIs(uri, p + 1, '/')) { p = parseAuthority(p + 2); } p = parsePath(p); p = parseQuery(p); return p; } private int parseScheme() { final int len = uri.length(); int p = find(0, ":/?#", len); if (charAtIsNot(uri, p, ':')) { return 0; } if (p == 0 && charAtIs(uri, p, ':')) { throw new IllegalArgumentException( String.format("Invalid template %s. Illegal character at %d. Scheme name expected", uri, p)); } if (p < len) { scheme = uri.substring(0, p); } return p; } private int parseAuthority(int begin) { final int end = StringUtils.scan(uri, begin, '/'); authority = uri.substring(begin, end); int p = parseUserInfo(begin, end); p = parseHost(p, end); p = parsePort(p, end); if (isPortInvalid()) { host = null; port = null; userInfo = null; } return p; } private boolean isPortInvalid() { return !(port == null || isTemplate(port) || isUriComponentContainsValidCharacters(PORT, port)); } private boolean isTemplate(String str) { return charAtIs(str, 0, '{') && charAtIs(str, str.length() - 1, '}'); } private int parseUserInfo(int begin, int end) { int p = find(begin, "@/?#", end); if (charAtIs(uri, p, '@')) { userInfo = uri.substring(begin, p); return p + 1; } return begin; } private int parseHost(int begin, int end) { int p = StringUtils.scan(uri, begin, ':', end); if (p > begin) { host = uri.substring(begin, p); return p + 1; } return begin; } private int parsePort(int begin, int end) { if (begin < end) { port = uri.substring(begin, end); } return end; } private int parsePath(int begin) { int p = find(begin, "?#", uri.length()); path = uri.substring(begin, p); return p; } private int parseQuery(int begin) { if (charAtIs(uri, begin, '?')) { int p = StringUtils.scan(uri, begin, '#'); if (p > begin) { query = uri.substring(begin + 1, p); return p; } } return begin; } private void parseFragment(int begin) { if (charAtIs(uri, begin, '#')) { if (begin < uri.length()) { fragment = uri.substring(begin + 1); } } } private int find(int begin, String findOneOfChars, int end) { for (int i = begin; i < end; i++) { if (StringUtils.contains(findOneOfChars, uri.charAt(i))) { return i; } } return end; } }