Skip to content
This repository has been archived by the owner on Jul 28, 2024. It is now read-only.

Commit

Permalink
example: adds http_body_chunk (#421)
Browse files Browse the repository at this point in the history
  • Loading branch information
M4tteoP authored Jan 2, 2024
1 parent 9c1dd2b commit db22d5a
Show file tree
Hide file tree
Showing 6 changed files with 397 additions and 0 deletions.
28 changes: 28 additions & 0 deletions examples/http_body_chunk/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
## http_body_chunk

This example demonstrates how to perform operations on a request body, chunk by chunk.

Reading the received body chunk by chunk, it looks for the string `pattern` inside the body. If it finds it, a 403 response is returned providing the number of the chunk where the pattern was found. Logs are printed every time a chunk is received providing also the size of the read chunk.

Build and run the example:
```bash
$ make build.example name=http_body_chunk
$ make run name=http_body_chunk
```

Perform a request with a body containing the string `pattern`:
```bash
$ head -c 700000 /dev/urandom | base64 > /tmp/file.txt && echo "pattern" >> /tmp/file.txt && curl 'localhost:18000/anything' -d @/tmp/file.txt
pattern found in chunk: 2
```

Generated logs:
```
wasm log: OnHttpRequestBody called. BodySize: 114532, totalRequestBodyReadSize: 0, endOfStream: false
wasm log: read chunk size: 114532
wasm log: OnHttpRequestBody called. BodySize: 114532, totalRequestBodyReadSize: 114532, endOfStream: false
wasm log: OnHttpRequestBody called. BodySize: 933343, totalRequestBodyReadSize: 114532, endOfStream: true
wasm log: read chunk size: 818811
wasm log: pattern found in chunk: 2
wasm log: local 403 response sent
```
66 changes: 66 additions & 0 deletions examples/http_body_chunk/envoy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
static_resources:
listeners:
- name: main
address:
socket_address:
address: 0.0.0.0
port_value: 18000
filter_chains:
- filters:
- name: envoy.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
codec_type: auto
route_config:
name: admin
virtual_hosts:
- name: admin
domains:
- "*"
routes:
- match:
prefix: "/"
route:
cluster: admin
http_filters:
- name: envoy.filters.http.wasm
typed_config:
"@type": type.googleapis.com/udpa.type.v1.TypedStruct
type_url: type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm
value:
config:
configuration:
"@type": type.googleapis.com/google.protobuf.StringValue
value: "body-set"
vm_config:
runtime: "envoy.wasm.runtime.v8"
code:
local:
filename: "./examples/http_body_chunk/main.wasm"
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

clusters:
- name: admin
connect_timeout: 5000s
type: strict_dns
lb_policy: round_robin
load_assignment:
cluster_name: admin
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 0.0.0.0
port_value: 8001


admin:
access_log_path: "/dev/null"
address:
socket_address:
address: 0.0.0.0
port_value: 8001
17 changes: 17 additions & 0 deletions examples/http_body_chunk/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module github.com/tetratelabs/proxy-wasm-go-sdk/examples/http_body_chunk

go 1.19

replace github.com/tetratelabs/proxy-wasm-go-sdk => ../..

require (
github.com/stretchr/testify v1.8.2
github.com/tetratelabs/proxy-wasm-go-sdk v0.0.0-00010101000000-000000000000
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/tetratelabs/wazero v1.0.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
19 changes: 19 additions & 0 deletions examples/http_body_chunk/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/tetratelabs/wazero v1.0.1 h1:xyWBoGyMjYekG3mEQ/W7xm9E05S89kJ/at696d/9yuc=
github.com/tetratelabs/wazero v1.0.1/go.mod h1:wYx2gNRg8/WihJfSDxA1TIL8H+GkfLYm+bIfbblu9VQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
108 changes: 108 additions & 0 deletions examples/http_body_chunk/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Copyright 2020-2021 Tetrate
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
"fmt"
"strings"

"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm"
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm/types"
)

func main() {
proxywasm.SetVMContext(&vmContext{})
}

type vmContext struct {
// Embed the default VM context here,
// so that we don't need to reimplement all the methods.
types.DefaultVMContext
}

// Override types.DefaultVMContext.
func (*vmContext) NewPluginContext(contextID uint32) types.PluginContext {
return &pluginContext{}
}

type pluginContext struct {
// Embed the default plugin context here,
// so that we don't need to reimplement all the methods.
types.DefaultPluginContext
}

// Override types.DefaultPluginContext.
func (ctx *pluginContext) NewHttpContext(contextID uint32) types.HttpContext {
return &setBodyContext{}
}

// Override types.DefaultPluginContext.
func (ctx *pluginContext) OnPluginStart(pluginConfigurationSize int) types.OnPluginStartStatus {
return types.OnPluginStartStatusOK
}

type setBodyContext struct {
// Embed the default root http context here,
// so that we don't need to reimplement all the methods.
types.DefaultHttpContext
totalRequestBodyReadSize int
receivedChunks int
}

// Override types.DefaultHttpContext.
func (ctx *setBodyContext) OnHttpRequestBody(bodySize int, endOfStream bool) types.Action {
proxywasm.LogInfof("OnHttpRequestBody called. BodySize: %d, totalRequestBodyReadSize: %d, endOfStream: %v", bodySize, ctx.totalRequestBodyReadSize, endOfStream)

// If some data has been received, we read it.
// Reading the body chunk by chunk, bodySize is the size of the current chunk, not the total size of the body.
chunkSize := bodySize - ctx.totalRequestBodyReadSize
if chunkSize > 0 {
ctx.receivedChunks++
chunk, err := proxywasm.GetHttpRequestBody(ctx.totalRequestBodyReadSize, chunkSize)
if err != nil {
proxywasm.LogCriticalf("failed to get request body: %v", err)
return types.ActionContinue
}
proxywasm.LogInfof("read chunk size: %d", len(chunk))
if len(chunk) != chunkSize {
proxywasm.LogErrorf("read data does not match the expected size: %d != %d", len(chunk), chunkSize)
}
ctx.totalRequestBodyReadSize += len(chunk)
if strings.Contains(string(chunk), "pattern") {
patternFound := fmt.Sprintf("pattern found in chunk: %d", ctx.receivedChunks)
proxywasm.LogInfo(patternFound)
if err := proxywasm.SendHttpResponse(403, [][2]string{
{"powered-by", "proxy-wasm-go-sdk"},
}, []byte(patternFound), -1); err != nil {
proxywasm.LogCriticalf("failed to send local response: %v", err)
proxywasm.ResumeHttpRequest()
} else {
proxywasm.LogInfo("local 403 response sent")
}
return types.ActionPause
}
}

if !endOfStream {
// Wait until we see the entire body before sending the request upstream.
return types.ActionPause
}
// When endOfStream is true, we have received the entire body. We expect the total size is equal to the sum of the sizes of the chunks.
if ctx.totalRequestBodyReadSize != bodySize {
proxywasm.LogErrorf("read data does not match the expected total size: %d != %d", ctx.totalRequestBodyReadSize, bodySize)
}
proxywasm.LogInfof("pattern not found")
return types.ActionContinue
}
Loading

0 comments on commit db22d5a

Please sign in to comment.