mirror of
https://github.com/openappsec/attachment.git
synced 2025-06-28 16:41:03 +03:00
pulling from dev
This commit is contained in:
parent
cfeae10dcf
commit
f6d7d09bae
2
attachments/envoy/build_template
Normal file → Executable file
2
attachments/envoy/build_template
Normal file → Executable file
@ -10,4 +10,4 @@ ENVOY_ATTACHMENT_DIR="@ENVOY_ATTACHMENT_DIR@"
|
||||
cd $ENVOY_ATTACHMENT_DIR
|
||||
|
||||
# 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}'"
|
||||
|
@ -3,7 +3,6 @@ package main
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"strconv"
|
||||
@ -35,53 +34,58 @@ unsigned long get_thread_id() {
|
||||
import "C"
|
||||
|
||||
const Name = "cp_nano_filter"
|
||||
|
||||
const Admin_api = "http://127.0.0.1:%s/server_info"
|
||||
const admin_api_server_info = "http://127.0.0.1:%s/server_info"
|
||||
const keep_alive_interval = 10 * time.Second
|
||||
|
||||
var filter_id atomic.Int64
|
||||
|
||||
type nano_attachment C.struct_NanoAttachment
|
||||
|
||||
var attachments_map map[int]*nano_attachment = nil
|
||||
var thread_to_attachment_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 mutex sync.Mutex
|
||||
|
||||
const keep_alive_interval = 10 * time.Second
|
||||
|
||||
var last_keep_alive time.Time
|
||||
|
||||
type nano_attachment C.struct_NanoAttachment
|
||||
|
||||
// EnvoyServerInfo represents the structure of the JSON response from /server_info
|
||||
type EnvoyServerInfo struct {
|
||||
Concurrency int `json:"concurrency"`
|
||||
}
|
||||
|
||||
// getEnvoyConcurrency fetches and returns the concurrency level of Envoy from the admin API
|
||||
func getEnvoyConcurrency(admin_api_address string) (int, error) {
|
||||
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()
|
||||
func getEnvoyConcurrency() int {
|
||||
concurrency_method := getEnv("CONCURRENCY_CALC", "numOfCores")
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return 0, fmt.Errorf("unexpected status code from Envoy admin API: %d", resp.StatusCode)
|
||||
if concurrency_method == "numOfCores" {
|
||||
api.LogWarnf("using number of CPU cores")
|
||||
return runtime.NumCPU()
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to read response body: %w", err)
|
||||
var conc_number string
|
||||
|
||||
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 err := json.Unmarshal(body, &info); err != nil {
|
||||
return 0, fmt.Errorf("failed to parse JSON response: %w", err)
|
||||
if conc_number == "-1" {
|
||||
api.LogWarnf("concurrency number is not set as an env variable, using number of CPU cores")
|
||||
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() {
|
||||
@ -150,8 +154,7 @@ func configurationServer() {
|
||||
|
||||
func init() {
|
||||
last_keep_alive = time.Time{}
|
||||
envoyHttp.RegisterHttpFilterFactoryAndConfigParser(Name, ConfigFactory, &parser{})
|
||||
//envoyHttp.RegisterHttpFilterConfigFactoryAndParser(Name, ConfigFactory, &parser{})
|
||||
envoyHttp.RegisterHttpFilterConfigFactoryAndParser(Name, ConfigFactory, &parser{})
|
||||
go configurationServer()
|
||||
}
|
||||
|
||||
@ -193,37 +196,7 @@ func (p *parser) Parse(any *anypb.Any, callbacks api.ConfigCallbackHandler) (int
|
||||
return conf, nil
|
||||
}
|
||||
|
||||
var num_of_workers int
|
||||
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()
|
||||
}
|
||||
num_of_workers := getEnvoyConcurrency()
|
||||
|
||||
configStruct := &xds.TypedStruct{}
|
||||
if err := any.UnmarshalTo(configStruct); err != nil {
|
||||
@ -266,54 +239,13 @@ func (p *parser) Merge(parent interface{}, child interface{}) interface{} {
|
||||
return &newConfig
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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 {
|
||||
@ -347,6 +279,6 @@ func ConfigFactory(c interface{}, callbacks api.FilterCallbackHandler) api.Strea
|
||||
request_structs: attachment_to_filter_request_structs[worker_id],
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func main() {}
|
||||
|
@ -107,6 +107,7 @@ type filter struct {
|
||||
session_data *C.HttpSessionData
|
||||
cp_attachment *nano_attachment
|
||||
request_structs *filterRequestStructs
|
||||
body_buffer_chunk int
|
||||
}
|
||||
|
||||
type filterRequestStructs struct {
|
||||
@ -230,10 +231,6 @@ func (f *filter) sendBody(buffer api.BufferInstance, is_req bool) C.AttachmentVe
|
||||
data := buffer.Bytes()
|
||||
data_len := len(data)
|
||||
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
|
||||
|
||||
// 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 {
|
||||
//f.callbacks.DecoderFilterCallbacks().SendLocalReply(ret_code, custom_response, headers, 0, "") // new api
|
||||
// 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, "")
|
||||
f.callbacks.SendLocalReply(ret_code, custom_response, headers, 0, "")
|
||||
return api.LocalReply
|
||||
}
|
||||
|
||||
@ -428,6 +412,21 @@ func (f *filter) EncodeHeaders(header api.ResponseHeaderMap, endStream bool) api
|
||||
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.
|
||||
// The endStream is true when handling the last piece of the body.
|
||||
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)
|
||||
injectBodyChunk(res.modifications, f.body_buffer_chunk, &buffer)
|
||||
f.body_buffer_chunk++
|
||||
if C.AttachmentVerdict(res.verdict) != C.ATTACHMENT_VERDICT_INSPECT {
|
||||
api.LogInfof("got final verict: %v", res.verdict)
|
||||
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.
|
||||
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
|
||||
// (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
|
||||
// (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) {
|
||||
freeHttpMetaDataFields(f.request_structs.http_meta_data)
|
||||
|
@ -1,15 +1,13 @@
|
||||
module gitlab.ngen.checkpoint.com/Ngen/agent-core/attachments/envoy
|
||||
|
||||
// the version should >= 1.18
|
||||
go 1.22
|
||||
|
||||
toolchain go1.22.5
|
||||
go 1.20
|
||||
|
||||
// NOTICE: these lines could be generated automatically by "go mod tidy"
|
||||
require (
|
||||
github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa
|
||||
github.com/envoyproxy/envoy v1.32.1
|
||||
google.golang.org/protobuf v1.35.1
|
||||
github.com/envoyproxy/envoy v1.29.8-0.20240702140355-f3e7e90ed021
|
||||
google.golang.org/protobuf v1.34.2
|
||||
)
|
||||
|
||||
require github.com/go-chi/chi/v5 v5.1.0
|
||||
|
@ -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/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM=
|
||||
github.com/envoyproxy/envoy v1.32.1 h1:+HeajIC+S9PH3mjY/bVqJabjprqxA7h6pSQ+Ie1Ziww=
|
||||
github.com/envoyproxy/envoy v1.32.1/go.mod h1:KGS+IUehDX1mSIdqodPTWskKOo7bZMLLy3GHxvOKcJk=
|
||||
github.com/envoyproxy/envoy v1.28.1-0.20231218050644-ca5d45d1887a h1:PQveCjvjXZS400K7z+uuouN/Q/dLhLpB5a/6GIC4v34=
|
||||
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/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE=
|
||||
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/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/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
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/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/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.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
|
||||
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
"unsafe"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
)
|
||||
func getEnv(key, defaultValue string) string {
|
||||
value, exists := os.LookupEnv(key)
|
||||
@ -23,49 +24,48 @@ func getEnv(key, defaultValue string) string {
|
||||
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 {
|
||||
C.memcpy(unsafe.Pointer(&dest[location]), src, size)
|
||||
return location + int(size)
|
||||
}
|
||||
|
||||
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{}))))
|
||||
if nanoStr == nil {
|
||||
panic("failed to allocate memory for nano_str_t struct")
|
||||
}
|
||||
|
||||
// Set the length of the 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
|
||||
}
|
||||
|
||||
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 {
|
||||
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{
|
||||
len: C.size_t(len(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
|
||||
}
|
||||
|
||||
func createNanoStrWithoutCopy(str string) C.nano_str_t {
|
||||
//c_str := C.CString(str)
|
||||
|
||||
nanoStr := C.nano_str_t{
|
||||
len: C.size_t(len(str)),
|
||||
data: (*C.uchar)(unsafe.Pointer((*(*reflect.StringHeader)(unsafe.Pointer(&str))).Data)),
|
||||
|
@ -4,9 +4,10 @@ include_directories(include)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_GNU_SOURCE -lpthread -Wall")
|
||||
|
||||
link_directories(../../core)
|
||||
link_directories(../../core/shmem_ipc)
|
||||
include_directories(../../core/include/attachments)
|
||||
link_directories(${ng_module_osrc_zlib_path}/lib)
|
||||
link_directories(${CMAKE_BINARY_DIR}/core)
|
||||
link_directories(${CMAKE_BINARY_DIR}/core/shmem_ipc)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/core/include/attachments)
|
||||
|
||||
|
||||
add_library(
|
||||
@ -21,9 +22,10 @@ add_library(
|
||||
nano_attachment_sender.c
|
||||
nano_attachment_sender_thread.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)
|
||||
|
||||
|
72
attachments/nano_attachment/include/mock_nano_compression.h
Executable file
72
attachments/nano_attachment/include/mock_nano_compression.h
Executable 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__
|
@ -15,17 +15,18 @@
|
||||
#include "nano_utils.h"
|
||||
#include "attachment_types.h"
|
||||
#include "nano_blockpage.h"
|
||||
#include "compression_utils.h"
|
||||
#include "nano_compression.h"
|
||||
|
||||
NanoAttachment *
|
||||
InitNanoAttachment(uint8_t attachment_type, int worker_id, int num_of_workers, int logging_fd)
|
||||
{
|
||||
// NanoAttachment *attachment = malloc(sizeof(NanoAttachment));
|
||||
NanoAttachment *attachment = calloc(1, sizeof(NanoAttachment));
|
||||
NanoAttachment *attachment = malloc(sizeof(NanoAttachment));
|
||||
if (attachment == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// memset(attachment, 0, sizeof(NanoAttachment));
|
||||
memset(attachment, 0, sizeof(NanoAttachment));
|
||||
|
||||
attachment->shared_verdict_signal_path[0] = '\0';
|
||||
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_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;
|
||||
};
|
||||
|
||||
@ -153,6 +158,16 @@ FiniSessionData(NanoAttachment *attachment, HttpSessionData *session_data)
|
||||
DBG_LEVEL_DEBUG,
|
||||
"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);
|
||||
};
|
||||
|
||||
@ -208,13 +223,6 @@ SendDataNanoAttachment(NanoAttachment *attachment, AttachmentData *data)
|
||||
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.
|
||||
///
|
||||
@ -587,3 +595,22 @@ FreeAttachmentResponseContent(
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -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__
|
@ -50,6 +50,7 @@ notify_signal_to_service(NanoAttachment *attachment, uint32_t cur_session_id)
|
||||
|
||||
s_poll.fd = attachment->comm_socket;
|
||||
s_poll.events = POLLOUT;
|
||||
s_poll.revents = 0;
|
||||
res = poll(&s_poll, 1, 0);
|
||||
if (res > 0 && s_poll.revents & POLLHUP) {
|
||||
write_dbg(
|
||||
@ -470,7 +471,7 @@ create_modification_node(NanoAttachment *attachment, SessionID session_id, HttpI
|
||||
"Injection position: %d, "
|
||||
"Injection size: %d, "
|
||||
"Original buffer index: %d, "
|
||||
"Data: %s, "
|
||||
"Modification data: %s, "
|
||||
"Should change data: %d",
|
||||
modification_node->modification.is_header,
|
||||
modification_node->modification.injection_pos,
|
||||
@ -513,6 +514,15 @@ handle_inject_response(
|
||||
for (modification_index = 0; modification_index < modification_count; modification_index++) {
|
||||
// Go over the modifications and create nodes.
|
||||
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) {
|
||||
write_dbg(attachment, session_id, DBG_LEVEL_WARNING, "Failed to create modification node");
|
||||
while (*modification_list) {
|
||||
@ -527,6 +537,10 @@ handle_inject_response(
|
||||
*modification_list = new_modification;
|
||||
current_modification = *modification_list;
|
||||
} else {
|
||||
while (*modification_list) {
|
||||
current_modification = *modification_list;
|
||||
*modification_list = (*modification_list)->next;
|
||||
}
|
||||
current_modification->next = new_modification;
|
||||
current_modification = current_modification->next;
|
||||
}
|
||||
|
@ -1,9 +1,64 @@
|
||||
#include "nano_attachment_sender_thread.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "nano_initializer.h"
|
||||
#include "nano_attachment_sender.h"
|
||||
#include "nano_attachment_common.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
|
||||
init_thread_ctx(HttpEventThreadCtx *ctx, NanoAttachment *attachment, AttachmentData *data)
|
||||
@ -133,7 +188,7 @@ SendResponseHeadersThread(void *_ctx)
|
||||
NanoAttachment *attachment = ctx->attachment;
|
||||
HttpSessionData *session_data_p = ctx->session_data_p;
|
||||
HttpHeaders *http_headers = headers->headers;
|
||||
bool is_verdict_requested = false;
|
||||
bool is_verdict_requested = true;
|
||||
|
||||
nano_send_response_code(
|
||||
attachment,
|
||||
@ -151,6 +206,12 @@ SendResponseHeadersThread(void *_ctx)
|
||||
&session_data_p->remaining_messages_to_reply
|
||||
);
|
||||
|
||||
set_response_content_encoding(
|
||||
attachment,
|
||||
session_data_p,
|
||||
http_headers
|
||||
);
|
||||
|
||||
nano_header_sender(
|
||||
attachment,
|
||||
http_headers,
|
||||
|
@ -49,3 +49,9 @@ add_unit_test(
|
||||
"nano_attachment_metrics_ut.cc"
|
||||
"nano_attachment"
|
||||
)
|
||||
|
||||
add_unit_test(
|
||||
nano_compression_ut
|
||||
"nano_compression_ut.cc"
|
||||
"nano_attachment"
|
||||
)
|
||||
|
@ -25,7 +25,6 @@ public:
|
||||
initializer_mocker,
|
||||
nano_attachment_init_process(_)).WillOnce(Return(NanoCommunicationResult::NANO_OK)
|
||||
);
|
||||
setenv("CLOUDGUARD_UID", "Testing", 1);
|
||||
attachment = InitNanoAttachment(
|
||||
static_cast<uint8_t>(AttachmentType::NGINX_ATT_ID),
|
||||
2,
|
||||
@ -67,6 +66,10 @@ public:
|
||||
free(reply_from_service_mock);
|
||||
FiniSessionData(attachment, session_data);
|
||||
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
|
||||
@ -156,6 +159,8 @@ public:
|
||||
HttpWebResponseData *web_response_data;
|
||||
uint32_t reply_session_id = -1;
|
||||
void *reply_session_id_void = &reply_session_id;
|
||||
struct pollfd fds;
|
||||
struct pollfd *mock_fds = &fds;
|
||||
const char **replay_data_mock;
|
||||
|
||||
NanoAttachment *attachment;
|
||||
@ -421,7 +426,17 @@ TEST_F(NanoAttachmentIoTest, NanoBodySender)
|
||||
EXPECT_CALL(
|
||||
mock_nano_poll,
|
||||
poll(_, _, _)
|
||||
).WillRepeatedly(Return(1));
|
||||
).WillRepeatedly(
|
||||
DoAll(
|
||||
SaveArg<0>(&mock_fds),
|
||||
InvokeWithoutArgs(
|
||||
[&] () {
|
||||
mock_fds[0].revents = POLLIN;
|
||||
}
|
||||
),
|
||||
Return(1)
|
||||
)
|
||||
);
|
||||
|
||||
EXPECT_CALL(
|
||||
mock_nano_socket,
|
||||
|
@ -24,7 +24,6 @@ public:
|
||||
).WillOnce(
|
||||
Return(NanoCommunicationResult::NANO_OK)
|
||||
);
|
||||
setenv("CLOUDGUARD_UID", "Testing", 1);
|
||||
attachment = InitNanoAttachment(
|
||||
static_cast<uint8_t>(AttachmentType::NGINX_ATT_ID),
|
||||
2,
|
||||
@ -32,6 +31,7 @@ public:
|
||||
STDOUT_FILENO
|
||||
);
|
||||
EXPECT_NE(attachment, nullptr);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -26,7 +26,6 @@ public:
|
||||
).WillOnce(
|
||||
Return(NanoCommunicationResult::NANO_OK)
|
||||
);
|
||||
setenv("CLOUDGUARD_UID", "Testing", 1);
|
||||
attachment = InitNanoAttachment(
|
||||
static_cast<uint8_t>(AttachmentType::NGINX_ATT_ID),
|
||||
2,
|
||||
|
@ -6,6 +6,7 @@
|
||||
#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"
|
||||
@ -26,7 +27,6 @@ public:
|
||||
).WillOnce(
|
||||
Return(NanoCommunicationResult::NANO_OK)
|
||||
);
|
||||
setenv("CLOUDGUARD_UID", "Testing", 1);
|
||||
attachment = InitNanoAttachment(
|
||||
static_cast<uint8_t>(AttachmentType::NGINX_ATT_ID),
|
||||
2,
|
||||
@ -199,6 +199,7 @@ public:
|
||||
StrictMock<NanoInitializerMocker> initializer_mocker;
|
||||
StrictMock<NanoSocketMocker> socket_mocker;
|
||||
StrictMock<NanoConfigurationMocker> configuration_mocker;
|
||||
StrictMock<NanoCompressionMocker> compression_mocker;
|
||||
};
|
||||
|
||||
TEST_F(NanoAttachmentTest, InitNanoAttachment)
|
||||
@ -450,3 +451,32 @@ TEST_F(NanoAttachmentTest, SendAccumulatedMetricData)
|
||||
EXPECT_CALL(sender_mocker, SendMetricData(attachment)).WillOnce(Return(NanoCommunicationResult::NANO_OK));
|
||||
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);
|
||||
}
|
||||
|
105
attachments/nano_attachment/nano_attachment_ut/nano_compression_ut.cc
Executable file
105
attachments/nano_attachment/nano_attachment_ut/nano_compression_ut.cc
Executable 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);
|
||||
}
|
@ -90,7 +90,6 @@ TEST_F(NanoConfigurationTest, InitAttachmentConfiguration)
|
||||
res = set_logging_fd(&attachment, STDOUT_FILENO);
|
||||
EXPECT_EQ(res, NanoCommunicationResult::NANO_OK);
|
||||
|
||||
setenv("CLOUDGUARD_UID", "Testing", 1);
|
||||
res = set_docker_id(&attachment);
|
||||
EXPECT_EQ(res, NanoCommunicationResult::NANO_OK);
|
||||
|
||||
|
@ -25,7 +25,6 @@ public:
|
||||
).WillOnce(
|
||||
Return(NanoCommunicationResult::NANO_OK)
|
||||
);
|
||||
setenv("CLOUDGUARD_UID", "Testing", 1);
|
||||
attachment = InitNanoAttachment(
|
||||
static_cast<uint8_t>(AttachmentType::NGINX_ATT_ID),
|
||||
2,
|
||||
@ -77,7 +76,7 @@ public:
|
||||
create_nano_str("/dogs.html")
|
||||
};
|
||||
|
||||
HttpHeaderData http_headers[3] = {
|
||||
HttpHeaderData http_headers[4] = {
|
||||
{
|
||||
create_nano_str("Host"),
|
||||
create_nano_str("www.nanoattachmentut.com")
|
||||
@ -89,12 +88,16 @@ public:
|
||||
{
|
||||
create_nano_str("Accept"),
|
||||
create_nano_str("text/html")
|
||||
},
|
||||
{
|
||||
create_nano_str("content-encoding"),
|
||||
create_nano_str("gzip")
|
||||
}
|
||||
};
|
||||
|
||||
HttpHeaders http_headers_data = {
|
||||
http_headers,
|
||||
3
|
||||
4
|
||||
};
|
||||
|
||||
HttpRequestFilterData request_filter_data = {
|
||||
@ -348,12 +351,14 @@ TEST_F(NanoAttachmentSenderThreadTest, SendResponseHeadersThread)
|
||||
AttachmentDataType::RESPONSE_HEADER,
|
||||
session_data->session_id,
|
||||
&session_data->remaining_messages_to_reply,
|
||||
false
|
||||
true
|
||||
)
|
||||
);
|
||||
|
||||
init_thread_ctx(&ctx, attachment, &res_header_data);
|
||||
SendResponseHeadersThread(&ctx);
|
||||
|
||||
EXPECT_EQ(session_data->response_data.compression_type, CompressionType::GZIP);
|
||||
}
|
||||
|
||||
TEST_F(NanoAttachmentSenderThreadTest, SendRequestBodyThread)
|
||||
|
@ -27,7 +27,6 @@ public:
|
||||
).WillOnce(
|
||||
Return(NanoCommunicationResult::NANO_OK)
|
||||
);
|
||||
setenv("CLOUDGUARD_UID", "Testing", 1);
|
||||
attachment = InitNanoAttachment(
|
||||
static_cast<uint8_t>(AttachmentType::NGINX_ATT_ID),
|
||||
2,
|
||||
|
@ -1,3 +1,7 @@
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
|
||||
link_directories(${BOOST_ROOT}/lib)
|
||||
|
||||
add_definitions(-DUSERSPACE)
|
||||
add_library(nano_attachment_util SHARED nano_attachment_util.cc)
|
||||
target_link_libraries(nano_attachment_util http_configuration)
|
||||
|
130
attachments/nano_attachment/nano_compression.c
Executable file
130
attachments/nano_attachment/nano_compression.c
Executable 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);
|
||||
}
|
45
attachments/nano_attachment/nano_compression.h
Executable file
45
attachments/nano_attachment/nano_compression.h
Executable 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__
|
@ -400,7 +400,6 @@ set_docker_id(NanoAttachment *attachment)
|
||||
|
||||
if (!uid_read) {
|
||||
write_dbg(attachment, 0, DBG_LEVEL_WARNING, "Severe error - failed to get uid!");
|
||||
return NANO_ERROR;
|
||||
}
|
||||
|
||||
return NANO_OK;
|
||||
|
@ -1,3 +1,5 @@
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
|
||||
add_library(shmem_ipc_2 SHARED shmem_ipc.c shared_ring_queue.c)
|
||||
|
||||
target_link_libraries(shmem_ipc_2 -lrt)
|
||||
|
Loading…
x
Reference in New Issue
Block a user