Skip to content

Commit

Permalink
feat: expose host and port on mobileproxy (#107)
Browse files Browse the repository at this point in the history
* Expose host and port on mobileproxy

* Update README to use new functions
  • Loading branch information
fortuna authored Oct 17, 2023
1 parent a19d8ee commit 7bc0cae
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 24 deletions.
52 changes: 33 additions & 19 deletions x/mobileproxy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,17 @@ The header file below is an example of the Objective-C interface that Go Mobile
- (nonnull instancetype)initWithRef:(_Nonnull id)ref;
- (nonnull instancetype)init;
/**
* Address returns the actual IP and port the server is bound to.
* Address returns the IP and port the server is bound to.
*/
- (NSString* _Nonnull)address;
/**
* Host returns the IP the server is bound to.
*/
- (NSString* _Nonnull)host;
/**
* Port returns the port the server is bound to.
*/
- (long)port;
/**
* Stop gracefully stops the proxy service, waiting for at most timeout seconds before forcefully closing it.
The function takes a timeoutSeconds number instead of a [time.Duration] so it's compatible with Go Mobile.
Expand Down Expand Up @@ -89,20 +97,20 @@ The files below are examples of the Java interface that Go Mobile generates.
```java
// Code generated by gobind. DO NOT EDIT.

// Java class mobileproxy.mobileproxy is a proxy for talking to a Go program.
// Java class mobileproxy.Mobileproxy is a proxy for talking to a Go program.
//
// autogenerated by gobind -lang=java github.com/Jigsaw-Code/outline-sdk/x/mobileproxy
package mobileproxy;

import go.Seq;

public abstract class mobileproxy {
public abstract class Mobileproxy {
static {
Seq.touch(); // for loading the native library
_init();
}

private mobileproxy() {} // uninstantiable
private Mobileproxy() {} // uninstantiable

// touch is called from other bound packages to initialize this package
public static void touch() {}
Expand All @@ -113,11 +121,10 @@ public abstract class mobileproxy {

/**
* RunProxy runs a local web proxy that listens on localAddress, and uses the transportConfig to
create the [transport.StreamDialer] to use to connect to the destination from the proxy requests.
create a [transport.StreamDialer] that is used to connect to the requested destination.
*/
public static native Proxy runProxy(String localAddress, String transportConfig) throws Exception;
}

```

`Proxy.java`:
Expand All @@ -136,7 +143,7 @@ import go.Seq;
* Proxy enables you to get the actual address bound by the server and stop the service when no longer needed.
*/
public final class Proxy implements Seq.Proxy {
static { mobileproxy.touch(); }
static { Mobileproxy.touch(); }

private final int refnum;

Expand All @@ -152,11 +159,20 @@ public final class Proxy implements Seq.Proxy {
private static native int __New();

/**
* Address returns the actual IP and port the server is bound to.
* Address returns the IP and port the server is bound to.
*/
public native String address();
/**
* Stops gracefully stops the proxy service, waiting for at most timeout seconds before forcefully closing it.
* Host returns the IP the server is bound to.
*/
public native String host();
/**
* Port returns the port the server is bound to.
*/
public native long port();
/**
* Stop gracefully stops the proxy service, waiting for at most timeout seconds before forcefully closing it.
The function takes a timeoutSeconds number instead of a [time.Duration] so it's compatible with Go Mobile.
*/
public native void stop(long timeoutSeconds);
@Override public boolean equals(Object o) {
Expand Down Expand Up @@ -193,9 +209,7 @@ On Android, you can have the following Kotlin code:
```kotlin
// Use port zero to let the system pick an open port for you.
val proxy = mobileproxy.runProxy("localhost:0", "split:3")
// Find the address the local proxy is bound to.
val proxyAddress = proxy.address()
// Configure your networking library with proxyAddress.
// Configure your networking library using proxy.host() and proxy.port() or proxy.address().
// ...
// Stop running the proxy.
proxy.stop()
Expand All @@ -215,7 +229,7 @@ Dart example:
```dart
HttpClient client = HttpClient();
client.findProxy = (Uri uri) {
return "PROXY localhost:1234";
return "PROXY " + proxy.address();
};
```

Expand All @@ -227,18 +241,18 @@ Set the proxy with [`OkHttpClient.Builder.proxy`](https://square.github.io/okhtt
Kotlin example:

```kotlin
val proxy = Proxy(Proxy.Type.HTTP, InetSocketAddress("localhost", 1234))
val client = OkHttpClient.Builder().proxy(proxy).build()
val proxyConfig = Proxy(Proxy.Type.HTTP, InetSocketAddress(proxy.host(), proxy.port()))
val client = OkHttpClient.Builder().proxy(proxyConfig).build()
```

### JVM (Java, Kotlin)

In the JVM, you can configure the proxy to use with [system properties](https://docs.oracle.com/javase/8/docs/technotes/guides/net/proxies.html):
```kotlin
System.setProperty("http.proxyHost", "localhost")
System.setProperty("http.proxyPort", "1234")
System.setProperty("https.proxyHost", "localhost")
System.setProperty("https.proxyPort", "1234")
System.setProperty("http.proxyHost", proxy.host())
System.setProperty("http.proxyPort", String.valueOf(proxy.port()))
System.setProperty("https.proxyHost", proxy.host())
System.setProperty("https.proxyPort", String.valueOf(proxy.port()))
```

Note that this may not fully work on Android, since it will only affect the JVM, not native code. You should also make sure you set this early in your code.
Expand Down
30 changes: 25 additions & 5 deletions x/mobileproxy/mobileproxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"log"
"net"
"net/http"
"strconv"
"time"

"github.com/Jigsaw-Code/outline-sdk/x/config"
Expand All @@ -32,13 +33,24 @@ import (

// Proxy enables you to get the actual address bound by the server and stop the service when no longer needed.
type Proxy struct {
address string
server *http.Server
host string
port int
server *http.Server
}

// Address returns the actual IP and port the server is bound to.
// Address returns the IP and port the server is bound to.
func (p *Proxy) Address() string {
return p.address
return net.JoinHostPort(p.host, strconv.Itoa(p.port))
}

// Host returns the IP the server is bound to.
func (p *Proxy) Host() string {
return p.host
}

// Port returns the port the server is bound to.
func (p *Proxy) Port() int {
return p.port
}

// Stop gracefully stops the proxy service, waiting for at most timeout seconds before forcefully closing it.
Expand Down Expand Up @@ -68,5 +80,13 @@ func RunProxy(localAddress string, transportConfig string) (*Proxy, error) {
server := &http.Server{Handler: httpproxy.NewConnectHandler(dialer)}
go server.Serve(listener)

return &Proxy{address: listener.Addr().String(), server: server}, nil
host, portStr, err := net.SplitHostPort(listener.Addr().String())
if err != nil {
return nil, fmt.Errorf("could not parse proxy address '%v': %v", listener.Addr().String(), err)
}
port, err := strconv.Atoi(portStr)
if err != nil {
return nil, fmt.Errorf("could not parse proxy port '%v': %v", portStr, err)
}
return &Proxy{host: host, port: port, server: server}, nil
}

0 comments on commit 7bc0cae

Please sign in to comment.