Skip to content

Commit 9628376

Browse files
authored
Merge pull request #390 from Chainfire/https-proxy
HTTPS proxy support
2 parents 56c7a2c + 5af8a38 commit 9628376

3 files changed

Lines changed: 73 additions & 4 deletions

File tree

lib/src/main/java/xyz/gianlu/librespot/core/Session.java

Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@
5656
import javax.crypto.Cipher;
5757
import javax.crypto.Mac;
5858
import javax.crypto.spec.SecretKeySpec;
59+
import javax.net.SocketFactory;
60+
import javax.net.ssl.SSLSocketFactory;
5961
import javax.xml.parsers.DocumentBuilder;
6062
import javax.xml.parsers.DocumentBuilderFactory;
6163
import javax.xml.parsers.ParserConfigurationException;
@@ -156,6 +158,10 @@ public Request authenticate(Route route, @NotNull Response response) {
156158
}
157159
});
158160
}
161+
if (conf.proxyType == Proxy.Type.HTTP && conf.proxySSL) {
162+
// builder.socketFactory(SSLSocketFactory.getDefault()) throws an error on some okhttp versions
163+
builder.socketFactory(new DelegatingSocketFactory(SSLSocketFactory.getDefault()));
164+
}
159165
}
160166

161167
builder.addInterceptor(chain -> {
@@ -1029,6 +1035,7 @@ public final static class Configuration {
10291035
// Proxy
10301036
public final boolean proxyEnabled;
10311037
public final Proxy.Type proxyType;
1038+
public final boolean proxySSL;
10321039
public final String proxyAddress;
10331040
public final int proxyPort;
10341041
public final boolean proxyAuth;
@@ -1054,13 +1061,15 @@ public final static class Configuration {
10541061
// Network
10551062
public final int connectionTimeout;
10561063

1057-
private Configuration(boolean proxyEnabled, Proxy.Type proxyType, String proxyAddress, int proxyPort, boolean proxyAuth, String proxyUsername, String proxyPassword,
1064+
private Configuration(boolean proxyEnabled, Proxy.Type proxyType, boolean proxySSL, String proxyAddress,
1065+
int proxyPort, boolean proxyAuth, String proxyUsername, String proxyPassword,
10581066
TimeProvider.Method timeSynchronizationMethod, int timeManualCorrection,
10591067
boolean cacheEnabled, File cacheDir, boolean doCacheCleanUp,
10601068
boolean storeCredentials, File storedCredentialsFile,
10611069
boolean retryOnChunkError, int connectionTimeout) {
10621070
this.proxyEnabled = proxyEnabled;
10631071
this.proxyType = proxyType;
1072+
this.proxySSL = proxySSL;
10641073
this.proxyAddress = proxyAddress;
10651074
this.proxyPort = proxyPort;
10661075
this.proxyAuth = proxyAuth;
@@ -1081,6 +1090,7 @@ public static final class Builder {
10811090
// Proxy
10821091
private boolean proxyEnabled = false;
10831092
private Proxy.Type proxyType;
1093+
private boolean proxySSL = false;
10841094
private String proxyAddress;
10851095
private int proxyPort;
10861096
private boolean proxyAuth;
@@ -1119,6 +1129,11 @@ public Builder setProxyType(Proxy.Type proxyType) {
11191129
return this;
11201130
}
11211131

1132+
public Builder setProxySSL(boolean proxySSL) {
1133+
this.proxySSL = proxySSL;
1134+
return this;
1135+
}
1136+
11221137
public Builder setProxyAddress(String proxyAddress) {
11231138
this.proxyAddress = proxyAddress;
11241139
return this;
@@ -1191,7 +1206,8 @@ public Builder setConnectionTimeout(int connectionTimeout) {
11911206

11921207
@NotNull
11931208
public Configuration build() {
1194-
return new Configuration(proxyEnabled, proxyType, proxyAddress, proxyPort, proxyAuth, proxyUsername, proxyPassword,
1209+
return new Configuration(proxyEnabled, proxyType, proxySSL, proxyAddress, proxyPort, proxyAuth,
1210+
proxyUsername, proxyPassword,
11951211
timeSynchronizationMethod, timeManualCorrection,
11961212
cacheEnabled, cacheDir, doCacheCleanUp,
11971213
storeCredentials, storedCredentialsFile,
@@ -1245,7 +1261,12 @@ static ConnectionHolder create(@NotNull String addr, @NotNull Configuration conf
12451261

12461262
switch (conf.proxyType) {
12471263
case HTTP:
1248-
Socket sock = new Socket(conf.proxyAddress, conf.proxyPort);
1264+
Socket sock;
1265+
if (conf.proxySSL) {
1266+
sock = SSLSocketFactory.getDefault().createSocket(conf.proxyAddress, conf.proxyPort);
1267+
} else{
1268+
sock = new Socket(conf.proxyAddress, conf.proxyPort);
1269+
}
12491270
OutputStream out = sock.getOutputStream();
12501271
DataInputStream in = new DataInputStream(sock.getInputStream());
12511272

@@ -1264,7 +1285,7 @@ static ConnectionHolder create(@NotNull String addr, @NotNull Configuration conf
12641285
// Read all headers
12651286
}
12661287

1267-
LOGGER.info("Successfully connected to the HTTP proxy.");
1288+
LOGGER.info(String.format("Successfully connected to the %s proxy.", conf.proxySSL ? "HTTPS" : "HTTP"));
12681289
return new ConnectionHolder(sock);
12691290
case SOCKS:
12701291
if (conf.proxyAuth) {
@@ -1399,4 +1420,50 @@ public void run() {
13991420
LOGGER.trace("Session.Receiver stopped");
14001421
}
14011422
}
1423+
1424+
/**
1425+
* A {@link SocketFactory} that delegates calls. Sockets can be configured after creation by
1426+
* overriding {@link #configureSocket(java.net.Socket)}.
1427+
*
1428+
* Copy/pasted from okhttp3 tests sources for HTTPS proxy support
1429+
*/
1430+
public static class DelegatingSocketFactory extends SocketFactory {
1431+
private final SocketFactory delegate;
1432+
1433+
public DelegatingSocketFactory(SocketFactory delegate) {
1434+
this.delegate = delegate;
1435+
}
1436+
1437+
@Override public Socket createSocket() throws IOException {
1438+
Socket socket = delegate.createSocket();
1439+
return configureSocket(socket);
1440+
}
1441+
1442+
@Override public Socket createSocket(String host, int port) throws IOException {
1443+
Socket socket = delegate.createSocket(host, port);
1444+
return configureSocket(socket);
1445+
}
1446+
1447+
@Override public Socket createSocket(String host, int port, InetAddress localAddress,
1448+
int localPort) throws IOException {
1449+
Socket socket = delegate.createSocket(host, port, localAddress, localPort);
1450+
return configureSocket(socket);
1451+
}
1452+
1453+
@Override public Socket createSocket(InetAddress host, int port) throws IOException {
1454+
Socket socket = delegate.createSocket(host, port);
1455+
return configureSocket(socket);
1456+
}
1457+
1458+
@Override public Socket createSocket(InetAddress host, int port, InetAddress localAddress,
1459+
int localPort) throws IOException {
1460+
Socket socket = delegate.createSocket(host, port, localAddress, localPort);
1461+
return configureSocket(socket);
1462+
}
1463+
1464+
protected Socket configureSocket(Socket socket) throws IOException {
1465+
// No-op by default.
1466+
return socket;
1467+
}
1468+
}
14021469
}

player/src/main/java/xyz/gianlu/librespot/player/FileConfiguration.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,7 @@ public Session.Configuration toSession() {
411411
.setTimeManualCorrection(config.get("time.manualCorrection"))
412412
.setProxyEnabled(config.get("proxy.enabled"))
413413
.setProxyType(config.getEnum("proxy.type", Proxy.Type.class))
414+
.setProxySSL(config.get("proxy.ssl"))
414415
.setProxyAddress(config.get("proxy.address"))
415416
.setProxyPort(config.get("proxy.port"))
416417
.setProxyAuth(config.get("proxy.auth"))

player/src/main/resources/default.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ host = "0.0.0.0" # API listen interface (`api` module only)
5858
[proxy] ### Proxy ###
5959
enabled = false # Whether the proxy is enabled
6060
type = "HTTP" # The proxy type (HTTP, SOCKS)
61+
ssl = false # Connect to proxy using SSL (HTTP only)
6162
address = "" # The proxy hostname
6263
port = 0 # The proxy port
6364
auth = false # Whether authentication is enabled on the server

0 commit comments

Comments
 (0)