Skip to content

Commit

Permalink
encapsulating ICAP request logs
Browse files Browse the repository at this point in the history
  • Loading branch information
MarwanGalal746 committed Oct 30, 2022
1 parent 1dce216 commit 3651f31
Show file tree
Hide file tree
Showing 10 changed files with 255 additions and 207 deletions.
51 changes: 33 additions & 18 deletions api/icap-request.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"icapeg/service/services-utilities/ContentTypes"
"io"
"io/ioutil"
"math/rand"
"net/http"
"strconv"
"strings"
Expand All @@ -29,10 +30,10 @@ type ICAPRequest struct {
serviceName string
methodName string
vendor string
optionsReqHeaders string
optionsRespHeaders string
generalReqHeaders string
generalRespHeaders string
optionsReqHeaders map[string]interface{}
optionsRespHeaders map[string]interface{}
generalReqHeaders map[string]interface{}
generalRespHeaders map[string]interface{}
}

// NewICAPRequest is a func to create a new instance from struct IcapRequest yo handle upcoming ICAP requests
Expand Down Expand Up @@ -155,6 +156,7 @@ func (i *ICAPRequest) RequestProcessing() {
i.optionsReqHeaders = i.LogICAPReqHeaders()
i.optionsMode(i.serviceName)
optionsReqResp := make(map[string]interface{})
optionsReqResp["X-ICAP-Metadata"] = i.generateICAPReqMetaData(utils.ICAPRequestIdLen)
optionsReqResp["ICAP-OPTIONS-Request"] = i.optionsReqHeaders
optionsReqResp["ICAP-OPTIONS-Response"] = i.optionsRespHeaders
jsonHeaders, _ := json.Marshal(optionsReqResp)
Expand Down Expand Up @@ -194,7 +196,8 @@ func (i *ICAPRequest) RespAndReqMods(partial bool) {

logging.Logger.Debug("calling Processing func to process the http message which encapsulated inside the ICAP request")
//calling Processing func to process the http message which encapsulated inside the ICAP request
IcapStatusCode, httpMsg, serviceHeaders, httpMshHeaders := requiredService.Processing(partial)
IcapStatusCode, httpMsg, serviceHeaders, httpMshHeadersBeforeProcessing, httpMshHeadersAfterProcessing,
vendorMsgs := requiredService.Processing(partial)

// adding the headers which the service wants to add them in the ICAP response
logging.Logger.Debug("adding the headers which the service wants to add them in the ICAP response")
Expand Down Expand Up @@ -229,7 +232,7 @@ func (i *ICAPRequest) RespAndReqMods(partial bool) {
} else {
i.req.Response.Body = io.NopCloser(bytes.NewBuffer(httpMsgBody.Bytes()))
}
i.allHeaders(IcapStatusCode, httpMshHeaders)
i.allHeaders(IcapStatusCode, httpMshHeadersBeforeProcessing, httpMshHeadersAfterProcessing, vendorMsgs)
i.RespAndReqMods(false)
case utils.RequestTimeOutStatusCodeStr:
logging.Logger.Debug(i.serviceName + " returned ICAP response with status code " + strconv.Itoa(utils.RequestTimeOutStatusCodeStr))
Expand All @@ -249,12 +252,19 @@ func (i *ICAPRequest) RespAndReqMods(partial bool) {
logging.Logger.Debug(i.serviceName + " returned ICAP response with status code " + strconv.Itoa(utils.BadRequestStatusCodeStr))
i.w.WriteHeader(IcapStatusCode, httpMsg, true)
}
i.allHeaders(IcapStatusCode, httpMshHeaders)
i.allHeaders(IcapStatusCode, httpMshHeadersBeforeProcessing, httpMshHeadersAfterProcessing, vendorMsgs)
}

func (i *ICAPRequest) allHeaders(IcapStatusCode int, httpMshHeaders string) {
func (i *ICAPRequest) allHeaders(IcapStatusCode int, httpMshHeadersBeforeProcessing map[string]interface{},
httpMshHeadersAfterProcessing map[string]interface{}, vendorMsgs map[string]interface{}) {
i.generalRespHeaders = i.LogICAPResHeaders(IcapStatusCode)
generalReqResp := make(map[string]string)
generalReqResp := make(map[string]interface{})
generalReqResp["X-ICAP-Metadata"] = i.generateICAPReqMetaData(utils.ICAPRequestIdLen)
generalReqResp["Vendor-Messages"] = vendorMsgs
i.generalReqHeaders["HTTP-Message"] = httpMshHeadersBeforeProcessing
if IcapStatusCode == utils.OkStatusCodeStr {
i.generalRespHeaders["HTTP-Message"] = httpMshHeadersAfterProcessing
}
if i.methodName == utils.ICAPModeReq {
generalReqResp["ICAP-REQMOD-Request"] = i.generalReqHeaders
generalReqResp["ICAP-REQMOD-Response"] = i.generalRespHeaders
Expand All @@ -263,9 +273,6 @@ func (i *ICAPRequest) allHeaders(IcapStatusCode int, httpMshHeaders string) {
generalReqResp["ICAP-RESPMOD-Request"] = i.generalReqHeaders
generalReqResp["ICAP-RESPMOD-Response"] = i.generalRespHeaders
}
if IcapStatusCode == utils.OkStatusCodeStr {
generalReqResp["HTTP-Headers"] = httpMshHeaders
}
jsonHeaders, _ := json.Marshal(generalReqResp)
final := string(jsonHeaders)
final = strings.ReplaceAll(final, `\`, "")
Expand Down Expand Up @@ -428,7 +435,7 @@ func (i *ICAPRequest) preview() *bytes.Buffer {
return buf
}

func (i *ICAPRequest) LogICAPReqHeaders() string {
func (i *ICAPRequest) LogICAPReqHeaders() map[string]interface{} {
reqHeaders := make(map[string]interface{})
reqHeaders["ICAP-Requested-URL"] = "icap://" + i.req.URL.Host + "/" + i.serviceName
for key, value := range i.req.Header {
Expand All @@ -441,11 +448,10 @@ func (i *ICAPRequest) LogICAPReqHeaders() string {
}
reqHeaders[key] = value
}
jsonHeaders, _ := json.Marshal(reqHeaders)
return string(jsonHeaders)
return reqHeaders
}

func (i *ICAPRequest) LogICAPResHeaders(statusCode int) string {
func (i *ICAPRequest) LogICAPResHeaders(statusCode int) map[string]interface{} {
respHeaders := make(map[string]interface{})
respHeaders["ICAP-Response-Status-Code"] = statusCode
for key, value := range i.h {
Expand All @@ -458,6 +464,15 @@ func (i *ICAPRequest) LogICAPResHeaders(statusCode int) string {
}
respHeaders[key] = value
}
jsonHeaders, _ := json.Marshal(respHeaders)
return string(jsonHeaders)
return respHeaders
}

func (i *ICAPRequest) generateICAPReqMetaData(size int) string {

name := make([]rune, size)
var letterRunes = []rune(utils.IdentifierString)
for i := range name {
name[i] += letterRunes[rand.Intn(len(letterRunes))]
}
return string(name)
}
2 changes: 2 additions & 0 deletions consts/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,6 @@ const (
ErrPageReasonFileRejected = "File rejected"
ErrPageReasonMaxFileExceeded = "The Max file size is exceeded"
ErrPageReasonFileIsNotSafe = "File is not safe"
ICAPRequestIdLen = 20
IdentifierString = "abcdefghijklmnopqrstuvwxyz0123456789"
)
3 changes: 2 additions & 1 deletion service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ const (
type (
// Service holds the info to distinguish a service
Service interface {
Processing(bool) (int, interface{}, map[string]string, string)
Processing(bool) (int, interface{}, map[string]string,
map[string]interface{}, map[string]interface{}, map[string]interface{})
ISTagValue() string
}
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ func (f *GeneralFunc) ShouldUpdateContentLengthAfterPreview(methodName string, f
return false
}
}
func (f *GeneralFunc) LogHTTPMsgHeaders(methodName string) string {
func (f *GeneralFunc) LogHTTPMsgHeaders(methodName string) map[string]interface{} {
msgHeaders := make(map[string]interface{})
if methodName == utils.ICAPModeReq {
for key, value := range f.httpMsg.Request.Header {
Expand All @@ -501,6 +501,5 @@ func (f *GeneralFunc) LogHTTPMsgHeaders(methodName string) string {
msgHeaders[key] = values
}
}
jsonHeaders, _ := json.Marshal(msgHeaders)
return string(jsonHeaders)
return msgHeaders
}
83 changes: 45 additions & 38 deletions service/services/clamav/clamav.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package clamav

import (
"bytes"
"encoding/json"
"github.com/dutchcoders/go-clamd"
"icapeg/consts"
"icapeg/logging"
Expand All @@ -12,27 +11,30 @@ import (
"time"
)

func (c *Clamav) Processing(partial bool) (int, interface{}, map[string]string, string) {
func (c *Clamav) Processing(partial bool) (int, interface{}, map[string]string, map[string]interface{},
map[string]interface{}, map[string]interface{}) {
logging.Logger.Info(c.serviceName + " service has started processing")
serviceHeaders := make(map[string]string)
msgHeadersBeforeProcessing := c.generalFunc.LogHTTPMsgHeaders(c.methodName)
msgHeadersAfterProcessing := make(map[string]interface{})
vendorMsgs := make(map[string]interface{})
// no need to scan part of the file, this service needs all the file at ine time
if partial {
logging.Logger.Info(c.serviceName + " service has stopped processing partially")
return utils.Continue, nil, nil, ""
return utils.Continue, nil, nil, msgHeadersBeforeProcessing, msgHeadersAfterProcessing, vendorMsgs
}

isGzip := false
c.generalFunc.LogHTTPMsgHeaders(c.methodName)
msgHeaders := make(map[string]interface{})
msgHeaders["HTTP-Msg-Before-Processing"] = c.generalFunc.LogHTTPMsgHeaders(c.methodName)
logging.Logger.Info(c.serviceName + " service has started processing")

//extracting the file from http message
file, reqContentType, err := c.generalFunc.CopyingFileToTheBuffer(c.methodName)
if err != nil {
logging.Logger.Error(c.serviceName + " error: " + err.Error())
logging.Logger.Info(c.serviceName + " service has stopped processing")
return utils.InternalServerErrStatusCodeStr, nil, serviceHeaders, ""
return utils.InternalServerErrStatusCodeStr, nil, serviceHeaders, msgHeadersBeforeProcessing,
msgHeadersAfterProcessing, vendorMsgs
}

//getting the extension of the file
Expand Down Expand Up @@ -60,9 +62,9 @@ func (c *Clamav) Processing(partial bool) (int, interface{}, map[string]string,
c.serviceName, c.methodName, ClamavIdentifier, c.httpMsg.Request.RequestURI, reqContentType, file)
if !isProcess {
logging.Logger.Info(c.serviceName + " service has stopped processing")
msgHeaders["HTTP-Msg-After-Processing"] = c.generalFunc.LogHTTPMsgHeaders(c.methodName)
jsonHeaders, _ := json.Marshal(msgHeaders)
return icapStatus, httpMsg, serviceHeaders, string(jsonHeaders)
msgHeadersAfterProcessing = c.generalFunc.LogHTTPMsgHeaders(c.methodName)
return icapStatus, httpMsg, serviceHeaders, msgHeadersBeforeProcessing,
msgHeadersAfterProcessing, vendorMsgs
}

//check if the file size is greater than max file size of the service
Expand All @@ -72,33 +74,35 @@ func (c *Clamav) Processing(partial bool) (int, interface{}, map[string]string,
fileAfterPrep, httpMsg := c.generalFunc.IfStatusIs204WithFile(c.methodName, status, file, isGzip, reqContentType, httpMsg, true)
if fileAfterPrep == nil && httpMsg == nil {
logging.Logger.Info(c.serviceName + " service has stopped processing")
return utils.InternalServerErrStatusCodeStr, nil, serviceHeaders, ""
return utils.InternalServerErrStatusCodeStr, nil, serviceHeaders, msgHeadersBeforeProcessing,
msgHeadersAfterProcessing, vendorMsgs
}
switch msg := httpMsg.(type) {
case *http.Request:
msg.Body = io.NopCloser(bytes.NewBuffer(fileAfterPrep))
logging.Logger.Info(c.serviceName + " service has stopped processing")
msgHeaders["HTTP-Msg-After-Processing"] = c.generalFunc.LogHTTPMsgHeaders(c.methodName)
jsonHeaders, _ := json.Marshal(msgHeaders)
return status, msg, nil, string(jsonHeaders)
msgHeadersAfterProcessing = c.generalFunc.LogHTTPMsgHeaders(c.methodName)
return status, msg, nil, msgHeadersBeforeProcessing,
msgHeadersAfterProcessing, vendorMsgs
case *http.Response:
msg.Body = io.NopCloser(bytes.NewBuffer(fileAfterPrep))
logging.Logger.Info(c.serviceName + " service has stopped processing")
msgHeaders["HTTP-Msg-After-Processing"] = c.generalFunc.LogHTTPMsgHeaders(c.methodName)
jsonHeaders, _ := json.Marshal(msgHeaders)
return status, msg, nil, string(jsonHeaders)
msgHeadersAfterProcessing = c.generalFunc.LogHTTPMsgHeaders(c.methodName)
return status, msg, nil, msgHeadersBeforeProcessing,
msgHeadersAfterProcessing, vendorMsgs
}
msgHeaders["HTTP-Msg-After-Processing"] = c.generalFunc.LogHTTPMsgHeaders(c.methodName)
jsonHeaders, _ := json.Marshal(msgHeaders)
return status, nil, nil, string(jsonHeaders)
msgHeadersAfterProcessing = c.generalFunc.LogHTTPMsgHeaders(c.methodName)
return status, nil, nil, msgHeadersBeforeProcessing,
msgHeadersAfterProcessing, vendorMsgs
}
clmd := clamd.NewClamd(c.SocketPath)
logging.Logger.Debug("sending the HTTP msg body to the ClamAV through antivirus socket")
response, err := clmd.ScanStream(bytes.NewReader(file.Bytes()), make(chan bool))
if err != nil {
logging.Logger.Error(c.serviceName + " error: " + err.Error())
logging.Logger.Info(c.serviceName + " service has stopped processing")
return utils.InternalServerErrStatusCodeStr, nil, serviceHeaders, ""
return utils.InternalServerErrStatusCodeStr, nil, serviceHeaders, msgHeadersBeforeProcessing,
msgHeadersAfterProcessing, vendorMsgs
}

result := &clamd.ScanResult{}
Expand All @@ -116,7 +120,8 @@ func (c *Clamav) Processing(partial bool) (int, interface{}, map[string]string,
if !scanFinished {
logging.Logger.Error(c.serviceName + " error: scanning timeout")
logging.Logger.Info(c.serviceName + " service has stopped processing")
return utils.RequestTimeOutStatusCodeStr, nil, serviceHeaders, ""
return utils.RequestTimeOutStatusCodeStr, nil, serviceHeaders, msgHeadersBeforeProcessing,
msgHeadersAfterProcessing, vendorMsgs
}

if result.Status == ClamavMalStatus {
Expand All @@ -126,18 +131,19 @@ func (c *Clamav) Processing(partial bool) (int, interface{}, map[string]string,
c.httpMsg.Response = c.generalFunc.ErrPageResp(http.StatusForbidden, errPage.Len())
c.httpMsg.Response.Body = io.NopCloser(bytes.NewBuffer(errPage.Bytes()))
logging.Logger.Info(c.serviceName + " service has stopped processing")
msgHeaders["HTTP-Msg-After-Processing"] = c.generalFunc.LogHTTPMsgHeaders(c.methodName)
jsonHeaders, _ := json.Marshal(msgHeaders)
return utils.OkStatusCodeStr, c.httpMsg.Response, serviceHeaders, string(jsonHeaders)
msgHeadersAfterProcessing = c.generalFunc.LogHTTPMsgHeaders(c.methodName)
return utils.OkStatusCodeStr, c.httpMsg.Response, serviceHeaders, msgHeadersBeforeProcessing,
msgHeadersAfterProcessing, vendorMsgs
} else {
htmlPage, req, err := c.generalFunc.ReqModErrPage(utils.ErrPageReasonFileIsNotSafe, c.serviceName, ClamavIdentifier)
if err != nil {
return utils.InternalServerErrStatusCodeStr, nil, nil, ""
return utils.InternalServerErrStatusCodeStr, nil, nil, msgHeadersBeforeProcessing,
msgHeadersAfterProcessing, vendorMsgs
}
req.Body = io.NopCloser(htmlPage)
msgHeaders["HTTP-Msg-After-Processing"] = c.generalFunc.LogHTTPMsgHeaders(c.methodName)
jsonHeaders, _ := json.Marshal(msgHeaders)
return utils.OkStatusCodeStr, req, serviceHeaders, string(jsonHeaders)
msgHeadersAfterProcessing = c.generalFunc.LogHTTPMsgHeaders(c.methodName)
return utils.OkStatusCodeStr, req, serviceHeaders, msgHeadersBeforeProcessing,
msgHeadersAfterProcessing, vendorMsgs
}
}
logging.Logger.Debug(c.serviceName + "File is safe")
Expand All @@ -146,29 +152,30 @@ func (c *Clamav) Processing(partial bool) (int, interface{}, map[string]string,
file, false, reqContentType, c.httpMsg)
if fileAfterPrep == nil && httpMsg == nil {
logging.Logger.Info(c.serviceName + " service has stopped processing")
return utils.InternalServerErrStatusCodeStr, nil, nil, ""
return utils.InternalServerErrStatusCodeStr, nil, nil, msgHeadersBeforeProcessing,
msgHeadersAfterProcessing, vendorMsgs
}

//returning the http message and the ICAP status code
switch msg := httpMsg.(type) {
case *http.Request:
msg.Body = io.NopCloser(bytes.NewBuffer(fileAfterPrep))
logging.Logger.Info(c.serviceName + " service has stopped processing")
msgHeaders["HTTP-Msg-After-Processing"] = c.generalFunc.LogHTTPMsgHeaders(c.methodName)
jsonHeaders, _ := json.Marshal(msgHeaders)
return utils.NoModificationStatusCodeStr, msg, serviceHeaders, string(jsonHeaders)
msgHeadersAfterProcessing = c.generalFunc.LogHTTPMsgHeaders(c.methodName)
return utils.NoModificationStatusCodeStr, msg, serviceHeaders, msgHeadersBeforeProcessing,
msgHeadersAfterProcessing, vendorMsgs
case *http.Response:
msg.Body = io.NopCloser(bytes.NewBuffer(fileAfterPrep))
logging.Logger.Info(c.serviceName + " service has stopped processing")
msgHeaders["HTTP-Msg-After-Processing"] = c.generalFunc.LogHTTPMsgHeaders(c.methodName)
jsonHeaders, _ := json.Marshal(msgHeaders)
return utils.NoModificationStatusCodeStr, msg, serviceHeaders, string(jsonHeaders)
msgHeadersAfterProcessing = c.generalFunc.LogHTTPMsgHeaders(c.methodName)
return utils.NoModificationStatusCodeStr, msg, serviceHeaders, msgHeadersBeforeProcessing,
msgHeadersAfterProcessing, vendorMsgs
}
c.generalFunc.LogHTTPMsgHeaders(c.methodName)
logging.Logger.Info(c.serviceName + " service has stopped processing")
msgHeaders["HTTP-Msg-After-Processing"] = c.generalFunc.LogHTTPMsgHeaders(c.methodName)
jsonHeaders, _ := json.Marshal(msgHeaders)
return utils.NoModificationStatusCodeStr, nil, serviceHeaders, string(jsonHeaders)
msgHeadersAfterProcessing = c.generalFunc.LogHTTPMsgHeaders(c.methodName)
return utils.NoModificationStatusCodeStr, nil, serviceHeaders, msgHeadersBeforeProcessing,
msgHeadersAfterProcessing, vendorMsgs
}

func (c *Clamav) ISTagValue() string {
Expand Down
Loading

0 comments on commit 3651f31

Please sign in to comment.