pulling from dev

This commit is contained in:
wiaamm 2025-01-05 12:01:24 +02:00
parent cfeae10dcf
commit f6d7d09bae
26 changed files with 657 additions and 426 deletions

2
attachments/envoy/build_template Normal file → Executable file
View File

@ -10,4 +10,4 @@ ENVOY_ATTACHMENT_DIR="@ENVOY_ATTACHMENT_DIR@"
cd $ENVOY_ATTACHMENT_DIR cd $ENVOY_ATTACHMENT_DIR
# Run the go build command # Run the go build command
CC=gcc CGO_CFLAGS="-I@ATTACHMENTS_INCLUDE_DIR@ -I@NANO_ATTACHMENT_INCLUDE_DIR@" go build -o ${ENVOY_ATTACHMENT_DIR}/libenvoy_attachment.so -buildmode=c-shared -ldflags="-extldflags '-L${SHMEM_LIBRARY_DIR} -L${NANO_ATTACHMENT_LIBRARY_DIR} -L${NANO_ATTACHMENT_UTIL_LIBRARY_DIR} ${LIBRARIES}'" CGO_CFLAGS="-I@ATTACHMENTS_INCLUDE_DIR@ -I@NANO_ATTACHMENT_INCLUDE_DIR@" go build -o ${ENVOY_ATTACHMENT_DIR}/libenvoy_attachment.so -buildmode=c-shared -ldflags="-extldflags '-L${SHMEM_LIBRARY_DIR} -L${NANO_ATTACHMENT_LIBRARY_DIR} -L${NANO_ATTACHMENT_UTIL_LIBRARY_DIR} ${LIBRARIES}'"

View File

@ -3,7 +3,6 @@ package main
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil"
"net/http" "net/http"
"runtime" "runtime"
"strconv" "strconv"
@ -35,53 +34,58 @@ unsigned long get_thread_id() {
import "C" import "C"
const Name = "cp_nano_filter" const Name = "cp_nano_filter"
const admin_api_server_info = "http://127.0.0.1:%s/server_info"
const Admin_api = "http://127.0.0.1:%s/server_info" const keep_alive_interval = 10 * time.Second
var filter_id atomic.Int64 var filter_id atomic.Int64
type nano_attachment C.struct_NanoAttachment
var attachments_map map[int]*nano_attachment = nil var attachments_map map[int]*nano_attachment = nil
var thread_to_attachment_mapping map[int]int = nil var thread_to_attachment_mapping map[int]int = nil
var attachment_to_thread_mapping map[int]int = nil var attachment_to_thread_mapping map[int]int = nil
var attachment_to_filter_request_structs map[int]*filterRequestStructs = nil var attachment_to_filter_request_structs map[int]*filterRequestStructs = nil
var mutex sync.Mutex var mutex sync.Mutex
const keep_alive_interval = 10 * time.Second
var last_keep_alive time.Time var last_keep_alive time.Time
type nano_attachment C.struct_NanoAttachment
// EnvoyServerInfo represents the structure of the JSON response from /server_info // EnvoyServerInfo represents the structure of the JSON response from /server_info
type EnvoyServerInfo struct { type EnvoyServerInfo struct {
Concurrency int `json:"concurrency"` Concurrency int `json:"concurrency"`
} }
// getEnvoyConcurrency fetches and returns the concurrency level of Envoy from the admin API func getEnvoyConcurrency() int {
func getEnvoyConcurrency(admin_api_address string) (int, error) { concurrency_method := getEnv("CONCURRENCY_CALC", "numOfCores")
resp, err := http.Get(admin_api_address)
if err != nil {
return 0, fmt.Errorf("failed to reach Envoy admin API: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK { if concurrency_method == "numOfCores" {
return 0, fmt.Errorf("unexpected status code from Envoy admin API: %d", resp.StatusCode) api.LogWarnf("using number of CPU cores")
return runtime.NumCPU()
} }
body, err := ioutil.ReadAll(resp.Body) var conc_number string
if err != nil {
return 0, fmt.Errorf("failed to read response body: %w", err) switch concurrency_method {
case "istioCpuLimit":
conc_number = getEnv("ISTIO_CPU_LIMIT", "-1")
api.LogWarnf("using istioCpuLimit, conc_number %s", conc_number)
case "custom":
conc_number = getEnv("CONCURRENCY_NUMBER", "-1")
api.LogWarnf("using custom concurrency number, conc_number %s", conc_number)
default:
api.LogWarnf("unknown concurrency method %s, using number of CPU cores", concurrency_method)
return runtime.NumCPU()
} }
var info EnvoyServerInfo if conc_number == "-1" {
if err := json.Unmarshal(body, &info); err != nil { api.LogWarnf("concurrency number is not set as an env variable, using number of CPU cores")
return 0, fmt.Errorf("failed to parse JSON response: %w", err) return runtime.NumCPU()
} }
return info.Concurrency, nil conc_num, err := strconv.Atoi(conc_number)
if err != nil || conc_num <= 0 {
api.LogWarnf("error converting concurrency number %s, using number of CPU cores", conc_number)
return runtime.NumCPU()
}
return conc_num
} }
func configurationServer() { func configurationServer() {
@ -150,8 +154,7 @@ func configurationServer() {
func init() { func init() {
last_keep_alive = time.Time{} last_keep_alive = time.Time{}
envoyHttp.RegisterHttpFilterFactoryAndConfigParser(Name, ConfigFactory, &parser{}) envoyHttp.RegisterHttpFilterConfigFactoryAndParser(Name, ConfigFactory, &parser{})
//envoyHttp.RegisterHttpFilterConfigFactoryAndParser(Name, ConfigFactory, &parser{})
go configurationServer() go configurationServer()
} }
@ -193,37 +196,7 @@ func (p *parser) Parse(any *anypb.Any, callbacks api.ConfigCallbackHandler) (int
return conf, nil return conf, nil
} }
var num_of_workers int num_of_workers := getEnvoyConcurrency()
concurrency_method := getEnv("CONCURRENCY_CALC", "numOfCores")
if concurrency_method == "numOfCores" {
num_of_workers = runtime.NumCPU()
api.LogInfof("using number of cpu cores %d", num_of_workers)
} else if concurrency_method == "config" {
config_port := getEnv("CONFIG_PORT", "15000")
admin_api := fmt.Sprintf(Admin_api, config_port)
workers, err := getEnvoyConcurrency(admin_api)
if err != nil {
api.LogWarnf("unable to fetch concurrency from admin server, using cpu cores. err: %s", err.Error())
num_of_workers = runtime.NumCPU()
} else {
num_of_workers = workers
}
} else if concurrency_method == "custom" {
conc_number := getEnv("CONCURRENCY_NUMBER", "-1")
if conc_number == "-1" {
api.LogWarnf("concurrency number is not set as an env variable, using cpu cores")
num_of_workers = runtime.NumCPU()
} else if conc_num, err := strconv.Atoi(conc_number); err == nil && conc_num > 0 {
num_of_workers = conc_num
} else {
api.LogWarnf("error converting conc_number %s, using num of cpu cores", conc_number)
num_of_workers = runtime.NumCPU()
}
} else {
api.LogWarnf("unable to fetch concurrency from %s, using cpu cores", concurrency_method)
num_of_workers = runtime.NumCPU()
}
configStruct := &xds.TypedStruct{} configStruct := &xds.TypedStruct{}
if err := any.UnmarshalTo(configStruct); err != nil { if err := any.UnmarshalTo(configStruct); err != nil {
@ -266,87 +239,46 @@ func (p *parser) Merge(parent interface{}, child interface{}) interface{} {
return &newConfig return &newConfig
} }
// func ConfigFactory(c interface{}) api.StreamFilterFactory { func ConfigFactory(c interface{}) api.StreamFilterFactory {
// conf, ok := c.(*config)
// if !ok {
// panic("unexpected config type")
// }
// return func(callbacks api.FilterCallbackHandler) api.StreamFilter {
// worker_thread_id := int(C.get_thread_id())
// api.LogDebugf("worker_thread_id: %d", worker_thread_id)
// if _, ok := thread_to_attachment_mapping[int(worker_thread_id)]; !ok {
// api.LogDebugf("need to add new thread to the map")
// map_size := len(attachment_to_thread_mapping)
// if map_size < len(attachments_map) {
// attachment_to_thread_mapping[map_size] = worker_thread_id
// thread_to_attachment_mapping[worker_thread_id] = map_size
// api.LogDebugf("len(attachment_to_thread_mapping): %d", len(attachment_to_thread_mapping))
// api.LogDebugf("thread_to_attachment_mapping: %v", thread_to_attachment_mapping)
// api.LogDebugf("attachment_to_thread_mapping: %v", attachment_to_thread_mapping)
// } else {
// panic("unexpected thread id")
// }
// }
// worker_id := thread_to_attachment_mapping[int(worker_thread_id)]
// api.LogDebugf("worker_id: %d", worker_id)
// filter_id.Add(1)
// session_id := filter_id.Load()
// attachment_ptr := attachments_map[worker_id]
// session_data := C.InitSessionData((*C.NanoAttachment)(attachment_ptr), C.SessionID(session_id))
// return &filter{
// callbacks: callbacks,
// config: conf,
// session_id: session_id,
// cp_attachment: attachment_ptr,
// session_data: session_data,
// request_structs: attachment_to_filter_request_structs[worker_id],
// }
// }
// }
func ConfigFactory(c interface{}, callbacks api.FilterCallbackHandler) api.StreamFilter {
conf, ok := c.(*config) conf, ok := c.(*config)
if !ok { if !ok {
panic("unexpected config type") panic("unexpected config type")
} }
worker_thread_id := int(C.get_thread_id()) return func(callbacks api.FilterCallbackHandler) api.StreamFilter {
api.LogDebugf("worker_thread_id: %d", worker_thread_id) worker_thread_id := int(C.get_thread_id())
if _, ok := thread_to_attachment_mapping[int(worker_thread_id)]; !ok { api.LogDebugf("worker_thread_id: %d", worker_thread_id)
api.LogDebugf("need to add new thread to the map") if _, ok := thread_to_attachment_mapping[int(worker_thread_id)]; !ok {
map_size := len(attachment_to_thread_mapping) api.LogDebugf("need to add new thread to the map")
if map_size < len(attachments_map) { map_size := len(attachment_to_thread_mapping)
attachment_to_thread_mapping[map_size] = worker_thread_id if map_size < len(attachments_map) {
thread_to_attachment_mapping[worker_thread_id] = map_size attachment_to_thread_mapping[map_size] = worker_thread_id
api.LogDebugf("len(attachment_to_thread_mapping): %d", len(attachment_to_thread_mapping)) thread_to_attachment_mapping[worker_thread_id] = map_size
api.LogDebugf("thread_to_attachment_mapping: %v", thread_to_attachment_mapping) api.LogDebugf("len(attachment_to_thread_mapping): %d", len(attachment_to_thread_mapping))
api.LogDebugf("attachment_to_thread_mapping: %v", attachment_to_thread_mapping) api.LogDebugf("thread_to_attachment_mapping: %v", thread_to_attachment_mapping)
} else { api.LogDebugf("attachment_to_thread_mapping: %v", attachment_to_thread_mapping)
panic("unexpected thread id") } else {
panic("unexpected thread id")
}
} }
}
worker_id := thread_to_attachment_mapping[int(worker_thread_id)] worker_id := thread_to_attachment_mapping[int(worker_thread_id)]
api.LogDebugf("worker_id: %d", worker_id) api.LogDebugf("worker_id: %d", worker_id)
filter_id.Add(1) filter_id.Add(1)
session_id := filter_id.Load() session_id := filter_id.Load()
attachment_ptr := attachments_map[worker_id] attachment_ptr := attachments_map[worker_id]
session_data := C.InitSessionData((*C.NanoAttachment)(attachment_ptr), C.SessionID(session_id)) session_data := C.InitSessionData((*C.NanoAttachment)(attachment_ptr), C.SessionID(session_id))
return &filter{ return &filter{
callbacks: callbacks, callbacks: callbacks,
config: conf, config: conf,
session_id: session_id, session_id: session_id,
cp_attachment: attachment_ptr, cp_attachment: attachment_ptr,
session_data: session_data, session_data: session_data,
request_structs: attachment_to_filter_request_structs[worker_id], request_structs: attachment_to_filter_request_structs[worker_id],
}
} }
} }
func main() {} func main() {}

View File

@ -107,6 +107,7 @@ type filter struct {
session_data *C.HttpSessionData session_data *C.HttpSessionData
cp_attachment *nano_attachment cp_attachment *nano_attachment
request_structs *filterRequestStructs request_structs *filterRequestStructs
body_buffer_chunk int
} }
type filterRequestStructs struct { type filterRequestStructs struct {
@ -230,10 +231,6 @@ func (f *filter) sendBody(buffer api.BufferInstance, is_req bool) C.AttachmentVe
data := buffer.Bytes() data := buffer.Bytes()
data_len := len(data) data_len := len(data)
buffer_size := 8 * 1024 buffer_size := 8 * 1024
// body_chunk := newNanoStr(data)
// body_chunk.data = (*C.uchar)(unsafe.Pointer(&data[0]))
num_of_buffers := ((data_len - 1) / buffer_size) + 1 num_of_buffers := ((data_len - 1) / buffer_size) + 1
// TO DO: FIX THIS ASAP // TO DO: FIX THIS ASAP
@ -299,20 +296,7 @@ func (f *filter) handleStartTransaction(header api.RequestHeaderMap) {
} }
func (f *filter) sendLocalReplyInternal(ret_code int, custom_response string, headers map[string][]string) api.StatusType { func (f *filter) sendLocalReplyInternal(ret_code int, custom_response string, headers map[string][]string) api.StatusType {
//f.callbacks.DecoderFilterCallbacks().SendLocalReply(ret_code, custom_response, headers, 0, "") // new api f.callbacks.SendLocalReply(ret_code, custom_response, headers, 0, "")
// var headers_map map[string]string = nil
// if headers != nil {
// headers_map = make(map[string]string)
// for key, val := range headers {
// header_val := ""
// if len(val) > 0 {
// header_val = val[0]
// }
// headers_map[key] = header_val
// }
// }
f.callbacks.DecoderFilterCallbacks().SendLocalReply(ret_code, custom_response, headers, 0, "")
return api.LocalReply return api.LocalReply
} }
@ -428,6 +412,21 @@ func (f *filter) EncodeHeaders(header api.ResponseHeaderMap, endStream bool) api
return ret return ret
} }
func injectBodyChunk(
curr_modification *C.struct_NanoHttpModificationList,
body_buffer_chunk int,
buffer *api.BufferInstance) {
for curr_modification != nil {
if (int(curr_modification.modification.orig_buff_index) == body_buffer_chunk) {
mod := curr_modification.modification // type: HttpInjectData
modifications := C.GoString(curr_modification.modification_buffer)
new_buffer:= insertAtPosition((*buffer).String(), modifications, int(mod.injection_pos))
(*buffer).SetString(new_buffer)
}
curr_modification = curr_modification.next
}
}
// EncodeData might be called multiple times during handling the response body. // EncodeData might be called multiple times during handling the response body.
// The endStream is true when handling the last piece of the body. // The endStream is true when handling the last piece of the body.
func (f *filter) EncodeData(buffer api.BufferInstance, endStream bool) api.StatusType { func (f *filter) EncodeData(buffer api.BufferInstance, endStream bool) api.StatusType {
@ -448,6 +447,8 @@ func (f *filter) EncodeData(buffer api.BufferInstance, endStream bool) api.Statu
} }
res := f.sendBody(buffer, false) res := f.sendBody(buffer, false)
injectBodyChunk(res.modifications, f.body_buffer_chunk, &buffer)
f.body_buffer_chunk++
if C.AttachmentVerdict(res.verdict) != C.ATTACHMENT_VERDICT_INSPECT { if C.AttachmentVerdict(res.verdict) != C.ATTACHMENT_VERDICT_INSPECT {
api.LogInfof("got final verict: %v", res.verdict) api.LogInfof("got final verict: %v", res.verdict)
return f.finalizeRequest(&res) return f.finalizeRequest(&res)
@ -471,15 +472,15 @@ func (f *filter) EncodeTrailers(trailers api.ResponseTrailerMap) api.StatusType
} }
// OnLog is called when the HTTP stream is ended on HTTP Connection Manager filter. // OnLog is called when the HTTP stream is ended on HTTP Connection Manager filter.
func (f *filter) OnLog(api.RequestHeaderMap, api.RequestTrailerMap, api.ResponseHeaderMap, api.ResponseTrailerMap) {} func (f *filter) OnLog() {}
// OnLogDownstreamStart is called when HTTP Connection Manager filter receives a new HTTP request // OnLogDownstreamStart is called when HTTP Connection Manager filter receives a new HTTP request
// (required the corresponding access log type is enabled) // (required the corresponding access log type is enabled)
func (f *filter) OnLogDownstreamStart(api.RequestHeaderMap) {} func (f *filter) OnLogDownstreamStart() {}
// OnLogDownstreamPeriodic is called on any HTTP Connection Manager periodic log record // OnLogDownstreamPeriodic is called on any HTTP Connection Manager periodic log record
// (required the corresponding access log type is enabled) // (required the corresponding access log type is enabled)
func (f *filter) OnLogDownstreamPeriodic(api.RequestHeaderMap, api.RequestTrailerMap, api.ResponseHeaderMap, api.ResponseTrailerMap) {} func (f *filter) OnLogDownstreamPeriodic() {}
func (f *filter) OnDestroy(reason api.DestroyReason) { func (f *filter) OnDestroy(reason api.DestroyReason) {
freeHttpMetaDataFields(f.request_structs.http_meta_data) freeHttpMetaDataFields(f.request_structs.http_meta_data)

View File

@ -1,15 +1,13 @@
module gitlab.ngen.checkpoint.com/Ngen/agent-core/attachments/envoy module gitlab.ngen.checkpoint.com/Ngen/agent-core/attachments/envoy
// the version should >= 1.18 // the version should >= 1.18
go 1.22 go 1.20
toolchain go1.22.5
// NOTICE: these lines could be generated automatically by "go mod tidy" // NOTICE: these lines could be generated automatically by "go mod tidy"
require ( require (
github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa
github.com/envoyproxy/envoy v1.32.1 github.com/envoyproxy/envoy v1.29.8-0.20240702140355-f3e7e90ed021
google.golang.org/protobuf v1.35.1 google.golang.org/protobuf v1.34.2
) )
require github.com/go-chi/chi/v5 v5.1.0 require github.com/go-chi/chi/v5 v5.1.0

View File

@ -1,7 +1,11 @@
github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ= github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ=
github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM= github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM=
github.com/envoyproxy/envoy v1.32.1 h1:+HeajIC+S9PH3mjY/bVqJabjprqxA7h6pSQ+Ie1Ziww= github.com/envoyproxy/envoy v1.28.1-0.20231218050644-ca5d45d1887a h1:PQveCjvjXZS400K7z+uuouN/Q/dLhLpB5a/6GIC4v34=
github.com/envoyproxy/envoy v1.32.1/go.mod h1:KGS+IUehDX1mSIdqodPTWskKOo7bZMLLy3GHxvOKcJk= github.com/envoyproxy/envoy v1.28.1-0.20231218050644-ca5d45d1887a/go.mod h1:STO/nOGQMw2DNOFTaokM1VY72GJBs0mbXq0I1lJr0XQ=
github.com/envoyproxy/envoy v1.29.8-0.20240702140355-f3e7e90ed021 h1:mTisjPVHGpxlWi7Yj7PnpxD0GeoauHcWvEgch069i+M=
github.com/envoyproxy/envoy v1.29.8-0.20240702140355-f3e7e90ed021/go.mod h1:ujBFxE543X8OePZG+FbeR9LnpBxTLu64IAU7A20EB9A=
github.com/envoyproxy/envoy v1.31.0 h1:NsTo+medzu0bMffXAjl+zKaViLOShKuIZWQnKKYq0/4=
github.com/envoyproxy/envoy v1.31.0/go.mod h1:ujBFxE543X8OePZG+FbeR9LnpBxTLu64IAU7A20EB9A=
github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA=
github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE=
github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
@ -11,7 +15,6 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 h1:rcS6EyEaoCO52hQDupoSfrxI3R6C2Tq741is7X8OvnM= google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 h1:rcS6EyEaoCO52hQDupoSfrxI3R6C2Tq741is7X8OvnM=
google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917/go.mod h1:CmlNWB9lSezaYELKS5Ym1r44VrrbPUa7JTvw+6MbpJ0= google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917/go.mod h1:CmlNWB9lSezaYELKS5Ym1r44VrrbPUa7JTvw+6MbpJ0=
@ -19,5 +22,5 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 h1:
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917/go.mod h1:xtjpI3tXFPP051KaWnhvxkiubL/6dJ18vLVf7q2pTOU= google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917/go.mod h1:xtjpI3tXFPP051KaWnhvxkiubL/6dJ18vLVf7q2pTOU=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=

View File

@ -14,6 +14,7 @@ import (
"unsafe" "unsafe"
"os" "os"
"runtime" "runtime"
"strconv"
) )
func getEnv(key, defaultValue string) string { func getEnv(key, defaultValue string) string {
value, exists := os.LookupEnv(key) value, exists := os.LookupEnv(key)
@ -23,49 +24,48 @@ func getEnv(key, defaultValue string) string {
return value return value
} }
var INSERT_POS_ERR_MSG = "Got invalid insertion position, will not insert."
func copyToSlice(dest []byte, src unsafe.Pointer, size C.size_t, location int) int { func copyToSlice(dest []byte, src unsafe.Pointer, size C.size_t, location int) int {
C.memcpy(unsafe.Pointer(&dest[location]), src, size) C.memcpy(unsafe.Pointer(&dest[location]), src, size)
return location + int(size) return location + int(size)
} }
func newNanoStr(data []byte) *C.nano_str_t { func newNanoStr(data []byte) *C.nano_str_t {
// Allocate memory for the nano_str_t struct
nanoStr := (*C.nano_str_t)(C.malloc(C.size_t(unsafe.Sizeof(C.nano_str_t{})))) nanoStr := (*C.nano_str_t)(C.malloc(C.size_t(unsafe.Sizeof(C.nano_str_t{}))))
if nanoStr == nil { if nanoStr == nil {
panic("failed to allocate memory for nano_str_t struct") panic("failed to allocate memory for nano_str_t struct")
} }
// Set the length of the data
nanoStr.len = C.size_t(len(data)) nanoStr.len = C.size_t(len(data))
// Allocate memory for the data field and copy the Go byte slice into it
// nanoStr.data = (*C.uchar)(C.malloc(C.size_t(len(data))))
// if nanoStr.data == nil {
// C.free(unsafe.Pointer(nanoStr))
// panic("failed to allocate memory for data field")
// }
// copy((*[1 << 30]byte)(unsafe.Pointer(nanoStr.data))[:len(data):len(data)], data)
return nanoStr return nanoStr
} }
func insertAtPosition(buff string, injection string, pos int) string {
if pos < 0 || pos > len(buff) {
api.LogDebugf(
INSERT_POS_ERR_MSG +
" Position: " +
strconv.Itoa(pos) +
", buffer's lenght: " +
strconv.Itoa(len(buff)))
return buff
}
return_buff := buff[:pos] + injection + buff[pos:]
return return_buff
}
func createNanoStr(str string) C.nano_str_t { func createNanoStr(str string) C.nano_str_t {
c_str := C.CString(str) c_str := C.CString(str)
// nanoStr := (*C.nano_str_t)(C.malloc(C.size_t(unsafe.Sizeof(C.nano_str_t{}))))
nanoStr := C.nano_str_t{ nanoStr := C.nano_str_t{
len: C.size_t(len(str)), len: C.size_t(len(str)),
data: (*C.uchar)(unsafe.Pointer(c_str)), data: (*C.uchar)(unsafe.Pointer(c_str)),
} }
// nanoStr.len = C.size_t(len(str))
// nanoStr.data = (*C.uchar)(unsafe.Pointer(c_str))
return nanoStr return nanoStr
} }
func createNanoStrWithoutCopy(str string) C.nano_str_t { func createNanoStrWithoutCopy(str string) C.nano_str_t {
//c_str := C.CString(str)
nanoStr := C.nano_str_t{ nanoStr := C.nano_str_t{
len: C.size_t(len(str)), len: C.size_t(len(str)),
data: (*C.uchar)(unsafe.Pointer((*(*reflect.StringHeader)(unsafe.Pointer(&str))).Data)), data: (*C.uchar)(unsafe.Pointer((*(*reflect.StringHeader)(unsafe.Pointer(&str))).Data)),
@ -105,4 +105,4 @@ func RecoverPanic(ret *api.StatusType) {
*ret = api.Continue *ret = api.Continue
} }
} }

View File

@ -4,9 +4,10 @@ include_directories(include)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_GNU_SOURCE -lpthread -Wall") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_GNU_SOURCE -lpthread -Wall")
link_directories(../../core) link_directories(${ng_module_osrc_zlib_path}/lib)
link_directories(../../core/shmem_ipc) link_directories(${CMAKE_BINARY_DIR}/core)
include_directories(../../core/include/attachments) link_directories(${CMAKE_BINARY_DIR}/core/shmem_ipc)
include_directories(${PROJECT_SOURCE_DIR}/core/include/attachments)
add_library( add_library(
@ -21,9 +22,10 @@ add_library(
nano_attachment_sender.c nano_attachment_sender.c
nano_attachment_sender_thread.c nano_attachment_sender_thread.c
nano_attachment_metric.c nano_attachment_metric.c
nano_compression.c
) )
target_link_libraries(nano_attachment shmem_ipc_2 nano_attachment_util) target_link_libraries(nano_attachment shmem_ipc_2 nano_attachment_util compression_utils)
# add_subdirectory(nano_attachment_ut) # add_subdirectory(nano_attachment_ut)

View File

@ -0,0 +1,72 @@
#ifndef __MOCK_NANO_COMPRESSION_H__
#define __MOCK_NANO_COMPRESSION_H__
#include "cmock.h"
#include "nano_attachment_common.h"
extern "C" {
#include "nano_compression.h"
}
class NanoCompressionMocker : public CMockMocker<NanoCompressionMocker>
{
public:
MOCK_METHOD3(
nano_compress_body,
HttpBody*(
NanoAttachment *attachment,
HttpBody *bodies,
HttpSessionData *session_data_p
)
);
MOCK_METHOD3(
nano_decompress_body,
HttpBody*(
NanoAttachment *attachment,
HttpBody *bodies,
HttpSessionData *session_data_p
)
);
MOCK_METHOD3(
nano_free_compressed_body,
void(
NanoAttachment *attachment,
HttpBody *bodies,
HttpSessionData *session_data_p
)
);
};
CMOCK_MOCK_FUNCTION3(
NanoCompressionMocker,
nano_compress_body,
HttpBody*(
NanoAttachment *attachment,
HttpBody *bodies,
HttpSessionData *session_data_p
)
);
CMOCK_MOCK_FUNCTION3(
NanoCompressionMocker,
nano_decompress_body,
HttpBody*(
NanoAttachment *attachment,
HttpBody *bodies,
HttpSessionData *session_data_p
)
);
CMOCK_MOCK_FUNCTION3(
NanoCompressionMocker,
nano_free_compressed_body,
void(
NanoAttachment *attachment,
HttpBody *bodies,
HttpSessionData *session_data_p
)
);
#endif // __MOCK_NANO_COMPRESSION_H__

View File

@ -15,17 +15,18 @@
#include "nano_utils.h" #include "nano_utils.h"
#include "attachment_types.h" #include "attachment_types.h"
#include "nano_blockpage.h" #include "nano_blockpage.h"
#include "compression_utils.h"
#include "nano_compression.h"
NanoAttachment * NanoAttachment *
InitNanoAttachment(uint8_t attachment_type, int worker_id, int num_of_workers, int logging_fd) InitNanoAttachment(uint8_t attachment_type, int worker_id, int num_of_workers, int logging_fd)
{ {
// NanoAttachment *attachment = malloc(sizeof(NanoAttachment)); NanoAttachment *attachment = malloc(sizeof(NanoAttachment));
NanoAttachment *attachment = calloc(1, sizeof(NanoAttachment));
if (attachment == NULL) { if (attachment == NULL) {
return NULL; return NULL;
} }
// memset(attachment, 0, sizeof(NanoAttachment)); memset(attachment, 0, sizeof(NanoAttachment));
attachment->shared_verdict_signal_path[0] = '\0'; attachment->shared_verdict_signal_path[0] = '\0';
attachment->worker_id = worker_id; attachment->worker_id = worker_id;
@ -141,6 +142,10 @@ InitSessionData(NanoAttachment *attachment, SessionID session_id)
session_data->processed_req_body_size = 0; session_data->processed_req_body_size = 0;
session_data->processed_res_body_size = 0; session_data->processed_res_body_size = 0;
session_data->response_data.compression_type = NO_COMPRESSION;
session_data->response_data.compression_stream = NULL;
session_data->response_data.decompression_stream = NULL;
return session_data; return session_data;
}; };
@ -153,6 +158,16 @@ FiniSessionData(NanoAttachment *attachment, HttpSessionData *session_data)
DBG_LEVEL_DEBUG, DBG_LEVEL_DEBUG,
"Freeing session data for session_id" "Freeing session data for session_id"
); );
if (session_data->response_data.compression_stream != NULL) {
finiCompressionStream(session_data->response_data.compression_stream);
session_data->response_data.compression_stream = NULL;
}
if (session_data->response_data.decompression_stream != NULL) {
finiCompressionStream(session_data->response_data.decompression_stream);
session_data->response_data.decompression_stream = NULL;
}
free(session_data); free(session_data);
}; };
@ -208,13 +223,6 @@ SendDataNanoAttachment(NanoAttachment *attachment, AttachmentData *data)
return response; return response;
} }
// LCOV_EXCL_START Reason: Simple wrapper.
AttachmentVerdictResponse SendDataNanoAttachmentWrapper(NanoAttachment *attachment, AttachmentData data)
{
return SendDataNanoAttachment(attachment, &data);
}
// LCOV_EXCL_STOP
/// ///
/// @brief Connects to the keep-alive socket. /// @brief Connects to the keep-alive socket.
/// ///
@ -587,3 +595,22 @@ FreeAttachmentResponseContent(
return; return;
} }
HttpBody *
compressBody(NanoAttachment *attachment, HttpSessionData *session_data, HttpBody *bodies)
{
return nano_compress_body(attachment, bodies, session_data);
}
HttpBody *
decompressBody(NanoAttachment *attachment, HttpSessionData *session_data, HttpBody *bodies)
{
return nano_decompress_body(attachment, bodies, session_data);
}
void
freeCompressedBody(NanoAttachment *attachment, HttpSessionData *session_data, HttpBody *bodies)
{
nano_free_compressed_body(attachment, bodies, session_data);
}

View File

@ -1,217 +0,0 @@
#ifndef __NANO_ATTACHMENT_H__
#define __NANO_ATTACHMENT_H__
#include "nano_attachment_common.h"
#include "nano_initializer.h"
///
/// @brief Initializes a NanoAttachment structure.
///
/// This function initializes a NanoAttachment structure with the specified parameters and default values.
///
/// @param attachment_type The type of attachment to initialize.
/// @param worker_id The ID of the worker associated with the attachment.
/// @param num_of_workers The total number of workers.
/// @param logging_fd The file descriptor for logging.
///
/// @return A pointer to the initialized NanoAttachment structure if the function completes, NULL otherwise.
///
NanoAttachment * InitNanoAttachment(uint8_t attachment_type, int worker_id, int num_of_workers, int logging_fd);
///
/// @brief Cleans up resources associated with a NanoAttachment structure and deallocates memory.
///
/// This function performs cleanup operations on a NanoAttachment structure and deallocates
/// the memory associated with it.
/// The function closes the logging file descriptor associated with the NanoAttachment
/// and frees the memory allocated for the structure.
///
/// @param attachment A pointer to the NanoAttachment structure to be cleaned up.
///
void FiniNanoAttachment(NanoAttachment *attachment);
///
/// @brief Restarts the configuration of a NanoAttachment.
///
/// @param attachment A pointer to the NanoAttachment whose configuration is to be restarted.
///
/// @return A NanoCommunicationResult indicating the success or failure of the operation.
NanoCommunicationResult RestartAttachmentConfiguration(NanoAttachment *attachment);
///
/// @brief Initializes a HttpSessionData structure with default values.
///
/// This function dynamically allocates memory for a HttpSessionData structure
/// and initializes its fields with default values.
///
/// @param attachment A pointer to the NanoAttachment structure associated with the session.
/// @param session_id The ID of the session to be initialized.
///
/// @return A pointer to the initialized HttpSessionData structure if the function completes, NULL otherwise.
///
HttpSessionData * InitSessionData(NanoAttachment *attachment, SessionID session_id);
///
/// @brief Cleans up and deallocates resources associated with a HttpSessionData structure.
///
/// This function performs cleanup operations on a HttpSessionData structure and deallocates
/// the memory associated with it. It writes a debug message indicating the session ID being
/// freed, and then frees the memory allocated for the HttpSessionData structure.
///
/// @param attachment A pointer to the NanoAttachment structure associated with the session.
/// @param session_data A pointer to the HttpSessionData structure to be cleaned up.
///
void FiniSessionData(NanoAttachment *attachment, HttpSessionData *session_data);
///
/// @brief Updates a metric associated with a NanoAttachment.
///
/// This function updates a metric associated with a NanoAttachment structure
/// based on the provided metric type and value. It delegates the actual updating
/// of the metric to the helper function updateMetricField.
///
/// @param attachment A pointer to the NanoAttachment structure associated with the metric.
/// @param metric The type of metric to be updated.
/// @param value The value to be incorporated into the metric calculation.
///
void UpdateMetric(NanoAttachment *attachment, AttachmentMetricType metric, uint64_t value);
///
/// @brief Sends metric data that been accumulated in the attachment to the service.
///
/// @param attachment A pointer to the NanoAttachment structure associated with the metric.
///
void SendAccumulatedMetricData(NanoAttachment *attachment);
///
/// @brief Processes and sends attachment data to the appropriate handlers.
///
/// This function processes the attachment data based on its chunk type and sends
/// it to the appropriate handler functions. If the chunk type is not recognized,
/// it sets a default verdict of ATTACHMENT_VERDICT_INSPECT and returns an AttachmentVerdictResponse
/// structure containing the default verdict and the session ID from the provided AttachmentData.
///
/// @param attachment A pointer to the NanoAttachment structure associated with the data.
/// @param data A pointer to the AttachmentData structure containing the data to be processed.
///
/// @return An AttachmentVerdictResponse structure containing the verdict and session ID.
///
AttachmentVerdictResponse SendDataNanoAttachment(NanoAttachment *attachment, AttachmentData *data);
AttachmentVerdictResponse SendDataNanoAttachmentWrapper(NanoAttachment *attachment, AttachmentData data);
///
/// @brief Sends a keep-alive signal using a socket connection.
///
/// @param attachment A pointer to a NanoAttachment struct containing attachment information.
///
void SendKeepAlive(NanoAttachment *attachment);
///
/// @brief Checks if a session is finalized based on the session's verdict.
///
/// @param attachment The NanoAttachment object associated with the session.
/// @param session_data The HttpSessionData object representing the session.
///
/// @return Returns 0 if the session is not finalized, 1 otherwise.
///
int IsSessionFinalized(NanoAttachment *attachment, HttpSessionData *session_data);
///
/// @brief Checks if the response contains modifications.
///
/// This function determines whether the provided response contains modifications.
///
/// @param attachment A pointer to a NanoAttachment structure representing the attachment.
/// @param session_data A pointer to a HttpSessionData structure containing session data.
/// @param response A pointer to an AttachmentVerdictResponse structure representing the response.
///
/// @return 1 if the response contains modifications, 0 otherwise.
///
int IsResponseWithModification(
NanoAttachment *attachment,
HttpSessionData *session_data,
AttachmentVerdictResponse *response
);
///
/// @brief Retrieves response modifications from the given attachment and session data.
///
/// @param attachment Pointer to a NanoAttachment object.
/// @param session_data Pointer to HttpSessionData object containing session information.
/// @param response Pointer to an AttachmentVerdictResponse object.
///
/// @return NanoResponseModifications structure containing response modifications.
///
NanoResponseModifications GetResponseModifications(
NanoAttachment *attachment,
HttpSessionData *session_data,
AttachmentVerdictResponse *response
);
///
/// @brief Retrieves the type of web response associated with the given attachment and session data.
///
/// This function checks if the provided response object contains valid web response data.
/// If the response object is null, it logs a warning and returns NO_WEB_RESPONSE.
/// Otherwise, it returns the type of web response contained in the response object.
///
/// @param attachment Pointer to the NanoAttachment structure associated with the request.
/// @param session_data Pointer to the HttpSessionData structure containing session-related data.
/// @param response Pointer to the AttachmentVerdictResponse structure containing response data.
///
/// @return The type of web response, or NO_WEB_RESPONSE if no response object is provided.
///
NanoWebResponseType GetWebResponseType(
NanoAttachment *attachment,
HttpSessionData *session_data,
AttachmentVerdictResponse *response
);
///
/// @brief Retrieves the block page data for a response.
///
/// @param attachment The NanoAttachment object associated with the session.
/// @param session_data The HttpSessionData object representing the session.
/// @param response The AttachmentVerdictResponse object containing the verdict.
///
/// @return
///
BlockPageData GetBlockPage(
NanoAttachment *attachment,
HttpSessionData *session_data,
AttachmentVerdictResponse *response
);
///
/// @brief Retrieves the redict page data for a response.
///
/// @param attachment The NanoAttachment object associated with the session.
/// @param session_data The HttpSessionData object representing the session.
/// @param response The AttachmentVerdictResponse object containing the verdict.
///
/// @return
///
RedirectPageData GetRedirectPage(
NanoAttachment *attachment,
HttpSessionData *session_data,
AttachmentVerdictResponse *response
);
///
/// @brief Free allocated resources of an AttachmentVerdictResponse.
///
/// This function frees the allocated resources of an AttachmentVerdictResponse.
///
/// @param attachment The NanoAttachment object associated with the session.
/// @param session_data The HttpSessionData object representing the session.
/// @param response The AttachmentVerdictResponse object to be freed.
///
void FreeAttachmentResponseContent(
NanoAttachment *attachment,
HttpSessionData *session_data,
AttachmentVerdictResponse *response
);
#endif // __NANO_ATTACHMENT_H__

View File

@ -50,6 +50,7 @@ notify_signal_to_service(NanoAttachment *attachment, uint32_t cur_session_id)
s_poll.fd = attachment->comm_socket; s_poll.fd = attachment->comm_socket;
s_poll.events = POLLOUT; s_poll.events = POLLOUT;
s_poll.revents = 0;
res = poll(&s_poll, 1, 0); res = poll(&s_poll, 1, 0);
if (res > 0 && s_poll.revents & POLLHUP) { if (res > 0 && s_poll.revents & POLLHUP) {
write_dbg( write_dbg(
@ -470,7 +471,7 @@ create_modification_node(NanoAttachment *attachment, SessionID session_id, HttpI
"Injection position: %d, " "Injection position: %d, "
"Injection size: %d, " "Injection size: %d, "
"Original buffer index: %d, " "Original buffer index: %d, "
"Data: %s, " "Modification data: %s, "
"Should change data: %d", "Should change data: %d",
modification_node->modification.is_header, modification_node->modification.is_header,
modification_node->modification.injection_pos, modification_node->modification.injection_pos,
@ -513,6 +514,15 @@ handle_inject_response(
for (modification_index = 0; modification_index < modification_count; modification_index++) { for (modification_index = 0; modification_index < modification_count; modification_index++) {
// Go over the modifications and create nodes. // Go over the modifications and create nodes.
new_modification = create_modification_node(attachment, session_id, inject_data); new_modification = create_modification_node(attachment, session_id, inject_data);
write_dbg(
attachment,
session_id,
DBG_LEVEL_DEBUG,
"create modification node %d out of %d",
modification_index,
modification_count
);
if (new_modification == NULL) { if (new_modification == NULL) {
write_dbg(attachment, session_id, DBG_LEVEL_WARNING, "Failed to create modification node"); write_dbg(attachment, session_id, DBG_LEVEL_WARNING, "Failed to create modification node");
while (*modification_list) { while (*modification_list) {
@ -527,6 +537,10 @@ handle_inject_response(
*modification_list = new_modification; *modification_list = new_modification;
current_modification = *modification_list; current_modification = *modification_list;
} else { } else {
while (*modification_list) {
current_modification = *modification_list;
*modification_list = (*modification_list)->next;
}
current_modification->next = new_modification; current_modification->next = new_modification;
current_modification = current_modification->next; current_modification = current_modification->next;
} }

View File

@ -1,9 +1,64 @@
#include "nano_attachment_sender_thread.h" #include "nano_attachment_sender_thread.h"
#include <string.h>
#include <stdlib.h>
#include "nano_initializer.h" #include "nano_initializer.h"
#include "nano_attachment_sender.h" #include "nano_attachment_sender.h"
#include "nano_attachment_common.h" #include "nano_attachment_common.h"
#include "nano_attachment_io.h" #include "nano_attachment_io.h"
#include "nano_utils.h"
#include "nano_compression.h"
static HttpHeaderData *
get_http_header(HttpHeaders *http_headers, const char *header_name) {
size_t i;
for (i = 0; i < http_headers->headers_count; ++i) {
if (strcmp((char*)http_headers->data[i].key.data, header_name) == 0) {
return &http_headers->data[i];
}
}
return NULL;
}
static void
set_response_content_encoding(
NanoAttachment *attachment,
HttpSessionData *session_data_p,
HttpHeaders *http_headers
)
{
write_dbg(
attachment,
session_data_p->session_id,
DBG_LEVEL_TRACE,
"Determining response body's content encoding"
);
const HttpHeaderData *content_encoding = get_http_header(http_headers, "content-encoding");
if (content_encoding == NULL) {
session_data_p->response_data.compression_type = NO_COMPRESSION;
return;
}
if (strcmp((char*)content_encoding->value.data, "gzip") == 0) {
session_data_p->response_data.compression_type = GZIP;
} else if (strcmp((char*)content_encoding->value.data, "deflate") == 0) {
session_data_p->response_data.compression_type = ZLIB;
} else if (strcmp((char*)content_encoding->value.data, "identity") == 0) {
session_data_p->response_data.compression_type = NO_COMPRESSION;
} else {
write_dbg(
attachment,
session_data_p->session_id,
DBG_LEVEL_WARNING,
"Unsupported response content encoding: %.*s",
content_encoding->value.data
);
session_data_p->response_data.compression_type = NO_COMPRESSION;
}
}
void void
init_thread_ctx(HttpEventThreadCtx *ctx, NanoAttachment *attachment, AttachmentData *data) init_thread_ctx(HttpEventThreadCtx *ctx, NanoAttachment *attachment, AttachmentData *data)
@ -133,7 +188,7 @@ SendResponseHeadersThread(void *_ctx)
NanoAttachment *attachment = ctx->attachment; NanoAttachment *attachment = ctx->attachment;
HttpSessionData *session_data_p = ctx->session_data_p; HttpSessionData *session_data_p = ctx->session_data_p;
HttpHeaders *http_headers = headers->headers; HttpHeaders *http_headers = headers->headers;
bool is_verdict_requested = false; bool is_verdict_requested = true;
nano_send_response_code( nano_send_response_code(
attachment, attachment,
@ -151,6 +206,12 @@ SendResponseHeadersThread(void *_ctx)
&session_data_p->remaining_messages_to_reply &session_data_p->remaining_messages_to_reply
); );
set_response_content_encoding(
attachment,
session_data_p,
http_headers
);
nano_header_sender( nano_header_sender(
attachment, attachment,
http_headers, http_headers,

View File

@ -49,3 +49,9 @@ add_unit_test(
"nano_attachment_metrics_ut.cc" "nano_attachment_metrics_ut.cc"
"nano_attachment" "nano_attachment"
) )
add_unit_test(
nano_compression_ut
"nano_compression_ut.cc"
"nano_attachment"
)

View File

@ -25,7 +25,6 @@ public:
initializer_mocker, initializer_mocker,
nano_attachment_init_process(_)).WillOnce(Return(NanoCommunicationResult::NANO_OK) nano_attachment_init_process(_)).WillOnce(Return(NanoCommunicationResult::NANO_OK)
); );
setenv("CLOUDGUARD_UID", "Testing", 1);
attachment = InitNanoAttachment( attachment = InitNanoAttachment(
static_cast<uint8_t>(AttachmentType::NGINX_ATT_ID), static_cast<uint8_t>(AttachmentType::NGINX_ATT_ID),
2, 2,
@ -67,6 +66,10 @@ public:
free(reply_from_service_mock); free(reply_from_service_mock);
FiniSessionData(attachment, session_data); FiniSessionData(attachment, session_data);
FiniNanoAttachment(attachment); FiniNanoAttachment(attachment);
::testing::Mock::VerifyAndClearExpectations(&initializer_mocker);
::testing::Mock::VerifyAndClearExpectations(&mock_shmem_ipc);
::testing::Mock::VerifyAndClearExpectations(&mock_nano_socket);
::testing::Mock::VerifyAndClearExpectations(&mock_nano_poll);
} }
nano_str_t nano_str_t
@ -156,6 +159,8 @@ public:
HttpWebResponseData *web_response_data; HttpWebResponseData *web_response_data;
uint32_t reply_session_id = -1; uint32_t reply_session_id = -1;
void *reply_session_id_void = &reply_session_id; void *reply_session_id_void = &reply_session_id;
struct pollfd fds;
struct pollfd *mock_fds = &fds;
const char **replay_data_mock; const char **replay_data_mock;
NanoAttachment *attachment; NanoAttachment *attachment;
@ -421,7 +426,17 @@ TEST_F(NanoAttachmentIoTest, NanoBodySender)
EXPECT_CALL( EXPECT_CALL(
mock_nano_poll, mock_nano_poll,
poll(_, _, _) poll(_, _, _)
).WillRepeatedly(Return(1)); ).WillRepeatedly(
DoAll(
SaveArg<0>(&mock_fds),
InvokeWithoutArgs(
[&] () {
mock_fds[0].revents = POLLIN;
}
),
Return(1)
)
);
EXPECT_CALL( EXPECT_CALL(
mock_nano_socket, mock_nano_socket,

View File

@ -24,7 +24,6 @@ public:
).WillOnce( ).WillOnce(
Return(NanoCommunicationResult::NANO_OK) Return(NanoCommunicationResult::NANO_OK)
); );
setenv("CLOUDGUARD_UID", "Testing", 1);
attachment = InitNanoAttachment( attachment = InitNanoAttachment(
static_cast<uint8_t>(AttachmentType::NGINX_ATT_ID), static_cast<uint8_t>(AttachmentType::NGINX_ATT_ID),
2, 2,
@ -32,6 +31,7 @@ public:
STDOUT_FILENO STDOUT_FILENO
); );
EXPECT_NE(attachment, nullptr); EXPECT_NE(attachment, nullptr);
} }
void void

View File

@ -26,7 +26,6 @@ public:
).WillOnce( ).WillOnce(
Return(NanoCommunicationResult::NANO_OK) Return(NanoCommunicationResult::NANO_OK)
); );
setenv("CLOUDGUARD_UID", "Testing", 1);
attachment = InitNanoAttachment( attachment = InitNanoAttachment(
static_cast<uint8_t>(AttachmentType::NGINX_ATT_ID), static_cast<uint8_t>(AttachmentType::NGINX_ATT_ID),
2, 2,

View File

@ -6,6 +6,7 @@
#include "mock_nano_initializer.h" #include "mock_nano_initializer.h"
#include "mock_nano_attachment_sender.h" #include "mock_nano_attachment_sender.h"
#include "mock_nano_configuration.h" #include "mock_nano_configuration.h"
#include "mock_nano_compression.h"
extern "C" { extern "C" {
#include "nano_attachment.h" #include "nano_attachment.h"
@ -26,7 +27,6 @@ public:
).WillOnce( ).WillOnce(
Return(NanoCommunicationResult::NANO_OK) Return(NanoCommunicationResult::NANO_OK)
); );
setenv("CLOUDGUARD_UID", "Testing", 1);
attachment = InitNanoAttachment( attachment = InitNanoAttachment(
static_cast<uint8_t>(AttachmentType::NGINX_ATT_ID), static_cast<uint8_t>(AttachmentType::NGINX_ATT_ID),
2, 2,
@ -199,6 +199,7 @@ public:
StrictMock<NanoInitializerMocker> initializer_mocker; StrictMock<NanoInitializerMocker> initializer_mocker;
StrictMock<NanoSocketMocker> socket_mocker; StrictMock<NanoSocketMocker> socket_mocker;
StrictMock<NanoConfigurationMocker> configuration_mocker; StrictMock<NanoConfigurationMocker> configuration_mocker;
StrictMock<NanoCompressionMocker> compression_mocker;
}; };
TEST_F(NanoAttachmentTest, InitNanoAttachment) TEST_F(NanoAttachmentTest, InitNanoAttachment)
@ -450,3 +451,32 @@ TEST_F(NanoAttachmentTest, SendAccumulatedMetricData)
EXPECT_CALL(sender_mocker, SendMetricData(attachment)).WillOnce(Return(NanoCommunicationResult::NANO_OK)); EXPECT_CALL(sender_mocker, SendMetricData(attachment)).WillOnce(Return(NanoCommunicationResult::NANO_OK));
SendAccumulatedMetricData(attachment); SendAccumulatedMetricData(attachment);
} }
TEST_F(NanoAttachmentTest, CompressData)
{
EXPECT_CALL(
compression_mocker,
nano_compress_body(attachment, &http_body_data, session_data)
).WillOnce(Return(nullptr)
);
compressBody(attachment, session_data, &http_body_data);
}
TEST_F(NanoAttachmentTest, DecompressData)
{
EXPECT_CALL(
compression_mocker,
nano_decompress_body(attachment, &http_body_data, session_data)
).WillOnce(Return(nullptr)
);
decompressBody(attachment, session_data, &http_body_data);
}
TEST_F(NanoAttachmentTest, FreeCompressedData)
{
EXPECT_CALL(
compression_mocker,
nano_free_compressed_body(attachment, &http_body_data, session_data)
);
freeCompressedBody(attachment, session_data, &http_body_data);
}

View File

@ -0,0 +1,105 @@
#include "cptest.h"
#include "nano_attachment_common.h"
#include "attachment_types.h"
#include "compression_utils.h"
#include "mock_nano_socket.h"
#include "mock_nano_initializer.h"
#include "mock_nano_attachment_sender.h"
#include "mock_nano_configuration.h"
#include "mock_nano_compression.h"
extern "C" {
#include "nano_attachment.h"
#include "nano_compression.h"
}
using namespace std;
using namespace testing;
class NanoAttachmentTest : public Test
{
public:
void
SetUp() override
{
EXPECT_CALL(
initializer_mocker,
nano_attachment_init_process(_)
).WillOnce(
Return(NanoCommunicationResult::NANO_OK)
);
attachment = InitNanoAttachment(
static_cast<uint8_t>(AttachmentType::NGINX_ATT_ID),
2,
4,
STDOUT_FILENO
);
EXPECT_NE(attachment, nullptr);
session_data = InitSessionData(attachment, 1);
EXPECT_NE(session_data, nullptr);
}
void
TearDown() override
{
FiniSessionData(attachment, session_data);
FiniNanoAttachment(attachment);
}
nano_str_t
create_nano_str(const char *str)
{
nano_str_t nano_str;
nano_str.data = reinterpret_cast<unsigned char *>(const_cast<char *>(str));
nano_str.len = strlen(str);
return nano_str;
}
nano_str_t body[3] = {
create_nano_str("Hello"),
create_nano_str("World"),
create_nano_str("!")
};
HttpBody http_body_data = {
body,
3
};
AttachmentData req_body_data = {
1,
HttpChunkType::HTTP_REQUEST_BODY,
session_data,
(DataBuffer)&http_body_data
};
NanoAttachment *attachment;
HttpSessionData *session_data;
StrictMock<NanoInitializerMocker> initializer_mocker;
};
TEST_F(NanoAttachmentTest, CompressData)
{
session_data->response_data.compression_type = CompressionType::GZIP;
HttpBody * compressed_body_data = nullptr;
HttpBody * decompressed_body_data = nullptr;
compressed_body_data = nano_compress_body(attachment, &http_body_data, session_data);
EXPECT_EQ(compressed_body_data->bodies_count, 3u);
decompressed_body_data = nano_decompress_body(attachment, compressed_body_data, session_data);
EXPECT_EQ(decompressed_body_data->bodies_count, 3u);
EXPECT_EQ(decompressed_body_data->data[0].len, 5u);
EXPECT_EQ(decompressed_body_data->data[1].len, 5u);
EXPECT_EQ(decompressed_body_data->data[2].len, 1u);
EXPECT_EQ(strncmp((char *)decompressed_body_data->data[0].data, "Hello", decompressed_body_data->data[0].len), 0);
EXPECT_EQ(strncmp((char *)decompressed_body_data->data[1].data, "World", decompressed_body_data->data[1].len), 0);
EXPECT_EQ(strncmp((char *)decompressed_body_data->data[2].data, "!", decompressed_body_data->data[2].len), 0);
nano_free_compressed_body(attachment, compressed_body_data, session_data);
nano_free_compressed_body(attachment, decompressed_body_data, session_data);
}

View File

@ -90,7 +90,6 @@ TEST_F(NanoConfigurationTest, InitAttachmentConfiguration)
res = set_logging_fd(&attachment, STDOUT_FILENO); res = set_logging_fd(&attachment, STDOUT_FILENO);
EXPECT_EQ(res, NanoCommunicationResult::NANO_OK); EXPECT_EQ(res, NanoCommunicationResult::NANO_OK);
setenv("CLOUDGUARD_UID", "Testing", 1);
res = set_docker_id(&attachment); res = set_docker_id(&attachment);
EXPECT_EQ(res, NanoCommunicationResult::NANO_OK); EXPECT_EQ(res, NanoCommunicationResult::NANO_OK);

View File

@ -25,7 +25,6 @@ public:
).WillOnce( ).WillOnce(
Return(NanoCommunicationResult::NANO_OK) Return(NanoCommunicationResult::NANO_OK)
); );
setenv("CLOUDGUARD_UID", "Testing", 1);
attachment = InitNanoAttachment( attachment = InitNanoAttachment(
static_cast<uint8_t>(AttachmentType::NGINX_ATT_ID), static_cast<uint8_t>(AttachmentType::NGINX_ATT_ID),
2, 2,
@ -77,7 +76,7 @@ public:
create_nano_str("/dogs.html") create_nano_str("/dogs.html")
}; };
HttpHeaderData http_headers[3] = { HttpHeaderData http_headers[4] = {
{ {
create_nano_str("Host"), create_nano_str("Host"),
create_nano_str("www.nanoattachmentut.com") create_nano_str("www.nanoattachmentut.com")
@ -89,12 +88,16 @@ public:
{ {
create_nano_str("Accept"), create_nano_str("Accept"),
create_nano_str("text/html") create_nano_str("text/html")
},
{
create_nano_str("content-encoding"),
create_nano_str("gzip")
} }
}; };
HttpHeaders http_headers_data = { HttpHeaders http_headers_data = {
http_headers, http_headers,
3 4
}; };
HttpRequestFilterData request_filter_data = { HttpRequestFilterData request_filter_data = {
@ -348,12 +351,14 @@ TEST_F(NanoAttachmentSenderThreadTest, SendResponseHeadersThread)
AttachmentDataType::RESPONSE_HEADER, AttachmentDataType::RESPONSE_HEADER,
session_data->session_id, session_data->session_id,
&session_data->remaining_messages_to_reply, &session_data->remaining_messages_to_reply,
false true
) )
); );
init_thread_ctx(&ctx, attachment, &res_header_data); init_thread_ctx(&ctx, attachment, &res_header_data);
SendResponseHeadersThread(&ctx); SendResponseHeadersThread(&ctx);
EXPECT_EQ(session_data->response_data.compression_type, CompressionType::GZIP);
} }
TEST_F(NanoAttachmentSenderThreadTest, SendRequestBodyThread) TEST_F(NanoAttachmentSenderThreadTest, SendRequestBodyThread)

View File

@ -27,7 +27,6 @@ public:
).WillOnce( ).WillOnce(
Return(NanoCommunicationResult::NANO_OK) Return(NanoCommunicationResult::NANO_OK)
); );
setenv("CLOUDGUARD_UID", "Testing", 1);
attachment = InitNanoAttachment( attachment = InitNanoAttachment(
static_cast<uint8_t>(AttachmentType::NGINX_ATT_ID), static_cast<uint8_t>(AttachmentType::NGINX_ATT_ID),
2, 2,

View File

@ -1,3 +1,7 @@
include_directories(${Boost_INCLUDE_DIRS})
link_directories(${BOOST_ROOT}/lib)
add_definitions(-DUSERSPACE) add_definitions(-DUSERSPACE)
add_library(nano_attachment_util SHARED nano_attachment_util.cc) add_library(nano_attachment_util SHARED nano_attachment_util.cc)
target_link_libraries(nano_attachment_util http_configuration) target_link_libraries(nano_attachment_util http_configuration)

View File

@ -0,0 +1,130 @@
#include "nano_compression.h"
#include <stdlib.h>
#include "nano_attachment_common.h"
#include "nano_initializer.h"
#include "compression_utils.h"
#include "nano_utils.h"
HttpBody *
nano_compress_body(
NanoAttachment *attachment,
HttpBody *bodies,
HttpSessionData *session_data_p
)
{
CompressionResult compression_result;
HttpBody *compressed_body;
size_t i;
if (session_data_p->response_data.compression_type == NO_COMPRESSION) {
return NULL;
}
write_dbg(
attachment,
session_data_p->session_id,
DBG_LEVEL_TRACE,
"Compressing body"
);
if (session_data_p->response_data.compression_stream == NULL) {
session_data_p->response_data.compression_stream = initCompressionStream();
}
compressed_body = malloc(sizeof(HttpBody));
if (compressed_body == NULL) {
return NULL;
}
compressed_body->bodies_count = bodies->bodies_count;
compressed_body->data = malloc(bodies->bodies_count * sizeof(nano_str_t));
if (compressed_body->data == NULL) {
free(compressed_body);
return NULL;
}
for (i = 0; i < bodies->bodies_count; ++i) {
compression_result = compressData(
session_data_p->response_data.compression_stream,
session_data_p->response_data.compression_type,
bodies->data[i].len,
bodies->data[i].data,
i == bodies->bodies_count - 1
);
compressed_body->data[i].len = compression_result.num_output_bytes;
compressed_body->data[i].data = compression_result.output;
}
return compressed_body;
}
HttpBody *
nano_decompress_body(
NanoAttachment *attachment,
HttpBody *bodies,
HttpSessionData *session_data_p
)
{
DecompressionResult decompression_result;
HttpBody *decompressed_body;
size_t i;
if (session_data_p->response_data.compression_type == NO_COMPRESSION) {
return NULL;
}
write_dbg(
attachment,
session_data_p->session_id,
DBG_LEVEL_TRACE,
"Decompressing body"
);
if (session_data_p->response_data.decompression_stream == NULL) {
session_data_p->response_data.decompression_stream = initCompressionStream();
}
decompressed_body = malloc(sizeof(HttpBody));
if (decompressed_body == NULL) {
return NULL;
}
decompressed_body->bodies_count = bodies->bodies_count;
decompressed_body->data = malloc(bodies->bodies_count * sizeof(nano_str_t));
if (decompressed_body->data == NULL) {
free(decompressed_body);
return NULL;
}
for (i = 0; i < bodies->bodies_count; ++i) {
decompression_result = decompressData(
session_data_p->response_data.decompression_stream,
bodies->data[i].len,
bodies->data[i].data
);
decompressed_body->data[i].len = decompression_result.num_output_bytes;
decompressed_body->data[i].data = decompression_result.output;
}
return decompressed_body;
}
void
nano_free_compressed_body(
NanoAttachment *attachment,
HttpBody *bodies,
HttpSessionData *session_data_p
)
{
if (bodies == NULL) {
return;
}
write_dbg(
attachment,
session_data_p->session_id,
DBG_LEVEL_TRACE,
"Freeing compressed body"
);
free(bodies->data);
free(bodies);
}

View File

@ -0,0 +1,45 @@
#ifndef __NANO_COMPRESSION_H__
#define __NANO_COMPRESSION_H__
#include "nano_attachment_sender_thread.h"
/// @brief Compresses the given HTTP body using the specified compression type in the session data.
///
/// @param attachment Pointer to the NanoAttachment structure.
/// @param bodies Pointer to the HttpBody structure containing the data to be compressed.
/// @param session_data_p Pointer to the HttpSessionData structure containing session-specific data.
///
/// @return Pointer to a new HttpBody structure containing the compressed data,
/// or NULL if compression is not needed or fails.
HttpBody *nano_compress_body(
NanoAttachment *attachment,
HttpBody *bodies,
HttpSessionData *session_data_p
);
/// @brief Decompresses the given HTTP body using the specified compression type in the session data.
///
/// @param attachment Pointer to the NanoAttachment structure.
/// @param bodies Pointer to the HttpBody structure containing the data to be decompressed.
/// @param session_data_p Pointer to the HttpSessionData structure containing session-specific data.
///
/// @return Pointer to a new HttpBody structure containing the decompressed data,
/// or NULL if decompression is not needed or fails.
HttpBody *nano_decompress_body(
NanoAttachment *attachment,
HttpBody *bodies,
HttpSessionData *session_data_p
);
/// @brief Frees the memory allocated for the compressed HTTP body.
///
/// @param attachment Pointer to the NanoAttachment structure.
/// @param bodies Pointer to the HttpBody structure containing the compressed data to be freed.
/// @param session_data_p Pointer to the HttpSessionData structure containing session-specific data.
void nano_free_compressed_body(
NanoAttachment *attachment,
HttpBody *bodies,
HttpSessionData *session_data_p
);
#endif // __NANO_COMPRESSION_H__

View File

@ -400,7 +400,6 @@ set_docker_id(NanoAttachment *attachment)
if (!uid_read) { if (!uid_read) {
write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Severe error - failed to get uid!"); write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Severe error - failed to get uid!");
return NANO_ERROR;
} }
return NANO_OK; return NANO_OK;

View File

@ -1,3 +1,5 @@
include_directories(${Boost_INCLUDE_DIRS})
add_library(shmem_ipc_2 SHARED shmem_ipc.c shared_ring_queue.c) add_library(shmem_ipc_2 SHARED shmem_ipc.c shared_ring_queue.c)
target_link_libraries(shmem_ipc_2 -lrt) target_link_libraries(shmem_ipc_2 -lrt)