Skip to content

Commit

Permalink
fix: fix usage with ws:// scheme
Browse files Browse the repository at this point in the history
The URL constructor does not support the ws:// scheme, and would throw:

> java.net.MalformedURLException: unknown protocol: ws

Related:

- #650
- #555
- #233

Backported from 67fd5f3
  • Loading branch information
darrachequesne committed Jul 10, 2022
1 parent 48bf83f commit e57160a
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 81 deletions.
20 changes: 7 additions & 13 deletions src/main/java/io/socket/client/IO.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
Expand Down Expand Up @@ -58,17 +57,12 @@ public static Socket socket(URI uri, Options opts) {
opts = new Options();
}

URL parsed = Url.parse(uri);
URI source;
try {
source = parsed.toURI();
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
String id = Url.extractId(parsed);
String path = parsed.getPath();
Url.ParsedURI parsed = Url.parse(uri);
URI source = parsed.uri;
String id = parsed.id;

boolean sameNamespace = managers.containsKey(id)
&& managers.get(id).nsps.containsKey(path);
&& managers.get(id).nsps.containsKey(source.getPath());
boolean newConnection = opts.forceNew || !opts.multiplex || sameNamespace;
Manager io;

Expand All @@ -87,12 +81,12 @@ public static Socket socket(URI uri, Options opts) {
io = managers.get(id);
}

String query = parsed.getQuery();
String query = source.getQuery();
if (query != null && (opts.query == null || opts.query.isEmpty())) {
opts.query = query;
}

return io.socket(parsed.getPath(), opts);
return io.socket(source.getPath(), opts);
}


Expand Down
60 changes: 22 additions & 38 deletions src/main/java/io/socket/client/Url.java
Original file line number Diff line number Diff line change
@@ -1,38 +1,39 @@
package io.socket.client;

import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Url {

private static Pattern PATTERN_HTTP = Pattern.compile("^http|ws$");
private static Pattern PATTERN_HTTPS = Pattern.compile("^(http|ws)s$");
/**
* Expected format: "[id:password@]host[:port]"
*/
private static Pattern PATTERN_AUTHORITY = Pattern.compile("^(.*@)?([^:]+)(:\\d+)?$");

private Url() {}

public static URL parse(String uri) throws URISyntaxException {
return parse(new URI(uri));
static class ParsedURI {
public final URI uri;
public final String id;

public ParsedURI(URI uri, String id) {
this.uri = uri;
this.id = id;
}
}

public static URL parse(URI uri) {
public static ParsedURI parse(URI uri) {
String protocol = uri.getScheme();
if (protocol == null || !protocol.matches("^https?|wss?$")) {
protocol = "https";
}

int port = uri.getPort();
if (port == -1) {
if (PATTERN_HTTP.matcher(protocol).matches()) {
if ("http".equals(protocol) || "ws".equals(protocol)) {
port = 80;
} else if (PATTERN_HTTPS.matcher(protocol).matches()) {
} else if ("https".equals(protocol) || "wss".equals(protocol)) {
port = 443;
}
}
Expand All @@ -50,35 +51,18 @@ public static URL parse(URI uri) {
// might happen on some of Samsung Devices such as S4.
_host = extractHostFromAuthorityPart(uri.getRawAuthority());
}
try {
return new URL(protocol + "://"
+ (userInfo != null ? userInfo + "@" : "")
+ _host
+ (port != -1 ? ":" + port : "")
+ path
+ (query != null ? "?" + query : "")
+ (fragment != null ? "#" + fragment : ""));
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}

public static String extractId(String url) throws MalformedURLException {
return extractId(new URL(url));
URI completeUri = URI.create(protocol + "://"
+ (userInfo != null ? userInfo + "@" : "")
+ _host
+ (port != -1 ? ":" + port : "")
+ path
+ (query != null ? "?" + query : "")
+ (fragment != null ? "#" + fragment : ""));
String id = protocol + "://" + _host + ":" + port;

return new ParsedURI(completeUri, id);
}

public static String extractId(URL url) {
String protocol = url.getProtocol();
int port = url.getPort();
if (port == -1) {
if (PATTERN_HTTP.matcher(protocol).matches()) {
port = 80;
} else if (PATTERN_HTTPS.matcher(protocol).matches()) {
port = 443;
}
}
return protocol + "://" + url.getHost() + ":" + port;
}

private static String extractHostFromAuthorityPart(String authority)
{
Expand Down
85 changes: 55 additions & 30 deletions src/test/java/io/socket/client/UrlTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URI;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
Expand All @@ -15,58 +13,85 @@
@RunWith(JUnit4.class)
public class UrlTest {

private URI parse(String uri) {
return Url.parse(URI.create(uri)).uri;
}

private String extractId(String uri) {
return Url.parse(URI.create(uri)).id;
}

@Test
public void parse() throws URISyntaxException {
assertThat(Url.parse("http://username:password@host:8080/directory/file?query#ref").toString(),
public void parse() {
assertThat(parse("http://username:password@host:8080/directory/file?query#ref").toString(),
is("http://username:password@host:8080/directory/file?query#ref"));
}

@Test
public void parseRelativePath() throws URISyntaxException {
URL url = Url.parse("https://woot.com/test");
assertThat(url.getProtocol(), is("https"));
assertThat(url.getHost(), is("woot.com"));
assertThat(url.getPath(), is("/test"));
public void parseRelativePath() {
URI uri = parse("https://woot.com/test");
assertThat(uri.getScheme(), is("https"));
assertThat(uri.getHost(), is("woot.com"));
assertThat(uri.getPath(), is("/test"));
}

@Test
public void parseNoProtocol() throws URISyntaxException {
URL url = Url.parse("//localhost:3000");
assertThat(url.getProtocol(), is("https"));
assertThat(url.getHost(), is("localhost"));
assertThat(url.getPort(), is(3000));
public void parseNoProtocol() {
URI uri = parse("//localhost:3000");
assertThat(uri.getScheme(), is("https"));
assertThat(uri.getHost(), is("localhost"));
assertThat(uri.getPort(), is(3000));
}

@Test
public void parseNamespace() throws URISyntaxException {
assertThat(Url.parse("http://woot.com/woot").getPath(), is("/woot"));
assertThat(Url.parse("http://google.com").getPath(), is("/"));
assertThat(Url.parse("http://google.com/").getPath(), is("/"));
public void parseNamespace() {
assertThat(parse("http://woot.com/woot").getPath(), is("/woot"));
assertThat(parse("http://google.com").getPath(), is("/"));
assertThat(parse("http://google.com/").getPath(), is("/"));
}

@Test
public void parseDefaultPort() throws URISyntaxException {
assertThat(Url.parse("http://google.com/").toString(), is("http://google.com:80/"));
assertThat(Url.parse("https://google.com/").toString(), is("https://google.com:443/"));
public void parseDefaultPort() {
assertThat(parse("http://google.com/").toString(), is("http://google.com:80/"));
assertThat(parse("https://google.com/").toString(), is("https://google.com:443/"));
}

@Test
public void extractId() throws MalformedURLException {
String id1 = Url.extractId("http://google.com:80/");
String id2 = Url.extractId("http://google.com/");
String id3 = Url.extractId("https://google.com/");
public void testWsProtocol() {
URI uri = parse("ws://woot.com/test");
assertThat(uri.getScheme(), is("ws"));
assertThat(uri.getHost(), is("woot.com"));
assertThat(uri.getPort(), is(80));
assertThat(uri.getPath(), is("/test"));
}

@Test
public void testWssProtocol() {
URI uri = parse("wss://woot.com/test");
assertThat(uri.getScheme(), is("wss"));
assertThat(uri.getHost(), is("woot.com"));
assertThat(uri.getPort(), is(443));
assertThat(uri.getPath(), is("/test"));
}

@Test
public void extractId() {
String id1 = extractId("http://google.com:80/");
String id2 = extractId("http://google.com/");
String id3 = extractId("https://google.com/");
assertThat(id1, is(id2));
assertThat(id1, is(not(id3)));
assertThat(id2, is(not(id3)));
}

@Test
public void ipv6() throws URISyntaxException, MalformedURLException {
public void ipv6() {
String url = "http://[::1]";
URL parsed = Url.parse(url);
assertThat(parsed.getProtocol(), is("http"));
URI parsed = parse(url);
assertThat(parsed.getScheme(), is("http"));
assertThat(parsed.getHost(), is("[::1]"));
assertThat(parsed.getPort(), is(80));
assertThat(Url.extractId(url), is("http://[::1]:80"));
assertThat(extractId(url), is("http://[::1]:80"));
}

}

0 comments on commit e57160a

Please sign in to comment.