MCPcopy
hub / github.com/netdata/netdata / handler

Function handler

packaging/tools/agent-events/server.go:259–405  ·  view source on GitHub ↗

--- HTTP Handler ---

(w http.ResponseWriter, r *http.Request)

Source from the content-addressed store, hash-verified

257
258// --- HTTP Handler ---
259func handler(w http.ResponseWriter, r *http.Request) {
260 requestStartTime := time.Now()
261 ctx := r.Context()
262
263 defer func() {
264 requestDuration.Record(ctx, time.Since(requestStartTime).Seconds())
265 }()
266
267 // Method Check
268 if r.Method != http.MethodPost {
269 http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
270 slog.Info("request discarded", "reason", "method_not_allowed", "method", r.Method, "remote_addr", r.RemoteAddr)
271 requestsCounter.Add(ctx, 1, metric.WithAttributes(attribute.String("status", "method_not_allowed")))
272 return
273 }
274
275 // Read Body & Size Check
276 r.Body = http.MaxBytesReader(w, r.Body, maxRequestBodySize)
277 body, err := io.ReadAll(r.Body)
278 if err != nil {
279 var maxBytesErr *http.MaxBytesError
280 if errors.As(err, &maxBytesErr) {
281 http.Error(w, fmt.Sprintf("Request body exceeds limit (%d bytes)", maxRequestBodySize), http.StatusRequestEntityTooLarge)
282 slog.Info("request discarded", "reason", "body_too_large", "limit", maxRequestBodySize, "remote_addr", r.RemoteAddr)
283 requestsCounter.Add(ctx, 1, metric.WithAttributes(attribute.String("status", "body_too_large")))
284 } else {
285 http.Error(w, "Error reading request", http.StatusInternalServerError)
286 slog.Error("request discarded", "reason", "error_reading_body", "error", err)
287 requestsCounter.Add(ctx, 1, metric.WithAttributes(attribute.String("status", "failed_to_read")))
288 }
289 return
290 }
291
292 // JSON Validation - Attempt to unmarshal directly to map (requires object)
293 var fullData map[string]interface{}
294 if err := json.Unmarshal(body, &fullData); err != nil {
295 http.Error(w, "Invalid JSON", http.StatusBadRequest)
296 bodyDetail := ""
297 if slog.Default().Enabled(context.Background(), slog.LevelDebug) {
298 bodyDetail = fmt.Sprintf(", Body: %s", string(body))
299 } else {
300 bodyDetail = fmt.Sprintf(", Body snippet: %s", limitString(string(body), 100))
301 }
302 slog.Warn("request discarded", "reason", "invalid_json", "error", err.Error(), "body_detail", bodyDetail)
303 bytesReceived.Add(ctx, int64(len(body)), metric.WithAttributes(attribute.String("status", "invalid_json")))
304 requestsCounter.Add(ctx, 1, metric.WithAttributes(attribute.String("status", "invalid_json")))
305 return
306 }
307
308 bytesReceived.Add(ctx, int64(len(body)), metric.WithAttributes(attribute.String("status", "success")))
309
310 // Add Cloudflare Headers to all requests, excluding IP addresses for GDPR compliance
311 cfHeaders := make(map[string]string)
312 cfHeaderPrefixes := []string{"CF-IPCountry", "CF-Ray", "CF-IPCity", "CF-IPContinent", "CF-IPRegion", "CF-IPTimeZone", "CF-IPCOLO"}
313 // Explicitly excluding IP-related headers: CF-Connecting-IP, CF-IPLatitude, CF-IPLongitude, CF-Visitor
314 for _, name := range cfHeaderPrefixes {
315 if value := r.Header.Get(name); value != "" {
316 key := strings.TrimPrefix(name, "CF-")

Callers 9

__init__Method · 0.85
lookupFunctionMethod · 0.85
WrapHandlerFunction · 0.85
collectSingleMetricMethod · 0.85
collectSingleMetricMethod · 0.85
TestHandlerFunction · 0.85

Calls 10

limitStringFunction · 0.85
checkAndRecordHashFunction · 0.85
InfoMethod · 0.65
AddMethod · 0.65
EnabledMethod · 0.65
GetMethod · 0.65
WriteMethod · 0.65
ErrorMethod · 0.45
StringMethod · 0.45
DebugMethod · 0.45

Tested by 3

TestHandlerFunction · 0.68

Used in the wild real call sites across dependent graphs

searching dependent graphs…