/** * Returns the username, or an empty string if none is set. * * <p><table summary=""> * <tr><th>URL</th><th>{@code encodedUsername()}</th></tr> * <tr><td>{@code http://host/}</td><td>{@code ""}</td></tr> * <tr><td>{@code http://username@host/}</td><td>{@code "username"}</td></tr> * <tr><td>{@code http://username:password@host/}</td><td>{@code "username"}</td></tr> * <tr><td>{@code http://a%20b:c%20d@host/}</td><td>{@code "a%20b"}</td></tr> * </table> */ public String encodedUsername() { if (username.isEmpty()) return ""; int usernameStart = scheme.length() + 3; // "://".length() == 3. int usernameEnd = delimiterOffset(url, usernameStart, url.length(), ":@"); return url.substring(usernameStart, usernameEnd); }
/** * Returns the entire path of this URL encoded for use in HTTP resource resolution. The returned * path will start with {@code "/"}. * * <p><table summary=""> * <tr><th>URL</th><th>{@code encodedPath()}</th></tr> * <tr><td>{@code http://host/}</td><td>{@code "/"}</td></tr> * <tr><td>{@code http://host/a/b/c}</td><td>{@code "/a/b/c"}</td></tr> * <tr><td>{@code http://host/a/b%20c/d}</td><td>{@code "/a/b%20c/d"}</td></tr> * </table> */ public String encodedPath() { int pathStart = url.indexOf('/', scheme.length() + 3); // "://".length() == 3. int pathEnd = delimiterOffset(url, pathStart, url.length(), "?#"); return url.substring(pathStart, pathEnd); }
private Builder addPathSegments(String pathSegments, boolean alreadyEncoded) { int offset = 0; do { int segmentEnd = delimiterOffset(pathSegments, offset, pathSegments.length(), "/\\"); boolean addTrailingSlash = segmentEnd < pathSegments.length(); push(pathSegments, offset, segmentEnd, addTrailingSlash, alreadyEncoded); offset = segmentEnd + 1; } while (offset <= pathSegments.length()); return this; }
/** * Returns a list of encoded path segments like {@code ["a", "b", "c"]} for the URL {@code * http://host/a/b/c}. This list is never empty though it may contain a single empty string. * * <p><table summary=""> * <tr><th>URL</th><th>{@code encodedPathSegments()}</th></tr> * <tr><td>{@code http://host/}</td><td>{@code [""]}</td></tr> * <tr><td>{@code http://host/a/b/c}</td><td>{@code ["a", "b", "c"]}</td></tr> * <tr><td>{@code http://host/a/b%20c/d}</td><td>{@code ["a", "b%20c", "d"]}</td></tr> * </table> */ public List<String> encodedPathSegments() { int pathStart = url.indexOf('/', scheme.length() + 3); int pathEnd = delimiterOffset(url, pathStart, url.length(), "?#"); List<String> result = new ArrayList<>(); for (int i = pathStart; i < pathEnd; ) { i++; // Skip the '/'. int segmentEnd = delimiterOffset(url, i, pathEnd, '/'); result.add(url.substring(i, segmentEnd)); i = segmentEnd; } return result; }
/** * Returns the query of this URL, encoded for use in HTTP resource resolution. The returned string * may be null (for URLs with no query), empty (for URLs with an empty query) or non-empty (all * other URLs). * * <p><table summary=""> * <tr><th>URL</th><th>{@code encodedQuery()}</th></tr> * <tr><td>{@code http://host/}</td><td>null</td></tr> * <tr><td>{@code http://host/?}</td><td>{@code ""}</td></tr> * <tr><td>{@code http://host/?a=apple&k=key+lime}</td><td>{@code * "a=apple&k=key+lime"}</td></tr> * <tr><td>{@code http://host/?a=apple&a=apricot}</td><td>{@code "a=apple&a=apricot"}</td></tr> * <tr><td>{@code http://host/?a=apple&b}</td><td>{@code "a=apple&b"}</td></tr> * </table> */ public @Nullable String encodedQuery() { if (queryNamesAndValues == null) return null; // No query. int queryStart = url.indexOf('?') + 1; int queryEnd = delimiterOffset(url, queryStart, url.length(), '#'); return url.substring(queryStart, queryEnd); }
private void resolvePath(String input, int pos, int limit) { // Read a delimiter. if (pos == limit) { // Empty path: keep the base path as-is. return; } char c = input.charAt(pos); if (c == '/' || c == '\\') { // Absolute path: reset to the default "/". encodedPathSegments.clear(); encodedPathSegments.add(""); pos++; } else { // Relative path: clear everything after the last '/'. encodedPathSegments.set(encodedPathSegments.size() - 1, ""); } // Read path segments. for (int i = pos; i < limit; ) { int pathSegmentDelimiterOffset = delimiterOffset(input, i, limit, "/\\"); boolean segmentHasTrailingSlash = pathSegmentDelimiterOffset < limit; push(input, i, pathSegmentDelimiterOffset, segmentHasTrailingSlash, true); i = pathSegmentDelimiterOffset; if (segmentHasTrailingSlash) i++; } }
/** * Returns the entire path of this URL encoded for use in HTTP resource resolution. The returned * path will start with {@code "/"}. * * <p><table summary=""> * <tr><th>URL</th><th>{@code encodedPath()}</th></tr> * <tr><td>{@code http://host/}</td><td>{@code "/"}</td></tr> * <tr><td>{@code http://host/a/b/c}</td><td>{@code "/a/b/c"}</td></tr> * <tr><td>{@code http://host/a/b%20c/d}</td><td>{@code "/a/b%20c/d"}</td></tr> * </table> */ public String encodedPath() { int pathStart = url.indexOf('/', scheme.length() + 3); // "://".length() == 3. int pathEnd = delimiterOffset(url, pathStart, url.length(), "?#"); return url.substring(pathStart, pathEnd); }
/** * Returns the username, or an empty string if none is set. * * <p><table summary=""> * <tr><th>URL</th><th>{@code encodedUsername()}</th></tr> * <tr><td>{@code http://host/}</td><td>{@code ""}</td></tr> * <tr><td>{@code http://username@host/}</td><td>{@code "username"}</td></tr> * <tr><td>{@code http://username:password@host/}</td><td>{@code "username"}</td></tr> * <tr><td>{@code http://a%20b:c%20d@host/}</td><td>{@code "a%20b"}</td></tr> * </table> */ public String encodedUsername() { if (username.isEmpty()) return ""; int usernameStart = scheme.length() + 3; // "://".length() == 3. int usernameEnd = delimiterOffset(url, usernameStart, url.length(), ":@"); return url.substring(usernameStart, usernameEnd); }
private Builder addPathSegments(String pathSegments, boolean alreadyEncoded) { int offset = 0; do { int segmentEnd = delimiterOffset(pathSegments, offset, pathSegments.length(), "/\\"); boolean addTrailingSlash = segmentEnd < pathSegments.length(); push(pathSegments, offset, segmentEnd, addTrailingSlash, alreadyEncoded); offset = segmentEnd + 1; } while (offset <= pathSegments.length()); return this; }
/** * Returns the query of this URL, encoded for use in HTTP resource resolution. The returned string * may be null (for URLs with no query), empty (for URLs with an empty query) or non-empty (all * other URLs). * * <p><table summary=""> * <tr><th>URL</th><th>{@code encodedQuery()}</th></tr> * <tr><td>{@code http://host/}</td><td>null</td></tr> * <tr><td>{@code http://host/?}</td><td>{@code ""}</td></tr> * <tr><td>{@code http://host/?a=apple&k=key+lime}</td><td>{@code * "a=apple&k=key+lime"}</td></tr> * <tr><td>{@code http://host/?a=apple&a=apricot}</td><td>{@code "a=apple&a=apricot"}</td></tr> * <tr><td>{@code http://host/?a=apple&b}</td><td>{@code "a=apple&b"}</td></tr> * </table> */ public @Nullable String encodedQuery() { if (queryNamesAndValues == null) return null; // No query. int queryStart = url.indexOf('?') + 1; int queryEnd = delimiterOffset(url, queryStart, url.length(), '#'); return url.substring(queryStart, queryEnd); }
/** * Returns a list of encoded path segments like {@code ["a", "b", "c"]} for the URL {@code * http://host/a/b/c}. This list is never empty though it may contain a single empty string. * * <p><table summary=""> * <tr><th>URL</th><th>{@code encodedPathSegments()}</th></tr> * <tr><td>{@code http://host/}</td><td>{@code [""]}</td></tr> * <tr><td>{@code http://host/a/b/c}</td><td>{@code ["a", "b", "c"]}</td></tr> * <tr><td>{@code http://host/a/b%20c/d}</td><td>{@code ["a", "b%20c", "d"]}</td></tr> * </table> */ public List<String> encodedPathSegments() { int pathStart = url.indexOf('/', scheme.length() + 3); int pathEnd = delimiterOffset(url, pathStart, url.length(), "?#"); List<String> result = new ArrayList<>(); for (int i = pathStart; i < pathEnd; ) { i++; // Skip the '/'. int segmentEnd = delimiterOffset(url, i, pathEnd, '/'); result.add(url.substring(i, segmentEnd)); i = segmentEnd; } return result; }
List<Cookie> result = new ArrayList<>(); for (int pos = 0, limit = header.length(), pairEnd; pos < limit; pos = pairEnd + 1) { pairEnd = delimiterOffset(header, pos, limit, ";,"); int equalsSign = delimiterOffset(header, pos, pairEnd, '='); String name = trimSubstring(header, pos, equalsSign); if (name.startsWith("$")) continue;
private void resolvePath(String input, int pos, int limit) { // Read a delimiter. if (pos == limit) { // Empty path: keep the base path as-is. return; } char c = input.charAt(pos); if (c == '/' || c == '\\') { // Absolute path: reset to the default "/". encodedPathSegments.clear(); encodedPathSegments.add(""); pos++; } else { // Relative path: clear everything after the last '/'. encodedPathSegments.set(encodedPathSegments.size() - 1, ""); } // Read path segments. for (int i = pos; i < limit; ) { int pathSegmentDelimiterOffset = delimiterOffset(input, i, limit, "/\\"); boolean segmentHasTrailingSlash = pathSegmentDelimiterOffset < limit; push(input, i, pathSegmentDelimiterOffset, segmentHasTrailingSlash, true); i = pathSegmentDelimiterOffset; if (segmentHasTrailingSlash) i++; } }
static @Nullable Cookie parse(long currentTimeMillis, HttpUrl url, String setCookie) { int pos = 0; int limit = setCookie.length(); int cookiePairEnd = delimiterOffset(setCookie, pos, limit, ';'); int pairEqualsSign = delimiterOffset(setCookie, pos, cookiePairEnd, '='); if (pairEqualsSign == cookiePairEnd) return null; int attributePairEnd = delimiterOffset(setCookie, pos, limit, ';'); int attributeEqualsSign = delimiterOffset(setCookie, pos, attributePairEnd, '='); String attributeName = trimSubstring(setCookie, pos, attributeEqualsSign); String attributeValue = attributeEqualsSign < attributePairEnd
authority: while (true) { int componentDelimiterOffset = delimiterOffset(input, pos, limit, "@/\\?#"); int c = componentDelimiterOffset != limit ? input.charAt(componentDelimiterOffset) int passwordColonOffset = delimiterOffset( input, pos, componentDelimiterOffset, ':'); String canonicalUsername = canonicalize(input, pos, passwordColonOffset, int pathDelimiterOffset = delimiterOffset(input, pos, limit, "?#"); resolvePath(input, pos, pathDelimiterOffset); pos = pathDelimiterOffset; int queryDelimiterOffset = delimiterOffset(input, pos, limit, '#'); this.encodedQueryNamesAndValues = queryStringToNamesAndValues(canonicalize( input, pos + 1, queryDelimiterOffset, QUERY_ENCODE_SET, true, false, true, true, null));
static @Nullable Cookie parse(long currentTimeMillis, HttpUrl url, String setCookie) { int pos = 0; int limit = setCookie.length(); int cookiePairEnd = delimiterOffset(setCookie, pos, limit, ';'); int pairEqualsSign = delimiterOffset(setCookie, pos, cookiePairEnd, '='); if (pairEqualsSign == cookiePairEnd) return null; int attributePairEnd = delimiterOffset(setCookie, pos, limit, ';'); int attributeEqualsSign = delimiterOffset(setCookie, pos, attributePairEnd, '='); String attributeName = trimSubstring(setCookie, pos, attributeEqualsSign); String attributeValue = attributeEqualsSign < attributePairEnd
authority: while (true) { int componentDelimiterOffset = delimiterOffset(input, pos, limit, "@/\\?#"); int c = componentDelimiterOffset != limit ? input.charAt(componentDelimiterOffset) int passwordColonOffset = delimiterOffset( input, pos, componentDelimiterOffset, ':'); String canonicalUsername = canonicalize(input, pos, passwordColonOffset, int pathDelimiterOffset = delimiterOffset(input, pos, limit, "?#"); resolvePath(input, pos, pathDelimiterOffset); pos = pathDelimiterOffset; int queryDelimiterOffset = delimiterOffset(input, pos, limit, '#'); this.encodedQueryNamesAndValues = queryStringToNamesAndValues(canonicalize( input, pos + 1, queryDelimiterOffset, QUERY_ENCODE_SET, true, false, true, true, null));
public List<String> encodedPathSegments() { int pathStart = url.indexOf('/', scheme.length() + 3); int pathEnd = delimiterOffset(url, pathStart, url.length(), "?#"); List<String> result = new ArrayList<>(); for (int i = pathStart; i < pathEnd; ) { i++; // Skip the '/'. int segmentEnd = delimiterOffset(url, i, pathEnd, '/'); result.add(url.substring(i, segmentEnd)); i = segmentEnd; } return result; }
/** * Returns the query of this URL, encoded for use in HTTP resource resolution. The returned string * may be null (for URLs with no query), empty (for URLs with an empty query) or non-empty (all * other URLs). */ public String encodedQuery() { if (queryNamesAndValues == null) return null; // No query. int queryStart = url.indexOf('?') + 1; int queryEnd = delimiterOffset(url, queryStart + 1, url.length(), '#'); return url.substring(queryStart, queryEnd); }
/** Returns the username, or an empty string if none is set. */ public String encodedUsername() { if (username.isEmpty()) return ""; int usernameStart = scheme.length() + 3; // "://".length() == 3. int usernameEnd = delimiterOffset(url, usernameStart, url.length(), ":@"); return url.substring(usernameStart, usernameEnd); }