add better user/password handling in userInfo, for instance passwords with colon
This commit is contained in:
parent
2b284199bb
commit
412b6eaeb5
5 changed files with 111 additions and 51 deletions
|
@ -1,6 +1,6 @@
|
|||
group = org.xbib
|
||||
name = net
|
||||
version = 1.1.1
|
||||
version = 1.1.3
|
||||
|
||||
jackson.version = 2.8.11
|
||||
junit.version = 4.12
|
||||
|
|
|
@ -248,7 +248,7 @@ public class URL implements Comparable<URL> {
|
|||
public static URL from(String input, boolean resolve) {
|
||||
try {
|
||||
return parser().parse(input, resolve);
|
||||
} catch (URLSyntaxException e) {
|
||||
} catch (URLSyntaxException | MalformedInputException | UnmappableCharacterException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
@ -260,7 +260,7 @@ public class URL implements Comparable<URL> {
|
|||
public static URL from(URL base, String spec) {
|
||||
try {
|
||||
return new Resolver(base).resolve(spec);
|
||||
} catch (URLSyntaxException e) {
|
||||
} catch (URLSyntaxException | MalformedInputException | UnmappableCharacterException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
@ -330,6 +330,22 @@ public class URL implements Comparable<URL> {
|
|||
return builder.userInfo;
|
||||
}
|
||||
|
||||
public String getUser() {
|
||||
if (builder.userInfo == null) {
|
||||
return null;
|
||||
}
|
||||
Pair<String, String> p = indexOf(COLON_CHAR, builder.userInfo);
|
||||
return decode(p.first);
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
if (builder.userInfo == null) {
|
||||
return null;
|
||||
}
|
||||
Pair<String, String> p = indexOf(COLON_CHAR, builder.userInfo);
|
||||
return decode(p.second);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the host name ('www.example.com' or '192.168.0.1:8080' or '[fde2:d7de:302::]') of the {@code URL}.
|
||||
* @return the host name
|
||||
|
@ -668,6 +684,13 @@ public class URL implements Comparable<URL> {
|
|||
return str == null || str.isEmpty();
|
||||
}
|
||||
|
||||
private static Pair<String, String> indexOf(char ch, String input) {
|
||||
int i = input.indexOf(ch);
|
||||
String k = i >= 0 ? input.substring(0, i) : input;
|
||||
String v = i >= 0 ? input.substring(i + 1) : null;
|
||||
return new Pair<>(k, v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return toString().hashCode();
|
||||
|
@ -675,7 +698,7 @@ public class URL implements Comparable<URL> {
|
|||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return other != null && other instanceof URL && toString().equals(other.toString());
|
||||
return other instanceof URL && toString().equals(other.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -751,6 +774,16 @@ public class URL implements Comparable<URL> {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder userInfo(String user, String pass) {
|
||||
try {
|
||||
this.userInfo = PercentEncoders.getRegNameEncoder(charset).encode(user) + ':' +
|
||||
PercentEncoders.getRegNameEncoder(charset).encode(pass);
|
||||
} catch (MalformedInputException | UnmappableCharacterException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder host(String host) {
|
||||
this.host = host;
|
||||
this.protocolVersion = ProtocolVersion.NONE;
|
||||
|
@ -935,11 +968,13 @@ public class URL implements Comparable<URL> {
|
|||
builder = new Builder();
|
||||
}
|
||||
|
||||
public URL parse(String input) throws URLSyntaxException {
|
||||
public URL parse(String input)
|
||||
throws URLSyntaxException, MalformedInputException, UnmappableCharacterException {
|
||||
return parse(input, true);
|
||||
}
|
||||
|
||||
public URL parse(String input, boolean resolve) throws URLSyntaxException {
|
||||
public URL parse(String input, boolean resolve)
|
||||
throws URLSyntaxException, MalformedInputException, UnmappableCharacterException {
|
||||
if (isNullOrEmpty(input)) {
|
||||
return INVALID;
|
||||
}
|
||||
|
@ -992,17 +1027,20 @@ public class URL implements Comparable<URL> {
|
|||
return p.getSecond();
|
||||
}
|
||||
|
||||
private String parseUserInfo(Builder builder, String input) {
|
||||
private String parseUserInfo(Builder builder, String input)
|
||||
throws MalformedInputException, UnmappableCharacterException {
|
||||
String remaining = input;
|
||||
int i = input.lastIndexOf(AT_CHAR);
|
||||
if (i > 0) {
|
||||
remaining = input.substring(i + 1);
|
||||
builder.userInfo(input.substring(0, i));
|
||||
String userInfo = input.substring(0, i);
|
||||
builder.userInfo(builder.percentDecoder.decode(userInfo));
|
||||
}
|
||||
return remaining;
|
||||
}
|
||||
|
||||
private void parseHostAndPort(Builder builder, String host, boolean resolve) throws URLSyntaxException {
|
||||
private void parseHostAndPort(Builder builder, String host, boolean resolve)
|
||||
throws URLSyntaxException {
|
||||
if (host.indexOf('[') == 0) {
|
||||
int i = host.lastIndexOf(']');
|
||||
if (i >= 0) {
|
||||
|
@ -1126,13 +1164,6 @@ public class URL implements Comparable<URL> {
|
|||
builder.query(query);
|
||||
}
|
||||
}
|
||||
|
||||
private Pair<String, String> indexOf(char ch, String input) {
|
||||
int i = input.indexOf(ch);
|
||||
String k = i >= 0 ? input.substring(0, i) : input;
|
||||
String v = i >= 0 ? input.substring(i + 1) : null;
|
||||
return new Pair<>(k, v);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1147,7 +1178,8 @@ public class URL implements Comparable<URL> {
|
|||
this.base = base;
|
||||
}
|
||||
|
||||
public URL resolve(String relative) throws URLSyntaxException {
|
||||
public URL resolve(String relative)
|
||||
throws URLSyntaxException, MalformedInputException, UnmappableCharacterException {
|
||||
if (relative == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -1158,7 +1190,8 @@ public class URL implements Comparable<URL> {
|
|||
return resolve(url);
|
||||
}
|
||||
|
||||
public URL resolve(URL relative) throws URLSyntaxException {
|
||||
public URL resolve(URL relative)
|
||||
throws URLSyntaxException {
|
||||
if (relative == null || relative == INVALID) {
|
||||
throw new URLSyntaxException("relative URL is invalid");
|
||||
}
|
||||
|
|
|
@ -10,17 +10,17 @@ import static org.junit.Assert.assertEquals;
|
|||
public class URLBuilderTest {
|
||||
|
||||
@Test
|
||||
public void testNoUrlParts() throws Exception {
|
||||
public void testNoUrlParts() {
|
||||
assertUrl(URL.http().resolveFromHost("foo.com").toUrlString(), "http://foo.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithPort() throws Exception {
|
||||
public void testWithPort() {
|
||||
assertUrl(URL.http().resolveFromHost("foo.com").port(33).toUrlString(), "http://foo.com:33");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimplePath() throws Exception {
|
||||
public void testSimplePath() {
|
||||
assertUrl(URL.http().resolveFromHost("foo.com")
|
||||
.pathSegment("seg1")
|
||||
.pathSegment("seg2")
|
||||
|
@ -29,7 +29,7 @@ public class URLBuilderTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testPathWithReserved() throws Exception {
|
||||
public void testPathWithReserved() {
|
||||
// RFC 1738 S3.3
|
||||
assertUrl(URL.http().resolveFromHost("foo.com")
|
||||
.pathSegment("seg/;?ment")
|
||||
|
@ -38,14 +38,14 @@ public class URLBuilderTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testPathSegments() throws Exception {
|
||||
public void testPathSegments() {
|
||||
assertUrl(URL.http().resolveFromHost("foo.com")
|
||||
.pathSegments("seg1", "seg2", "seg3")
|
||||
.toUrlString(), "http://foo.com/seg1/seg2/seg3");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatrixWithReserved() throws Exception {
|
||||
public void testMatrixWithReserved() {
|
||||
assertUrl(URL.http().resolveFromHost("foo.com")
|
||||
.pathSegment("foo")
|
||||
.matrixParam("foo", "bar")
|
||||
|
@ -55,28 +55,28 @@ public class URLBuilderTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testUrlEncodedPathSegmentUtf8() throws Exception {
|
||||
public void testUrlEncodedPathSegmentUtf8() {
|
||||
assertUrl(URL.http().resolveFromHost("foo.com")
|
||||
.pathSegment("snowman").pathSegment("\u2603")
|
||||
.toUrlString(), "http://foo.com/snowman/%E2%98%83");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUrlEncodedPathSegmentUtf8SurrogatePair() throws Exception {
|
||||
public void testUrlEncodedPathSegmentUtf8SurrogatePair() {
|
||||
assertUrl(URL.http().resolveFromHost("foo.com")
|
||||
.pathSegment("clef").pathSegment("\ud834\udd1e")
|
||||
.toUrlString(), "http://foo.com/clef/%F0%9D%84%9E");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryParamNoPath() throws Exception {
|
||||
public void testQueryParamNoPath() {
|
||||
assertUrl(URL.http().resolveFromHost("foo.com")
|
||||
.queryParam("foo", "bar")
|
||||
.toUrlString(), "http://foo.com?foo=bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryParamsDuplicated() throws Exception {
|
||||
public void testQueryParamsDuplicated() {
|
||||
assertUrl(URL.http().resolveFromHost("foo.com")
|
||||
.queryParam("foo", "bar")
|
||||
.queryParam("foo", "bar2")
|
||||
|
@ -86,7 +86,7 @@ public class URLBuilderTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeQueryParams() throws Exception {
|
||||
public void testEncodeQueryParams() {
|
||||
assertUrl(URL.http().resolveFromHost("foo.com")
|
||||
.queryParam("foo", "bar&=#baz")
|
||||
.queryParam("foo", "bar?/2")
|
||||
|
@ -94,7 +94,7 @@ public class URLBuilderTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeQueryParamWithSpaceAndPlus() throws Exception {
|
||||
public void testEncodeQueryParamWithSpaceAndPlus() {
|
||||
assertUrl(URL.http().resolveFromHost("foo.com")
|
||||
.queryParam("foo", "spa ce")
|
||||
.queryParam("fo+o", "plus+")
|
||||
|
@ -102,7 +102,7 @@ public class URLBuilderTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testPlusInVariousParts() throws Exception {
|
||||
public void testPlusInVariousParts() {
|
||||
assertUrl(URL.http().resolveFromHost("foo.com")
|
||||
.pathSegment("has+plus")
|
||||
.matrixParam("plusMtx", "pl+us")
|
||||
|
@ -112,7 +112,7 @@ public class URLBuilderTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testFragment() throws Exception {
|
||||
public void testFragment() {
|
||||
assertUrl(URL.http().resolveFromHost("foo.com")
|
||||
.queryParam("foo", "bar")
|
||||
.fragment("#frag/?")
|
||||
|
@ -120,7 +120,7 @@ public class URLBuilderTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testAllParts() throws Exception {
|
||||
public void testAllParts() {
|
||||
assertUrl(URL.https().resolveFromHost("foo.bar.com").port(3333)
|
||||
.pathSegment("foo")
|
||||
.pathSegment("bar")
|
||||
|
@ -134,24 +134,24 @@ public class URLBuilderTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testSlashInHost() throws Exception {
|
||||
public void testSlashInHost() {
|
||||
URL.http().resolveFromHost("/").toUrlString();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGoogle() throws Exception {
|
||||
public void testGoogle() {
|
||||
URL url = URL.https().resolveFromHost("google.com").build();
|
||||
assertEquals("https://google.com", url.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadIPv4LiteralDoesntChoke() throws Exception {
|
||||
public void testBadIPv4LiteralDoesntChoke() {
|
||||
assertUrl(URL.http().resolveFromHost("300.100.50.1")
|
||||
.toUrlString(), "http://300.100.50.1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIPv4Literal() throws Exception {
|
||||
public void testIPv4Literal() {
|
||||
if ("false".equals(System.getProperty("java.net.preferIPv6Addresses"))) {
|
||||
assertUrl(URL.http().resolveFromHost("127.0.0.1")
|
||||
.toUrlString(), "http://localhost");
|
||||
|
@ -161,7 +161,7 @@ public class URLBuilderTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testIPv6LiteralLocalhost() throws Exception {
|
||||
public void testIPv6LiteralLocalhost() {
|
||||
String s = URL.http().resolveFromHost("[::1]").toUrlString();
|
||||
if ("true".equals(System.getProperty("java.net.preferIPv6Addresses"))) {
|
||||
assertEquals("http://[0:0:0:0:0:0:0:1]", s);
|
||||
|
@ -171,7 +171,7 @@ public class URLBuilderTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testIPv6Literal() throws Exception {
|
||||
public void testIPv6Literal() {
|
||||
if ("true".equals(System.getProperty("java.net.preferIPv6Addresses"))) {
|
||||
String s = URL.http().resolveFromHost("[2001:db8:85a3::8a2e:370:7334]")
|
||||
.toUrlString();
|
||||
|
@ -180,21 +180,21 @@ public class URLBuilderTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testEncodedRegNameSingleByte() throws Exception {
|
||||
public void testEncodedRegNameSingleByte() {
|
||||
String s = URL.http().resolveFromHost("host?name;")
|
||||
.toUrlString();
|
||||
assertEquals("http://host%3Fname;", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodedRegNameMultiByte() throws Exception {
|
||||
public void testEncodedRegNameMultiByte() {
|
||||
String s = URL.http().host("snow\u2603man")
|
||||
.toUrlString();
|
||||
assertEquals("http://snow%E2%98%83man", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testThreePathSegments() throws Exception {
|
||||
public void testThreePathSegments() {
|
||||
String s = URL.https().resolveFromHost("foo.com")
|
||||
.pathSegments("a", "b", "c")
|
||||
.toUrlString();
|
||||
|
@ -202,7 +202,7 @@ public class URLBuilderTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testThreePathSegmentsWithQueryParams() throws Exception {
|
||||
public void testThreePathSegmentsWithQueryParams() {
|
||||
String s = URL.https().resolveFromHost("foo.com")
|
||||
.pathSegments("a", "b", "c")
|
||||
.queryParam("foo", "bar")
|
||||
|
@ -211,7 +211,7 @@ public class URLBuilderTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testIntermingledMatrixParamsAndPathSegments() throws Exception {
|
||||
public void testIntermingledMatrixParamsAndPathSegments() {
|
||||
String s = URL.http().resolveFromHost("foo.com")
|
||||
.pathSegments("seg1", "seg2")
|
||||
.matrixParam("m1", "v1")
|
||||
|
@ -222,7 +222,7 @@ public class URLBuilderTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testUseQueryParamAfterQuery() throws Exception {
|
||||
public void testUseQueryParamAfterQuery() {
|
||||
String s = URL.http().resolveFromHost("foo.com")
|
||||
.query("q")
|
||||
.queryParam("foo", "bar")
|
||||
|
@ -231,7 +231,7 @@ public class URLBuilderTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testUseQueryAfterQueryParam() throws Exception {
|
||||
public void testUseQueryAfterQueryParam() {
|
||||
String s = URL.http().resolveFromHost("foo.com")
|
||||
.queryParam("foo", "bar")
|
||||
.query("q")
|
||||
|
@ -240,7 +240,7 @@ public class URLBuilderTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testQueryWithNoSpecialChars() throws Exception {
|
||||
public void testQueryWithNoSpecialChars() {
|
||||
String s = URL.http().resolveFromHost("foo.com")
|
||||
.query("q")
|
||||
.toUrlString();
|
||||
|
@ -248,14 +248,14 @@ public class URLBuilderTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testQueryWithOkSpecialChars() throws Exception {
|
||||
public void testQueryWithOkSpecialChars() {
|
||||
String s = URL.http().resolveFromHost("foo.com")
|
||||
.query("q?/&=").toUrlString();
|
||||
assertEquals("http://foo.com?q?/&=", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryWithEscapedSpecialChars() throws Exception {
|
||||
public void testQueryWithEscapedSpecialChars() {
|
||||
String s = URL.http().resolveFromHost("foo.com")
|
||||
.query("q#+").toUrlString();
|
||||
assertEquals("http://foo.com?q%23%2B", s);
|
||||
|
@ -268,7 +268,19 @@ public class URLBuilderTest {
|
|||
assertEquals("https://google.com:8008/foobar", builder.build().toString());
|
||||
}
|
||||
|
||||
private void assertUrl(String urlString, String expected) throws Exception {
|
||||
@Test
|
||||
public void testUserInfo(){
|
||||
String s = URL.http().userInfo("foo:bar").host("foo.com").toUrlString();
|
||||
assertEquals("http://foo:bar@foo.com", s);
|
||||
s = URL.http().userInfo("foo:foo:bar").host("foo.com").toUrlString();
|
||||
assertEquals("http://foo:foo:bar@foo.com", s);
|
||||
s = URL.http().userInfo("foo:foo%3Abar").host("foo.com").toUrlString();
|
||||
assertEquals("http://foo:foo%3Abar@foo.com", s);
|
||||
s = URL.http().userInfo("foo", "foo:bar").host("foo.com").toUrlString();
|
||||
assertEquals("http://foo:foo%3Abar@foo.com", s);
|
||||
}
|
||||
|
||||
private void assertUrl(String urlString, String expected) {
|
||||
assertEquals(expected, urlString);
|
||||
assertEquals(expected, URL.from(urlString).toExternalForm());
|
||||
}
|
||||
|
|
|
@ -369,6 +369,18 @@ public class URLParserTest {
|
|||
assertEquals("plus+frag", url.getFragment());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserInfo() throws Exception {
|
||||
URL url = URL.parser().parse("http://foo:bar@foo.com/");
|
||||
assertEquals("foo:bar", url.getUserInfo());
|
||||
url = URL.parser().parse("http://foo:foo:bar@foo.com/");
|
||||
assertEquals("foo:foo:bar", url.getUserInfo());
|
||||
url = URL.parser().parse("http://foo:foo%3Abar@foo.com/");
|
||||
assertEquals("foo:foo:bar", url.getUserInfo());
|
||||
assertEquals("foo", url.getUser());
|
||||
assertEquals("foo:bar", url.getPassword());
|
||||
}
|
||||
|
||||
private void assertUrlCompatibility(String url) throws Exception {
|
||||
String s = URL.from(url).toExternalForm();
|
||||
assertEquals(s, URL.from(s).toExternalForm());
|
||||
|
|
|
@ -5,6 +5,8 @@ import org.junit.Test;
|
|||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.charset.MalformedInputException;
|
||||
import java.nio.charset.UnmappableCharacterException;
|
||||
|
||||
/**
|
||||
*/
|
||||
|
@ -98,7 +100,8 @@ public class URLResolverTest {
|
|||
resolve("http://a/b/c/d;p?q", "http://e/f/g/h", "http://e/f/g/h");
|
||||
}
|
||||
|
||||
private void resolve(String inputBase, String spec, String expected) throws URLSyntaxException {
|
||||
private void resolve(String inputBase, String spec, String expected)
|
||||
throws URLSyntaxException, MalformedInputException, UnmappableCharacterException {
|
||||
assertEquals(expected, URL.base(inputBase).resolve(spec).toExternalForm());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue