Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package io.roastedroot.proxywasm.internal;

import java.io.IOException;
import java.io.InputStream;
import java.util.function.Supplier;

/**
* Holds the HTTP request body, loading it from a stream when first accessed.
*/
public class HttpRequestBody {

private byte[] body;
private boolean loaded = false;
private final Supplier<InputStream> streamSupplier;

public HttpRequestBody(Supplier<InputStream> streamSupplier) {
this.streamSupplier = streamSupplier;
}

public byte[] get() {
if (!loaded) {
try {
body = streamSupplier.get().readAllBytes();
} catch (IOException e) {
throw new RuntimeException("Failed to read request body", e);
}
loaded = true;
}
return body;
}

/**
* Returns true if the request body has been loaded from the stream.
*/
public boolean isLoaded() {
return loaded;
}

/**
* Sets the request body directly, marking it as loaded.
* This is used when the body is modified by WASM plugins.
*/
public void setBody(byte[] body) {
this.body = body;
this.loaded = true;
}

/**
* Returns the request body if it has been loaded, null otherwise.
* This allows checking if the body was accessed without triggering a load.
*/
public byte[] getBodyIfLoaded() {
return loaded ? body : null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package io.roastedroot.proxywasm.internal;

import java.util.function.Supplier;

/**
* Holds the HTTP response body, loading it from a supplier when first accessed.
* Unlike request bodies which come from streams, response bodies can be provided
* directly as byte arrays or from suppliers.
*/
public class HttpResponseBody {

private byte[] body;
private boolean loaded = false;
private final Supplier<byte[]> bodySupplier;

public HttpResponseBody(Supplier<byte[]> bodySupplier) {
this.bodySupplier = bodySupplier;
}

/**
* Creates an HttpResponseBody with a fixed byte array (no lazy loading needed).
*/
public HttpResponseBody(byte[] body) {
this.body = body;
this.loaded = true;
this.bodySupplier = null;
}

public byte[] get() {
if (!loaded) {
if (bodySupplier != null) {
body = bodySupplier.get();
} else {
body = new byte[0];
}
loaded = true;
}
return body;
}

/**
* Returns true if the response body has been loaded.
*/
public boolean isLoaded() {
return loaded;
}

/**
* Sets the response body directly, marking it as loaded.
* This is used when the body is modified by WASM plugins.
*/
public void setBody(byte[] body) {
this.body = body;
this.loaded = true;
}

/**
* Returns the response body if it has been loaded, null otherwise.
* This allows checking if the body was accessed without triggering a load.
*/
public byte[] getBodyIfLoaded() {
return loaded ? body : null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,89 @@ public class PluginHttpContext {
private final long startedAt = System.currentTimeMillis();

final HashMap<List<String>, byte[]> properties = new HashMap<>();
private byte[] httpRequestBody = new byte[0];
private HttpRequestBody httpRequestBodyState;
private HttpResponseBody httpResponseBodyState;

// Other body buffers and state fields (not lazy)
private byte[] grpcReceiveBuffer = new byte[0];
private byte[] upstreamData = new byte[0];
private byte[] downStreamData = new byte[0];
private byte[] httpResponseBody = new byte[0];
private SendResponse sendResponse;
private Action action;
private CountDownLatch resumeLatch;

PluginHttpContext(Plugin plugin, HttpRequestAdaptor requestAdaptor) {
public PluginHttpContext(Plugin plugin, HttpRequestAdaptor requestAdaptor) {
this.plugin = plugin;
this.requestAdaptor = requestAdaptor;
this.context = plugin.wasm.createHttpContext(new HandlerImpl());
}

/**
* Sets the lazy request body supplier.
*/
public void setHttpRequestBodyState(HttpRequestBody supplier) {
this.httpRequestBodyState = supplier;
}

/**
* Gets the lazy request body supplier.
*/
public HttpRequestBody getHttpRequestBodyState() {
return httpRequestBodyState;
}

/**
* Gets the HTTP request body, triggering lazy loading if needed.
*/
public byte[] getHttpRequestBody() {
if (httpRequestBodyState != null) {
return httpRequestBodyState.get();
}
return new byte[0];
}

/**
* Sets the HTTP request body, updating the supplier if present.
*/
public void setHttpRequestBody(byte[] body) {
if (httpRequestBodyState != null && body != null) {
httpRequestBodyState.setBody(body);
}
}

/**
* Sets the HTTP response body state.
*/
public void setHttpResponseBodyState(HttpResponseBody responseBody) {
this.httpResponseBodyState = responseBody;
}

/**
* Gets the HTTP response body state.
*/
public HttpResponseBody getHttpResponseBodyState() {
return httpResponseBodyState;
}

/**
* Gets the HTTP response body, triggering lazy loading if needed.
*/
public byte[] getHttpResponseBody() {
if (httpResponseBodyState != null) {
return httpResponseBodyState.get();
}
return new byte[0];
}

/**
* Sets the HTTP response body, updating the state if present.
*/
public void setHttpResponseBody(byte[] httpResponseBody) {
if (httpResponseBodyState != null && httpResponseBody != null) {
httpResponseBodyState.setBody(httpResponseBody);
}
}

public Plugin plugin() {
return plugin;
}
Expand Down Expand Up @@ -68,22 +136,6 @@ public void maybePause() {
}
}

public byte[] getHttpRequestBody() {
return httpRequestBody;
}

public void setHttpRequestBody(byte[] httpRequestBody) {
this.httpRequestBody = httpRequestBody;
}

public byte[] getHttpResponseBody() {
return httpResponseBody;
}

public void setHttpResponseBody(byte[] httpResponseBody) {
this.httpResponseBody = httpResponseBody;
}

public byte[] getGrpcReceiveBuffer() {
return grpcReceiveBuffer;
}
Expand Down Expand Up @@ -156,17 +208,21 @@ public ProxyMap getGrpcReceiveTrailerMetaData() {

@Override
public byte[] getHttpRequestBody() {
return httpRequestBody;
return PluginHttpContext.this
.getHttpRequestBody(); // Delegate to outer class for lazy loading
}

@Override
public WasmResult setHttpRequestBody(byte[] body) {
httpRequestBody = body;
PluginHttpContext.this.setHttpRequestBody(body); // Delegate to outer class
return WasmResult.OK;
}

public void appendHttpRequestBody(byte[] body) {
httpRequestBody = Helpers.append(httpRequestBody, body);
byte[] currentBody =
PluginHttpContext.this
.getHttpRequestBody(); // This will trigger lazy loading if needed
PluginHttpContext.this.setHttpRequestBody(Helpers.append(currentBody, body));
}

@Override
Expand Down Expand Up @@ -204,17 +260,18 @@ public WasmResult setDownStreamData(byte[] data) {

@Override
public byte[] getHttpResponseBody() {
return httpResponseBody;
return PluginHttpContext.this.getHttpResponseBody();
}

@Override
public WasmResult setHttpResponseBody(byte[] body) {
httpResponseBody = body;
PluginHttpContext.this.setHttpResponseBody(body);
return WasmResult.OK;
}

public void appendHttpResponseBody(byte[] body) {
httpResponseBody = Helpers.append(httpResponseBody, body);
byte[] currentBody = PluginHttpContext.this.getHttpResponseBody();
PluginHttpContext.this.setHttpResponseBody(Helpers.append(currentBody, body));
}

// //////////////////////////////////////////////////////////////////////
Expand Down
Loading