Skip to content

Commit

Permalink
[#1] Support websocket proxy
Browse files Browse the repository at this point in the history
  • Loading branch information
WikiDru committed Sep 26, 2018
1 parent 650bb73 commit 6fb3617
Show file tree
Hide file tree
Showing 18 changed files with 886 additions and 243 deletions.
50 changes: 22 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
# ZeroProxy is a multi purpose http proxy.
* Support http(https) proxy
* Support websocket proxy (Not yet)
* Support multiple targets
# ZeroProxy is a multi target http/websocket proxy.
* Support http/https proxy
* Support ws/wss proxy
* Response use json for multiple requests.
* Used json for responding of multiple requests

[![Build Status](https://travis-ci.org/code13k/zeroproxy.svg?branch=master)](https://travis-ci.org/code13k/zeroproxy)

[![Build Status](https://travis-ci.org/code13k/zeroproxy.svg?branch=master)](https://travis-ci.org/code13k/zeroproxy)

# Supported protocol
* http / https
* ws / wss (Not yet)


# Configuration
Expand All @@ -23,43 +21,39 @@ port:
api_http: 55552
```
## proxy_config.yml
It's proxy configuration file.
## proxy_http_config.yml
It's proxy http configuration file.
```yaml
# Example-1
- location: /zeroproxy_example
type: round-robin
- location: /helios_pub
connect_timeout: 3000
idle_timeout: 3000
targets:
- http://1.1.1.1:3000
- http://127.0.0.1:55402

# Example-2
- location: /zeroproxy/example
type: random
- location: /helios_api
connect_timeout: 3000
idle_timeout: 3000
targets:
- http://1.1.1.1:3000
- http://1.1.1.1:3001
- http://127.0.0.1:55403
- http://127.0.0.1:55403

# Example-3
- location: /zeroproxy/example/1
type: all
- location: /thumbly_api
connect_timeout: 3000
idle_timeout: 3000
targets:
- http://1.1.1.1:3000
- http://1.1.1.1:3001
- http://1.1.1.1:3002
- http://127.0.0.1:57911
```
# Example-4
- location: /
type: round-robin
connect_timeout: 3000
idle_timeout: 3000
## proxy_ws_config.yml
It's proxy websocket configuration file.
```yaml
# Example-1
- location: /helios_pub
targets:
- http://1.1.1.1:3000
- ws://127.0.0.1:55401
```
## logback.xml
Expand Down
26 changes: 21 additions & 5 deletions src/main/java/org/code13k/zeroproxy/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@
import io.vertx.core.DeploymentOptions;
import io.vertx.core.Vertx;
import org.code13k.zeroproxy.business.proxy.http.ProxyHttpManager;
import org.code13k.zeroproxy.business.proxy.ws.ProxyWsManager;
import org.code13k.zeroproxy.config.AppConfig;
import org.code13k.zeroproxy.config.LogConfig;
import org.code13k.zeroproxy.config.ProxyConfig;
import org.code13k.zeroproxy.config.ProxyHttpConfig;
import org.code13k.zeroproxy.app.Env;
import org.code13k.zeroproxy.app.Status;
import org.code13k.zeroproxy.config.ProxyWsConfig;
import org.code13k.zeroproxy.service.api.ApiHttpServer;
import org.code13k.zeroproxy.service.proxy.ProxyHttpServer;
import org.code13k.zeroproxy.service.proxy.ProxyWsServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -69,13 +72,15 @@ public static void main(String[] args) {
try {
LogConfig.getInstance().init();
AppConfig.getInstance().init();
ProxyConfig.getInstance().init();
ProxyHttpConfig.getInstance().init();
ProxyWsConfig.getInstance().init();
Env.getInstance().init();
Status.getInstance().init();
ProxyHttpManager.getInstance().init();
ProxyWsManager.getInstance().init();
} catch (Exception e) {
mLogger.error("Failed to initialize", e);
return;
System.exit(1);
}

// Deploy ProxyHttpServer
Expand All @@ -86,7 +91,18 @@ public static void main(String[] args) {
Thread.sleep(1000);
} catch (Exception e) {
mLogger.error("Failed to deploy ProxyHttpServer", e);
return;
System.exit(2);
}

// Deploy ProxyWsServer
try {
DeploymentOptions options = new DeploymentOptions();
options.setInstances(Math.max(1, Env.getInstance().getProcessorCount() / 2));
Vertx.vertx().deployVerticle(ProxyWsServer.class.getName(), options);
Thread.sleep(1000);
} catch (Exception e) {
mLogger.error("Failed to deploy ProxyWsServer", e);
System.exit(3);
}

// Deploy APIHttpServer
Expand All @@ -97,7 +113,7 @@ public static void main(String[] args) {
Thread.sleep(1000);
} catch (Exception e) {
mLogger.error("Failed to deploy ApiHttpServer", e);
return;
System.exit(4);
}

// End
Expand Down
9 changes: 8 additions & 1 deletion src/main/java/org/code13k/zeroproxy/app/Status.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.code13k.zeroproxy.app;

import org.code13k.zeroproxy.business.proxy.http.ProxyHttpManager;
import org.code13k.zeroproxy.business.proxy.ws.ProxyWsManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -42,7 +43,7 @@ private Status() {
*/
public void init() {
// Timer
Timer timer = new Timer("perri-status-logging");
Timer timer = new Timer("zeroproxy-status");
timer.schedule(new TimerTask() {
@Override
public void run() {
Expand All @@ -67,6 +68,12 @@ public void logging() {
// Processed count (HTTP Proxy)
sb.append(", ProxyHttpCount=" + ProxyHttpManager.getInstance().getProcessedCount());

// Connected count (WS Proxy)
sb.append(", ProxyWsConnectedCount=" + ProxyWsManager.getInstance().getConnectedCount());

// Sent text count (WS Proxy)
sb.append(", ProxyWsSentTextCount=" + ProxyWsManager.getInstance().getSentTextCount());

// End
mLogger.info(sb.toString());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@
import io.vertx.ext.web.client.WebClientOptions;
import org.apache.commons.lang3.StringUtils;
import org.code13k.zeroproxy.app.Env;
import org.code13k.zeroproxy.config.ProxyConfig;
import org.code13k.zeroproxy.model.ProxyResponse;
import org.code13k.zeroproxy.model.config.proxy.ProxyInfo;
import org.code13k.zeroproxy.model.ProxyHttpResponse;
import org.code13k.zeroproxy.model.config.proxy.ProxyHttpInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -30,15 +29,14 @@ public class ProxyHttpClient {

// Data
private WebClient mWebClient;
private ProxyInfo mProxyInfo;
private int mRoundRobinIndex = 0;
private ProxyHttpInfo mProxyHttpInfo;

/**
* Constructor
*/
public ProxyHttpClient(ProxyInfo proxyInfo, int eventLoopPoolSize) {
mProxyInfo = proxyInfo;
mLogger.trace("ProxyHttpClient() # " + mProxyInfo);
public ProxyHttpClient(ProxyHttpInfo proxyHttpInfo, int eventLoopPoolSize) {
mProxyHttpInfo = proxyHttpInfo;
mLogger.trace("ProxyHttpClient() # " + mProxyHttpInfo);

// Set user-agent
String userAgent = "Code13k-ZeroProxy/" + Env.getInstance().getVersionString();
Expand All @@ -50,8 +48,8 @@ public ProxyHttpClient(ProxyInfo proxyInfo, int eventLoopPoolSize) {
webClientOptions.setTrustAll(true);
webClientOptions.setSsl(true);
webClientOptions.setTryUseCompression(true);
webClientOptions.setConnectTimeout(mProxyInfo.getConnectTimeout());
webClientOptions.setIdleTimeout(mProxyInfo.getIdleTimeout());
webClientOptions.setConnectTimeout(mProxyHttpInfo.getConnectTimeout());
webClientOptions.setIdleTimeout(mProxyHttpInfo.getIdleTimeout());

// Init VertxOptions
VertxOptions vertxOptions = new VertxOptions();
Expand All @@ -64,7 +62,7 @@ public ProxyHttpClient(ProxyInfo proxyInfo, int eventLoopPoolSize) {
/**
* Proxy
*/
public void proxy(String originPath, HttpMethod originMethod, MultiMap originHeaders, Buffer originBody, Consumer<ProxyResponse> consumer) {
public void proxy(String originPath, HttpMethod originMethod, MultiMap originHeaders, Buffer originBody, Consumer<ProxyHttpResponse> consumer) {
// Headers
final MultiMap headers = MultiMap.caseInsensitiveMultiMap();
headers.addAll(originHeaders);
Expand All @@ -87,55 +85,31 @@ public void proxy(String originPath, HttpMethod originMethod, MultiMap originHea
requestTarget(uri, method, headers, body, new Consumer<HttpResponse<Buffer>>() {
@Override
public void accept(HttpResponse<Buffer> response) {
/**
* Multiple Request
*/
if (ProxyConfig.isMultipleRequest(mProxyInfo) == true) {
Map<String, Object> resultItem = new HashMap<>();
if (response == null) {
resultItem.put("uri", uri);
resultItem.put("statusCode", 504);
resultItem.put("statusMessage", "Gateway Time-out");
resultItem.put("headers", makeDefaultHeaders());
resultItem.put("body", "");
} else {
resultItem.put("uri", uri);
resultItem.put("statusCode", response.statusCode());
resultItem.put("statusMessage", response.statusMessage());
resultItem.put("headers", convertHeaders(response.headers()));
resultItem.put("body", response.bodyAsString());
}
result.add(resultItem);

// END
if (processingCount.decrementAndGet() == 0) {
Buffer proxyBody = Buffer.buffer(new GsonBuilder().create().toJson(result));
ProxyResponse proxyResponse = new ProxyResponse();
proxyResponse.setStatusCode(200);
proxyResponse.setStatusMessage("OK");
proxyResponse.setHeaders(makeProxyResponseHeaders());
proxyResponse.setBody(proxyBody);
consumer.accept(proxyResponse);
}
Map<String, Object> resultItem = new HashMap<>();
if (response == null) {
resultItem.put("uri", uri);
resultItem.put("statusCode", 504);
resultItem.put("statusMessage", "Gateway Time-out");
resultItem.put("headers", makeDefaultHeaders());
resultItem.put("body", "");
} else {
resultItem.put("uri", uri);
resultItem.put("statusCode", response.statusCode());
resultItem.put("statusMessage", response.statusMessage());
resultItem.put("headers", convertHeaders(response.headers()));
resultItem.put("body", response.bodyAsString());
}

/**
* Single Request
*/
else {
ProxyResponse proxyResponse = new ProxyResponse();
if (response == null) {
proxyResponse.setStatusCode(504);
proxyResponse.setStatusMessage("Gateway Time-out");
proxyResponse.setHeaders(makeDefaultHeaders());
proxyResponse.setBody(null);
} else {
proxyResponse.setStatusCode(response.statusCode());
proxyResponse.setStatusMessage(response.statusMessage());
proxyResponse.setHeaders(response.headers());
proxyResponse.setBody(response.body());
}
consumer.accept(proxyResponse);
result.add(resultItem);

// END
if (processingCount.decrementAndGet() == 0) {
Buffer proxyBody = Buffer.buffer(new GsonBuilder().create().toJson(result));
ProxyHttpResponse proxyHttpResponse = new ProxyHttpResponse();
proxyHttpResponse.setStatusCode(200);
proxyHttpResponse.setStatusMessage("OK");
proxyHttpResponse.setHeaders(makeProxyResponseHeaders());
proxyHttpResponse.setBody(proxyBody);
consumer.accept(proxyHttpResponse);
}
}
});
Expand Down Expand Up @@ -179,21 +153,11 @@ private MultiMap makeProxyResponseHeaders() {
private ArrayList<String> getTargetURI(String originPath) {
ArrayList<String> result = new ArrayList<>();
ArrayList<String> uriList = new ArrayList<>();
mProxyInfo.getTargets().forEach(targetBaseUri -> {
mProxyHttpInfo.getTargets().forEach(targetBaseUri -> {
String uri = targetBaseUri + "/" + originPath;
uriList.add(uri);
});
if (mProxyInfo.getType().equalsIgnoreCase(ProxyConfig.ChannelType.ROUND_ROBIN)) {
String uri = uriList.get(mRoundRobinIndex);
mRoundRobinIndex = (mRoundRobinIndex + 1) % mProxyInfo.getTargets().size();
result.add(uri);
} else if (mProxyInfo.getType().equalsIgnoreCase(ProxyConfig.ChannelType.RANDOM)) {
int index = (int) (System.nanoTime() % mProxyInfo.getTargets().size());
mLogger.trace("index = " + index);
result.add(mProxyInfo.getTargets().get(index));
} else if (mProxyInfo.getType().equalsIgnoreCase(ProxyConfig.ChannelType.ALL)) {
result.addAll(uriList);
}
result.addAll(uriList);
return result;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpMethod;
import org.code13k.zeroproxy.app.Env;
import org.code13k.zeroproxy.config.ProxyConfig;
import org.code13k.zeroproxy.model.ProxyResponse;
import org.code13k.zeroproxy.model.config.proxy.ProxyInfo;
import org.code13k.zeroproxy.config.ProxyHttpConfig;
import org.code13k.zeroproxy.model.ProxyHttpResponse;
import org.code13k.zeroproxy.model.config.proxy.ProxyHttpInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -50,7 +50,7 @@ synchronized public void init() {

// Data
mData = new ArrayList<>();
ArrayList<ProxyInfo> channelList = ProxyConfig.getInstance().getChannelList();
ArrayList<ProxyHttpInfo> channelList = ProxyHttpConfig.getInstance().getChannelList();
channelList.forEach(channel -> {
ProxyHttpClient client = new ProxyHttpClient(channel, eventLoopPoolSize);
mData.add(client);
Expand All @@ -63,13 +63,13 @@ synchronized public void init() {
/**
* Proxy
*/
public void proxy(int channelIndex, String originPath, HttpMethod originMethod, MultiMap originHeaders, Buffer originBody, Consumer<ProxyResponse> consumer) {
public void proxy(int channelIndex, String originPath, HttpMethod originMethod, MultiMap originHeaders, Buffer originBody, Consumer<ProxyHttpResponse> consumer) {
ProxyHttpClient client = mData.get(channelIndex);
client.proxy(originPath, originMethod, originHeaders, originBody, new Consumer<ProxyResponse>() {
client.proxy(originPath, originMethod, originHeaders, originBody, new Consumer<ProxyHttpResponse>() {
@Override
public void accept(ProxyResponse proxyResponse) {
public void accept(ProxyHttpResponse proxyHttpResponse) {
mLogger.trace("Proxy : OK");
consumer.accept(proxyResponse);
consumer.accept(proxyHttpResponse);
mProcessedCount++;
}
});
Expand Down
Loading

0 comments on commit 6fb3617

Please sign in to comment.