Skip to content
75 changes: 62 additions & 13 deletions go/src/restincl/workerpool.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ var M_freechan chan int //List of free channels submitted by wokers

var M_ctxs []*atmi.ATMICtx //List of contexts

// Has leading circumflex, but not trailing dollar, because we need first value in X-Forwarded-For header and do not need port number in RemoteAddr.
// Groups order matters (start with longer numbers, otherwise trailing digits are lost).
var M_ipv4AddressRx, _ = regexp.Compile("^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])")

// Generates a file form a Base64 string and writes it to response
func generateFileFromBase64(fileContentsB64 string, tmpFileName string, w http.ResponseWriter) {
decodedFileContent, err := base64.StdEncoding.DecodeString(fileContentsB64)
Expand All @@ -96,6 +100,19 @@ func generateFileFromBase64(fileContentsB64 string, tmpFileName string, w http.R
os.Remove(tmpFileName)
}

// Generates a file from a path and writes it to response
func generateFileFromPath(filePath string) []byte {
// Read file
fileContents, err := os.ReadFile(filePath)
dec64 := base64.StdEncoding.EncodeToString([]byte(fileContents)) // We send files as base64, so we need to encode

if err != nil {
panic(err)
}

return []byte(dec64)
}

//Generate the headers for UBF mode and for EXT mode
//Return content type if available
func genRspHeaders(ac *atmi.ATMICtx, bufu *atmi.TypedUBF, w http.ResponseWriter,
Expand Down Expand Up @@ -379,8 +396,13 @@ func genRsp(ac *atmi.ATMICtx, buf atmi.TypedBuffer, svc *ServiceMap,
var errU atmi.UBFError

rsp, errU = bufu.BGetByteArr(ubftab.EX_IF_RSPDATA, 0)
if svc.Stream {
generateFileFromBase64(string(rsp), "./tempfilename", w)

if bufu.BPres(ubftab.EX_IF_RSPFILEACTION, 0) {
rsp = generateFileFromPath(string(rsp))
} else {
if svc.Stream {
generateFileFromBase64(string(rsp), "./tempfilename", w)
}
}

if nil != errU {
Expand Down Expand Up @@ -691,6 +713,10 @@ func genRsp(ac *atmi.ATMICtx, buf atmi.TypedBuffer, svc *ServiceMap,
header = obj["Header"].(map[string]interface{})
delete(obj, "Header")
}

// Remove address field from response JSON.
delete(obj, "RemoteAddr")

//Add headers to ResponseWriter
for k, v := range header {
for _, val := range v.([]interface{}) {
Expand Down Expand Up @@ -847,21 +873,26 @@ func genRsp(ac *atmi.ATMICtx, buf atmi.TypedBuffer, svc *ServiceMap,
func parseHeaders(ac *atmi.ATMICtx, svc *ServiceMap, req *http.Request,
bufu *atmi.TypedUBF) atmi.UBFError {

if errU := bufu.BAdd(ubftab.EX_NETTHEIRIP, getRemoteAddr(ac, req)); nil != errU {
return errU
}

// Add header data to UBF fields
if svc.Parseheaders {
for k, v := range req.Header {
ac.TpLogDebug("Header field %s, Value %+v", k, v)
hv := fmt.Sprintf("%s", v)
if errU := bufu.BAdd(ubftab.EX_IF_REQHN, k); nil != errU {
return errU
}

if errU := bufu.BAdd(ubftab.EX_IF_REQHV, hv); nil != errU {
return errU
for fld, hdr := range req.Header {
/* Bug #800 had header values with [] */
for _, val := range hdr {
ac.TpLogDebug("Header field %s, Value %s", fld, val)
if errU := bufu.BAdd(ubftab.EX_IF_REQHN, fld); nil != errU {
return errU
}
if errU := bufu.BAdd(ubftab.EX_IF_REQHV, val); nil != errU {
return errU
}
}
// Add Cookies data to UBF
}

// Add Cookies data to UBF
if svc.Parsecookies {
for _, cookie := range req.Cookies() {
// Incoming request have Name and Value
Expand All @@ -880,7 +911,23 @@ func parseHeaders(ac *atmi.ATMICtx, svc *ServiceMap, req *http.Request,
return nil
}

//Common func for parsing query parameters and loading them into UBF buffer
// Returns IPv4 address of client performin request, if available. Empty string otherwise.
func getRemoteAddr(ac *atmi.ATMICtx, req *http.Request) string {
// Add 'proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;' to Nginx site config to have this header (disabled by default).
// Header name casing does not matter.
fwdAddress := req.Header.Get("X-Forwarded-For")
if fwdAddress != "" {
ac.TpLogDebug("Client address connection [%s], forwarded [%s]", req.RemoteAddr, fwdAddress)
// First one is the most external. Separate by ", ", if more than one.
return M_ipv4AddressRx.FindString(fwdAddress)
}

ac.TpLogDebug("Client address connection [%s]", req.RemoteAddr)
// IP:port, we return only IP
return M_ipv4AddressRx.FindString(req.RemoteAddr)
}

// Common func for parsing query parameters and loading them into UBF buffer
func parseQuery(ac *atmi.ATMICtx, svc *ServiceMap, req *http.Request,
bufu *atmi.TypedUBF) atmi.UBFError {

Expand Down Expand Up @@ -1232,6 +1279,8 @@ func handleMessage(ac *atmi.ATMICtx, svc *ServiceMap, w http.ResponseWriter,

// Add header data to UBF fields
if svc.Parseheaders {
obj["RemoteAddr"] = getRemoteAddr(ac, req)

if svc.JsonHeaderField != "" {
obj[svc.JsonHeaderField] = req.Header
} else {
Expand Down