Skip to content

Commit 55b4df9

Browse files
committed
feat: implemented network proxying.
Added network example and tests. Signed-off-by: Hiram Chirino <hiram@hiramchirino.com>
1 parent 3f36a69 commit 55b4df9

File tree

12 files changed

+357
-4
lines changed

12 files changed

+357
-4
lines changed

src/main/java/io/roastedroot/proxywasm/impl/Exports.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,10 @@ public int proxyOnNewConnection(int arg0) {
6868
return (int) result;
6969
}
7070

71-
public int proxyOnDownstreamData(int arg0, int arg1, int arg2) {
72-
long result = exports.function("proxy_on_downstream_data").apply(arg0, arg1, arg2)[0];
71+
public int proxyOnDownstreamData(int contextId, int dataSize, int endOfStream) {
72+
long result =
73+
exports.function("proxy_on_downstream_data")
74+
.apply(contextId, dataSize, endOfStream)[0];
7375
return (int) result;
7476
}
7577

src/main/java/io/roastedroot/proxywasm/v1/HttpContext.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
public class HttpContext extends Context {
66

77
private final Handler handler;
8-
Action action;
98

109
HttpContext(ProxyWasm proxyWasm, Handler handler) {
1110
super(proxyWasm);

src/main/java/io/roastedroot/proxywasm/v1/MapType.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
/**
44
* Represents the type of map in proxy WASM.
5-
* Converted from Go's MapType type.
65
*/
76
public enum MapType {
87
HTTP_REQUEST_HEADERS(0),
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package io.roastedroot.proxywasm.v1;
2+
3+
import static io.roastedroot.proxywasm.v1.Helpers.len;
4+
5+
public class NetworkContext extends Context {
6+
7+
private final Handler handler;
8+
9+
NetworkContext(ProxyWasm proxyWasm, Handler handler) {
10+
super(proxyWasm);
11+
this.handler = handler;
12+
}
13+
14+
Handler handler() {
15+
return handler;
16+
}
17+
18+
public Action callOnNewConnection() {
19+
int result = proxyWasm.exports().proxyOnNewConnection(id);
20+
Action action = Action.fromInt(result);
21+
handler.setAction(StreamType.DOWNSTREAM, action);
22+
return action;
23+
}
24+
25+
public Action callOnDownstreamData(boolean endOfStream) {
26+
var data = handler.getDownStreamData();
27+
var result = proxyWasm.exports().proxyOnDownstreamData(id, len(data), endOfStream ? 1 : 0);
28+
Action action = Action.fromInt(result);
29+
handler.setAction(StreamType.DOWNSTREAM, action);
30+
return action;
31+
}
32+
33+
public Action callOnUpstreamData(boolean endOfStream) {
34+
var data = handler.getUpstreamData();
35+
var result = proxyWasm.exports().proxyOnUpstreamData(id, len(data), endOfStream ? 1 : 0);
36+
Action action = Action.fromInt(result);
37+
handler.setAction(StreamType.UPSTREAM, action);
38+
return action;
39+
}
40+
41+
public void callOnDownstreamConnectionClose(PeerType type) {
42+
proxyWasm.exports().proxyOnDownstreamConnectionClose(id, type.getValue());
43+
}
44+
45+
public void callOnDownstreamConnectionClose() {
46+
// peerType will be removed in the next ABI
47+
callOnDownstreamConnectionClose(PeerType.LOCAL);
48+
}
49+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package io.roastedroot.proxywasm.v1;
2+
3+
/**
4+
* Represents the type of peer in proxy WASM.
5+
*/
6+
public enum PeerType {
7+
UNKNOWN(0),
8+
LOCAL(1),
9+
REMOTE(2);
10+
11+
private final int value;
12+
13+
/**
14+
* Constructor for PeerType enum.
15+
*
16+
* @param value The integer value of the peer type
17+
*/
18+
PeerType(int value) {
19+
this.value = value;
20+
}
21+
22+
/**
23+
* Get the integer value of this peer type.
24+
*
25+
* @return The integer value
26+
*/
27+
public int getValue() {
28+
return value;
29+
}
30+
31+
/**
32+
* Convert an integer value to a PeerType.
33+
*
34+
* @param value The integer value to convert
35+
* @return The corresponding PeerType or null if the value doesn't match any PeerType
36+
*/
37+
public static PeerType fromInt(int value) {
38+
for (PeerType type : values()) {
39+
if (type.value == value) {
40+
return type;
41+
}
42+
}
43+
return null;
44+
}
45+
}

src/main/java/io/roastedroot/proxywasm/v1/ProxyWasm.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,12 @@ public HttpContext createHttpContext(Handler handler) {
214214
return context;
215215
}
216216

217+
public NetworkContext createNetworkContext(Handler handler) {
218+
NetworkContext context = new NetworkContext(this, handler);
219+
registerContext(context, this.pluginContext.id());
220+
return context;
221+
}
222+
217223
/**
218224
* Delivers a tick event to the plugin.
219225
* <p>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
## Attribution
2+
3+
This example originally came from:
4+
https://github.com/proxy-wasm/proxy-wasm-go-sdk/blob/ab4161dcf9246a828008b539a82a1556cf0f2e24/examples/network
5+
```
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module github.com/proxy-wasm/proxy-wasm-go-sdk/examples/network
2+
3+
go 1.24
4+
5+
require github.com/proxy-wasm/proxy-wasm-go-sdk v0.0.0-20250212164326-ab4161dcf924
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
4+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
5+
github.com/proxy-wasm/proxy-wasm-go-sdk v0.0.0-20250212164326-ab4161dcf924 h1:wTcK6gcyTKJMeDka69AMjZYvisdI8CBXzTEfZ+2pOxI=
6+
github.com/proxy-wasm/proxy-wasm-go-sdk v0.0.0-20250212164326-ab4161dcf924/go.mod h1:9mBRvh8I6Td6sg3CwEY+zGFE4DKaIoieCaca1kQnDBE=
7+
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
8+
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
9+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
10+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// Copyright 2020-2024 Tetrate
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package main
16+
17+
import (
18+
"github.com/proxy-wasm/proxy-wasm-go-sdk/proxywasm"
19+
"github.com/proxy-wasm/proxy-wasm-go-sdk/proxywasm/types"
20+
)
21+
22+
func main() {}
23+
func init() {
24+
proxywasm.SetVMContext(&vmContext{})
25+
}
26+
27+
// vmContext implements types.VMContext.
28+
type vmContext struct {
29+
// Embed the default VM context here,
30+
// so that we don't need to reimplement all the methods.
31+
types.DefaultVMContext
32+
}
33+
34+
// NewPluginContext implements types.VMContext.
35+
func (*vmContext) NewPluginContext(contextID uint32) types.PluginContext {
36+
return &pluginContext{counter: proxywasm.DefineCounterMetric("proxy_wasm_go.connection_counter")}
37+
}
38+
39+
// pluginContext implements types.PluginContext.
40+
type pluginContext struct {
41+
// Embed the default plugin context here,
42+
// so that we don't need to reimplement all the methods.
43+
types.DefaultPluginContext
44+
counter proxywasm.MetricCounter
45+
}
46+
47+
// NewTcpContext implements types.PluginContext.
48+
func (ctx *pluginContext) NewTcpContext(contextID uint32) types.TcpContext {
49+
return &networkContext{counter: ctx.counter}
50+
}
51+
52+
// networkContext implements types.TcpContext.
53+
type networkContext struct {
54+
// Embed the default tcp context here,
55+
// so that we don't need to reimplement all the methods.
56+
types.DefaultTcpContext
57+
counter proxywasm.MetricCounter
58+
}
59+
60+
// OnNewConnection implements types.TcpContext.
61+
func (ctx *networkContext) OnNewConnection() types.Action {
62+
proxywasm.LogInfo("new connection!")
63+
return types.ActionContinue
64+
}
65+
66+
// OnDownstreamData implements types.TcpContext.
67+
func (ctx *networkContext) OnDownstreamData(dataSize int, endOfStream bool) types.Action {
68+
if dataSize == 0 {
69+
return types.ActionContinue
70+
}
71+
72+
data, err := proxywasm.GetDownstreamData(0, dataSize)
73+
if err != nil && err != types.ErrorStatusNotFound {
74+
proxywasm.LogCriticalf("failed to get downstream data: %v", err)
75+
return types.ActionContinue
76+
}
77+
78+
proxywasm.LogInfof(">>>>>> downstream data received >>>>>>\n%s", string(data))
79+
return types.ActionContinue
80+
}
81+
82+
// OnDownstreamClose implements types.TcpContext.
83+
func (ctx *networkContext) OnDownstreamClose(types.PeerType) {
84+
proxywasm.LogInfo("downstream connection close!")
85+
}
86+
87+
// OnUpstreamData implements types.TcpContext.
88+
func (ctx *networkContext) OnUpstreamData(dataSize int, endOfStream bool) types.Action {
89+
if dataSize == 0 {
90+
return types.ActionContinue
91+
}
92+
93+
// Get the remote ip address of the upstream cluster.
94+
address, err := proxywasm.GetProperty([]string{"upstream", "address"})
95+
if err != nil {
96+
proxywasm.LogWarnf("failed to get upstream remote address: %v", err)
97+
}
98+
99+
proxywasm.LogInfof("remote address: %s", string(address))
100+
101+
// Get the upstream cluster's metadata in the cluster configuration.
102+
metadataKeyValues, err := proxywasm.GetPropertyMap([]string{"cluster_metadata", "filter_metadata", "location"})
103+
if err != nil {
104+
proxywasm.LogWarnf("failed to get upstream location metadata: %v", err)
105+
}
106+
107+
for _, metadata := range metadataKeyValues {
108+
key, value := metadata[0], metadata[1]
109+
proxywasm.LogInfof("upstream cluster metadata location[%s]=%s", string(key), string(value))
110+
}
111+
112+
data, err := proxywasm.GetUpstreamData(0, dataSize)
113+
if err != nil && err != types.ErrorStatusNotFound {
114+
proxywasm.LogCritical(err.Error())
115+
}
116+
117+
proxywasm.LogInfof("<<<<<< upstream data received <<<<<<\n%s", string(data))
118+
return types.ActionContinue
119+
}
120+
121+
// OnStreamDone implements types.TcpContext.
122+
func (ctx *networkContext) OnStreamDone() {
123+
ctx.counter.Increment(1)
124+
proxywasm.LogInfo("connection complete!")
125+
}

0 commit comments

Comments
 (0)