in internal/pkg/api/handleCheckin.go [174:258]
func (ct *CheckinT) validateRequest(zlog zerolog.Logger, w http.ResponseWriter, r *http.Request, start time.Time, agent *model.Agent) (validatedCheckin, error) {
span, ctx := apm.StartSpan(r.Context(), "validateRequest", "validate")
defer span.End()
body := r.Body
// Limit the size of the body to prevent malicious agent from exhausting RAM in server
if ct.cfg.Limits.CheckinLimit.MaxBody > 0 {
body = http.MaxBytesReader(w, body, ct.cfg.Limits.CheckinLimit.MaxBody)
}
readCounter := datacounter.NewReaderCounter(body)
var val validatedCheckin
var req CheckinRequest
decoder := json.NewDecoder(readCounter)
if err := decoder.Decode(&req); err != nil {
return val, &BadRequestErr{msg: "unable to decode checkin request", nextErr: err}
}
cntCheckin.bodyIn.Add(readCounter.Count())
if req.Status == CheckinRequestStatus("") {
return val, &BadRequestErr{msg: "checkin status missing"}
}
if len(req.Message) == 0 {
zlog.Warn().Msg("checkin request method is empty.")
}
var pDur time.Duration
var err error
if req.PollTimeout != nil {
pDur, err = time.ParseDuration(*req.PollTimeout)
if err != nil {
return val, &BadRequestErr{msg: "poll_timeout cannot be parsed as duration", nextErr: err}
}
}
pollDuration := ct.cfg.Timeouts.CheckinLongPoll
// set the pollDuration if pDur parsed from poll_timeout was a non-zero value
// sets timeout is set to max(1m, min(pDur-2m, max poll time))
// sets the response write timeout to max(2m, timeout+1m)
if pDur != time.Duration(0) {
pollDuration = pDur - (2 * time.Minute)
if pollDuration > ct.cfg.Timeouts.CheckinMaxPoll {
pollDuration = ct.cfg.Timeouts.CheckinMaxPoll
}
if pollDuration < time.Minute {
pollDuration = time.Minute
}
wTime := pollDuration + time.Minute
rc := http.NewResponseController(w)
if err := rc.SetWriteDeadline(start.Add(wTime)); err != nil {
zlog.Warn().Err(err).Time("write_deadline", start.Add(wTime)).Msg("Unable to set checkin write deadline.")
} else {
zlog.Trace().Time("write_deadline", start.Add(wTime)).Msg("Request write deadline set.")
}
}
zlog.Trace().Dur("pollDuration", pollDuration).Msg("Request poll duration set.")
// Compare local_metadata content and update if different
rawMeta, err := parseMeta(zlog, agent, &req)
if err != nil {
return val, &BadRequestErr{msg: "unable to parse meta", nextErr: err}
}
// Compare agent_components content and update if different
rawComponents, unhealthyReason, err := parseComponents(zlog, agent, &req)
if err != nil {
return val, err
}
// Resolve AckToken from request, fallback on the agent record
seqno, err := ct.resolveSeqNo(ctx, zlog, req, agent)
if err != nil {
return val, err
}
return validatedCheckin{
req: &req,
dur: pollDuration,
rawMeta: rawMeta,
rawComp: rawComponents,
seqno: seqno,
unhealthyReason: unhealthyReason,
}, nil
}