Coverage Report

Created: 2026-08-09 07:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fluent-bit/plugins/in_opentelemetry/opentelemetry_prot.c
Line
Count
Source
1
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*  Fluent Bit
4
 *  ==========
5
 *  Copyright (C) 2015-2026 The Fluent Bit Authors
6
 *
7
 *  Licensed under the Apache License, Version 2.0 (the "License");
8
 *  you may not use this file except in compliance with the License.
9
 *  You may obtain a copy of the License at
10
 *
11
 *      http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 *  Unless required by applicable law or agreed to in writing, software
14
 *  distributed under the License is distributed on an "AS IS" BASIS,
15
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 *  See the License for the specific language governing permissions and
17
 *  limitations under the License.
18
 */
19
20
#include <fluent-bit/flb_input_plugin.h>
21
#include <fluent-bit/flb_version.h>
22
#include <fluent-bit/flb_error.h>
23
#include <fluent-bit/flb_pack.h>
24
#include <fluent-bit/flb_time.h>
25
#include <fluent-bit/flb_gzip.h>
26
#include <fluent-bit/flb_snappy.h>
27
#include <fluent-bit/flb_zstd.h>
28
#include <fluent-bit/flb_mp.h>
29
#include <fluent-bit/flb_log_event_encoder.h>
30
#include <fluent-bit/flb_opentelemetry.h>
31
32
#include <fluent-bit/http_server/flb_http_server.h>
33
34
#include <cmetrics/cmt_decode_opentelemetry.h>
35
#include <cprofiles/cprof_decode_opentelemetry.h>
36
#include <cprofiles/cprof_encode_text.h>
37
38
#include <fluent-otel-proto/fluent-otel.h>
39
40
41
#include "opentelemetry.h"
42
#include "opentelemetry_utils.h"
43
#include "opentelemetry_logs.h"
44
#include "opentelemetry_traces.h"
45
#include "opentelemetry_prot.h"
46
47
#define HTTP_CONTENT_JSON  0
48
49
flb_sds_t opentelemetry_prot_create_request_tag(struct flb_opentelemetry *context,
50
                                                flb_sds_t uri_tag)
51
0
{
52
0
    if (context->ins->tag_default == FLB_FALSE) {
53
0
        return flb_sds_create(context->ins->tag);
54
0
    }
55
56
0
    if (context->tag_from_uri == FLB_TRUE) {
57
0
        return flb_sds_create(uri_tag);
58
0
    }
59
60
0
    return flb_sds_create(context->ins->tag);
61
0
}
62
63
static int is_profiles_export_path(const char *path)
64
0
{
65
0
    if (path == NULL) {
66
0
        return FLB_FALSE;
67
0
    }
68
69
0
    if (strcmp(path, "/opentelemetry.proto.collector.profiles.v1experimental.ProfilesService/Export") == 0 ||
70
0
        strcmp(path, "/opentelemetry.proto.collector.profiles.v1development.ProfilesService/Export") == 0) {
71
0
        return FLB_TRUE;
72
0
    }
73
74
0
    return FLB_FALSE;
75
0
}
76
77
static \
78
int uncompress_zlib(struct flb_opentelemetry *ctx,
79
                    char **output_buffer,
80
                    size_t *output_size,
81
                    char *input_buffer,
82
                    size_t input_size)
83
0
{
84
0
    flb_plg_warn(ctx->ins, "zlib decompression is not supported");
85
0
    return -1;
86
0
}
87
88
static \
89
int uncompress_zstd(struct flb_opentelemetry *ctx,
90
                    char **output_buffer,
91
                    size_t *output_size,
92
                    char *input_buffer,
93
                    size_t input_size)
94
0
{
95
0
    int ret;
96
97
0
    ret = flb_zstd_uncompress(input_buffer,
98
0
                              input_size,
99
0
                              (void *) output_buffer,
100
0
                              output_size);
101
102
0
    if (ret != 0) {
103
0
        flb_plg_error(ctx->ins, "zstd decompression failed");
104
0
        return -1;
105
0
    }
106
107
0
    return 1;
108
0
}
109
110
static \
111
int uncompress_deflate(struct flb_opentelemetry *ctx,
112
                       char **output_buffer,
113
                       size_t *output_size,
114
                       char *input_buffer,
115
                       size_t input_size)
116
0
{
117
0
    flb_plg_warn(ctx->ins, "deflate decompression is not supported");
118
0
    return -1;
119
0
}
120
121
static \
122
int uncompress_snappy(struct flb_opentelemetry *ctx,
123
                      char **output_buffer,
124
                      size_t *output_size,
125
                      char *input_buffer,
126
                      size_t input_size)
127
0
{
128
0
    int ret;
129
130
0
    ret = flb_snappy_uncompress_framed_data(input_buffer,
131
0
                                            input_size,
132
0
                                            output_buffer,
133
0
                                            output_size);
134
135
0
    if (ret != 0) {
136
0
        flb_plg_error(ctx->ins, "snappy decompression failed");
137
0
        return -1;
138
0
    }
139
140
0
    return 1;
141
0
}
142
143
static \
144
int uncompress_gzip(struct flb_opentelemetry *ctx,
145
                    char **output_buffer,
146
                    size_t *output_size,
147
                    char *input_buffer,
148
                    size_t input_size)
149
0
{
150
0
    int ret;
151
152
0
    ret = flb_gzip_uncompress(input_buffer,
153
0
                              input_size,
154
0
                              (void *) output_buffer,
155
0
                              output_size);
156
157
0
    if (ret == -1) {
158
0
        flb_error("[opentelemetry] gzip decompression failed");
159
160
0
        return -1;
161
0
    }
162
163
0
    return 1;
164
0
}
165
166
/*
167
 * We use two backends for HTTP parsing and it depends on the version of the
168
 * protocol:
169
 *
170
 * http/1.x: we use Monkey HTTP parser: struct mk_http_session.parser
171
 * http/2.x: we use nghttp2: struct flb_http_request
172
 *
173
 * based on the protocol version we need to handle the header lookup differently.
174
 */
175
static int http_header_lookup(int version, void *ptr, char *key,
176
                              char **val, size_t *val_len)
177
0
{
178
0
    int key_len;
179
180
    /* HTTP/1.1 */
181
0
    struct mk_list *head;
182
0
    struct mk_http_session *session;
183
0
    struct mk_http_request *request_11;
184
0
    struct mk_http_header *header;
185
186
    /* HTTP/2.0 */
187
0
    char *value;
188
0
    struct flb_http_request *request_20;
189
190
0
    if (!key) {
191
0
        return -1;
192
0
    }
193
194
0
    key_len = strlen(key);
195
0
    if (key_len <= 0) {
196
0
        return -1;
197
0
    }
198
199
0
    if (version <= HTTP_PROTOCOL_VERSION_11) {
200
0
        if (!ptr) {
201
0
            return -1;
202
0
        }
203
204
0
        request_11 = (struct mk_http_request *) ptr;
205
0
        session = request_11->session;
206
0
        mk_list_foreach(head, &session->parser.header_list) {
207
0
            header = mk_list_entry(head, struct mk_http_header, _head);
208
0
            if (header->key.len == key_len &&
209
0
                strncasecmp(header->key.data, key, key_len) == 0) {
210
0
                *val = header->val.data;
211
0
                *val_len = header->val.len;
212
0
                return 0;
213
0
            }
214
0
        }
215
0
        return -1;
216
0
    }
217
0
    else if (version == HTTP_PROTOCOL_VERSION_20) {
218
0
        request_20 = ptr;
219
0
        if (!request_20) {
220
0
            return -1;
221
0
        }
222
223
0
        value = flb_http_request_get_header(request_20, key);
224
0
        if (!value) {
225
0
            return -1;
226
0
        }
227
228
0
        *val = value;
229
0
        *val_len = strlen(value);
230
0
        return 0;
231
0
    }
232
233
0
    return -1;
234
0
}
235
236
/* New gen HTTP server */
237
static int send_response_ng(struct flb_http_response *response,
238
                            int http_status,
239
                            char *message)
240
0
{
241
0
    flb_http_response_set_status(response, http_status);
242
243
0
    if (http_status == 201) {
244
0
        flb_http_response_set_message(response, "Created");
245
0
    }
246
0
    else if (http_status == 200) {
247
0
        flb_http_response_set_message(response, "OK");
248
0
    }
249
0
    else if (http_status == 204) {
250
0
        flb_http_response_set_message(response, "No Content");
251
0
    }
252
0
    else if (http_status == 400) {
253
0
        flb_http_response_set_message(response, "Bad Request");
254
0
    }
255
0
    else if (http_status == 404) {
256
0
        flb_http_response_set_message(response, "Not Found");
257
0
    }
258
259
0
    if (message != NULL) {
260
0
        flb_http_response_set_body(response,
261
0
                                   (unsigned char *) message,
262
0
                                   strlen(message));
263
0
    }
264
265
0
    flb_http_response_commit(response);
266
267
0
    return 0;
268
0
}
269
270
static int send_grpc_response_ng(struct flb_http_response *response,
271
                                 uint8_t *message_buffer,
272
                                 size_t message_length,
273
                                 int grpc_status,
274
                                 char *grpc_message)
275
0
{
276
0
    char      grpc_status_as_string[16];
277
0
    uint32_t  wire_message_length;
278
0
    size_t    body_buffer_size;
279
0
    cfl_sds_t body_buffer;
280
281
0
    body_buffer_size = 5 + message_length;
282
283
0
    if (body_buffer_size < 65) {
284
0
        body_buffer_size = 65;
285
0
    }
286
287
0
    body_buffer = cfl_sds_create_size(body_buffer_size);
288
289
0
    if (body_buffer == NULL) {
290
0
        return -1;
291
0
    }
292
293
0
    sprintf(grpc_status_as_string, "%u", grpc_status);
294
295
0
    wire_message_length = (uint32_t) message_length;
296
297
0
    cfl_sds_cat_safe(&body_buffer, "\x00----", 5);
298
299
0
    ((uint8_t *) body_buffer)[1] = (wire_message_length & 0xFF000000) >> 24;
300
0
    ((uint8_t *) body_buffer)[2] = (wire_message_length & 0x00FF0000) >> 16;
301
0
    ((uint8_t *) body_buffer)[3] = (wire_message_length & 0x0000FF00) >> 8;
302
0
    ((uint8_t *) body_buffer)[4] = (wire_message_length & 0x000000FF) >> 0;
303
304
0
    if (message_buffer != NULL) {
305
0
        cfl_sds_cat_safe(&body_buffer, (char *) message_buffer, message_length);
306
0
    }
307
308
0
    flb_http_response_set_status(response, 200);
309
310
0
    flb_http_response_set_body(response,
311
0
                                (unsigned char *) body_buffer,
312
0
                                5 + message_length);
313
314
0
    flb_http_response_set_header(response,
315
0
                                 "content-type",     0,
316
0
                                 "application/grpc", 0);
317
318
0
    flb_http_response_set_trailer_header(response,
319
0
                                         "grpc-status", 0,
320
0
                                         grpc_status_as_string, 0);
321
322
0
    flb_http_response_set_trailer_header(response,
323
0
                                         "grpc-message", 0,
324
0
                                         grpc_message,   0);
325
326
0
    flb_http_response_commit(response);
327
328
0
    cfl_sds_destroy(body_buffer);
329
330
0
    return 0;
331
0
}
332
333
static int send_grpc_error_response_ng(struct flb_http_response *response,
334
                                       int grpc_status,
335
                                       const char *grpc_message)
336
0
{
337
0
    const char *message;
338
339
0
    message = grpc_message != NULL ? grpc_message : "";
340
341
0
    return send_grpc_response_ng(response, NULL, 0, grpc_status, (char *) message);
342
0
}
343
344
static int send_export_logs_service_response_ng(struct flb_http_response *response,
345
                                                int status)
346
0
{
347
0
    uint8_t                                                             *message_buffer;
348
0
    size_t                                                               message_length;
349
0
    const char                                                          *grpc_message;
350
0
    int                                                                  grpc_status;
351
0
    Opentelemetry__Proto__Collector__Logs__V1__ExportLogsServiceResponse message;
352
353
0
    if (status == 0) {
354
0
        opentelemetry__proto__collector__logs__v1__export_logs_service_response__init(&message);
355
356
0
        message_length = opentelemetry__proto__collector__logs__v1__export_logs_service_response__get_packed_size(&message);
357
358
0
        message_buffer = flb_calloc(message_length, sizeof(uint8_t));
359
0
        if (message_buffer == NULL) {
360
0
            return -1;
361
0
        }
362
363
0
        opentelemetry__proto__collector__logs__v1__export_logs_service_response__pack(&message, message_buffer);
364
365
0
        grpc_status  = 0;
366
0
        grpc_message = "";
367
0
    }
368
0
    else {
369
0
        grpc_status  = 2; /* gRPC UNKNOWN */
370
0
        grpc_message = "Serialization error.";
371
0
        message_buffer = NULL;
372
0
        message_length = 0;
373
0
    }
374
375
0
    send_grpc_response_ng(response, message_buffer, message_length, grpc_status, (char *) grpc_message);
376
377
0
    if (message_buffer != NULL) {
378
0
        flb_free(message_buffer);
379
0
    }
380
381
0
    return 0;
382
0
}
383
384
static int send_export_metrics_service_response_ng(struct flb_http_response *response,
385
                                                   int status)
386
0
{
387
0
    uint8_t                                                                   *message_buffer;
388
0
    size_t                                                                     message_length;
389
0
    const char                                                                *grpc_message;
390
0
    int                                                                        grpc_status;
391
0
    Opentelemetry__Proto__Collector__Metrics__V1__ExportMetricsServiceResponse message;
392
393
0
    if (status == 0) {
394
0
        opentelemetry__proto__collector__metrics__v1__export_metrics_service_response__init(&message);
395
396
0
        message_length = opentelemetry__proto__collector__metrics__v1__export_metrics_service_response__get_packed_size(&message);
397
398
0
        message_buffer = flb_calloc(message_length, sizeof(uint8_t));
399
400
0
        if (message_buffer == NULL) {
401
0
            return -1;
402
0
        }
403
404
0
        opentelemetry__proto__collector__metrics__v1__export_metrics_service_response__pack(&message, message_buffer);
405
406
0
        grpc_status  = 0;
407
0
        grpc_message = "-";
408
0
    }
409
0
    else {
410
0
        grpc_status  = 2; /* gRPC UNKNOWN */
411
0
        grpc_message = "Serialization error.";
412
0
        message_buffer = NULL;
413
0
        message_length = 0;
414
0
    }
415
416
0
    send_grpc_response_ng(response, message_buffer, message_length, grpc_status, (char *) grpc_message);
417
418
0
    if (message_buffer != NULL) {
419
0
        flb_free(message_buffer);
420
0
    }
421
422
0
    return 0;
423
0
}
424
425
static int send_export_traces_service_response_ng(struct flb_http_response *response,
426
                                                  int status)
427
0
{
428
0
    uint8_t                                                               *message_buffer;
429
0
    size_t                                                                 message_length;
430
0
    const char                                                            *grpc_message;
431
0
    int                                                                    grpc_status;
432
0
    Opentelemetry__Proto__Collector__Trace__V1__ExportTraceServiceResponse message;
433
434
0
    if (status == 0) {
435
0
        opentelemetry__proto__collector__trace__v1__export_trace_service_response__init(&message);
436
437
0
        message_length = opentelemetry__proto__collector__trace__v1__export_trace_service_response__get_packed_size(&message);
438
439
0
        message_buffer = flb_calloc(message_length, sizeof(uint8_t));
440
441
0
        if (message_buffer == NULL) {
442
0
            return -1;
443
0
        }
444
445
0
        opentelemetry__proto__collector__trace__v1__export_trace_service_response__pack(&message, message_buffer);
446
447
0
        grpc_status  = 0;
448
0
        grpc_message = "-";
449
0
    }
450
0
    else {
451
0
        grpc_status  = 2; /* gRPC UNKNOWN */
452
0
        grpc_message = "Serialization error.";
453
0
        message_buffer = NULL;
454
0
        message_length = 0;
455
0
    }
456
457
0
    send_grpc_response_ng(response, message_buffer, message_length, grpc_status, (char *) grpc_message);
458
459
0
    if (message_buffer != NULL) {
460
0
        flb_free(message_buffer);
461
0
    }
462
463
0
    return 0;
464
0
}
465
466
static int send_export_profiles_service_response_ng(struct flb_http_response *response,
467
                                                    int status)
468
0
{
469
0
    uint8_t                                                                    *message_buffer;
470
0
    size_t                                                                      message_length;
471
0
    const char                                                                 *grpc_message;
472
0
    int                                                                         grpc_status;
473
0
    Opentelemetry__Proto__Collector__Profiles__V1development__ExportProfilesServiceResponse message;
474
475
0
    if (status == 0) {
476
0
        opentelemetry__proto__collector__profiles__v1development__export_profiles_service_response__init(&message);
477
478
0
        message_length = opentelemetry__proto__collector__profiles__v1development__export_profiles_service_response__get_packed_size(&message);
479
480
0
        message_buffer = flb_calloc(message_length, sizeof(uint8_t));
481
0
        if (message_buffer == NULL) {
482
0
            return -1;
483
0
        }
484
485
0
        opentelemetry__proto__collector__profiles__v1development__export_profiles_service_response__pack(&message, message_buffer);
486
487
0
        grpc_status  = 0;
488
0
        grpc_message = "-";
489
0
    }
490
0
    else {
491
0
        grpc_status  = 2; /* gRPC UNKNOWN */
492
0
        grpc_message = "Serialization error.";
493
0
        message_buffer = NULL;
494
0
        message_length = 0;
495
0
    }
496
497
0
    send_grpc_response_ng(response, message_buffer, message_length, grpc_status, (char *) grpc_message);
498
499
0
    if (message_buffer != NULL) {
500
0
        flb_free(message_buffer);
501
0
    }
502
503
0
    return 0;
504
0
}
505
506
static int process_payload_metrics_ng(struct flb_opentelemetry *ctx,
507
                                      flb_sds_t tag,
508
                                      struct flb_http_request *request,
509
                                      char *payload, size_t payload_size)
510
511
0
{
512
0
    struct cfl_list  decoded_contexts;
513
0
    struct cfl_list *iterator;
514
0
    struct cfl_list *tmp;
515
0
    struct cmt      *context;
516
0
    size_t           offset;
517
0
    int              result = -1;
518
519
0
    offset = 0;
520
521
    /* note: if the content type is gRPC, it was already decoded */
522
0
    if (opentelemetry_is_json_content_type(request->content_type) == FLB_TRUE) {
523
0
        result = flb_opentelemetry_metrics_json_to_cmt(&decoded_contexts,
524
0
                                                       payload,
525
0
                                                       payload_size);
526
0
    }
527
0
    else if (opentelemetry_is_protobuf_content_type(request->content_type) ==
528
0
             FLB_TRUE) {
529
0
        result = cmt_decode_opentelemetry_create(&decoded_contexts,
530
0
                                                 payload,
531
0
                                                 payload_size,
532
0
                                                 &offset);
533
0
    }
534
0
    else {
535
0
        flb_plg_error(ctx->ins, "Unsupported content type %s", request->content_type);
536
0
        return -1;
537
0
    }
538
539
0
    if (result == CMT_DECODE_OPENTELEMETRY_SUCCESS) {
540
0
        if (opentelemetry_uses_worker_ingress_queue(ctx)) {
541
0
            result = flb_input_ingress_queue_metrics_list(ctx->ins,
542
0
                                                          tag,
543
0
                                                          cfl_sds_len(tag),
544
0
                                                          &decoded_contexts,
545
0
                                                          payload_size);
546
0
            if (result == FLB_INPUT_INGRESS_BUSY) {
547
0
                return FLB_INPUT_INGRESS_BUSY;
548
0
            }
549
0
            else if (result != 0) {
550
0
                flb_plg_debug(ctx->ins,
551
0
                              "could not queue metrics contexts : %d", result);
552
0
                return -1;
553
0
            }
554
555
0
            return 0;
556
0
        }
557
558
0
        cfl_list_foreach_safe(iterator, tmp, &decoded_contexts) {
559
0
            context = cfl_list_entry(iterator, struct cmt, _head);
560
561
0
            result = opentelemetry_ingest_metrics(ctx,
562
0
                                                  tag,
563
0
                                                  cfl_sds_len(tag),
564
0
                                                  context,
565
0
                                                  payload_size);
566
567
0
            if (result == FLB_INPUT_INGRESS_BUSY) {
568
0
                cmt_decode_opentelemetry_destroy(&decoded_contexts);
569
0
                return FLB_INPUT_INGRESS_BUSY;
570
0
            }
571
0
            else if (result != 0) {
572
0
                flb_plg_debug(ctx->ins, "could not ingest metrics context : %d", result);
573
0
            }
574
0
        }
575
576
0
        cmt_decode_opentelemetry_destroy(&decoded_contexts);
577
0
    }
578
0
    else {
579
0
        flb_plg_warn(ctx->ins, "non-success cmetrics opentelemetry decode result %d", result);
580
0
        return -1;
581
0
    }
582
583
0
    return 0;
584
0
}
585
586
static int ingest_profiles_context_as_log_entry(struct flb_opentelemetry *ctx,
587
                                                flb_sds_t tag,
588
                                                struct cprof *profiles_context)
589
0
{
590
0
    cfl_sds_t                     text_encoded_profiles_context;
591
0
    struct flb_log_event_encoder *encoder;
592
0
    int                           ret;
593
594
0
    encoder = flb_log_event_encoder_create(FLB_LOG_EVENT_FORMAT_FLUENT_BIT_V2);
595
596
0
    if (encoder == NULL) {
597
0
        return -1;
598
0
    }
599
600
0
    ret = cprof_encode_text_create(&text_encoded_profiles_context,
601
0
                                   profiles_context,
602
0
                                   CPROF_ENCODE_TEXT_RENDER_DICTIONARIES_AND_INDEXES);
603
604
0
    if (ret != CPROF_ENCODE_TEXT_SUCCESS) {
605
0
        flb_log_event_encoder_destroy(encoder);
606
607
0
        return -2;
608
0
    }
609
610
0
    flb_log_event_encoder_begin_record(encoder);
611
612
0
    flb_log_event_encoder_set_current_timestamp(encoder);
613
614
0
    ret = flb_log_event_encoder_append_body_values(
615
0
                encoder,
616
0
                FLB_LOG_EVENT_CSTRING_VALUE("Profile"),
617
0
                FLB_LOG_EVENT_STRING_VALUE(text_encoded_profiles_context,
618
0
                                            cfl_sds_len(text_encoded_profiles_context)));
619
620
0
    cprof_encode_text_destroy(text_encoded_profiles_context);
621
622
0
    if (ret != FLB_EVENT_ENCODER_SUCCESS) {
623
0
        flb_log_event_encoder_destroy(encoder);
624
625
0
        return -3;
626
0
    }
627
628
0
    ret = flb_log_event_encoder_commit_record(encoder);
629
630
0
    if (ret != FLB_EVENT_ENCODER_SUCCESS) {
631
0
        flb_log_event_encoder_destroy(encoder);
632
633
0
        return -4;
634
0
    }
635
636
0
    if (opentelemetry_uses_worker_ingress_queue(ctx)) {
637
0
        size_t allocation_size;
638
0
        void *resized_buffer;
639
640
0
        allocation_size = encoder->buffer.alloc;
641
642
0
        if (allocation_size > encoder->output_length) {
643
0
            resized_buffer = flb_realloc(encoder->output_buffer,
644
0
                                         encoder->output_length);
645
0
            if (resized_buffer != NULL) {
646
0
                encoder->buffer.data = resized_buffer;
647
0
                encoder->output_buffer = resized_buffer;
648
0
                encoder->buffer.alloc = encoder->output_length;
649
0
                allocation_size = encoder->output_length;
650
0
            }
651
0
        }
652
653
0
        ret = opentelemetry_ingest_logs_take(ctx,
654
0
                                             0,
655
0
                                             tag,
656
0
                                             flb_sds_len(tag),
657
0
                                             encoder->output_buffer,
658
0
                                             encoder->output_length,
659
0
                                             allocation_size);
660
0
        flb_log_event_encoder_claim_internal_buffer_ownership(encoder);
661
0
    }
662
0
    else {
663
0
        ret = opentelemetry_ingest_logs(ctx,
664
0
                                        tag,
665
0
                                        flb_sds_len(tag),
666
0
                                        encoder->output_buffer,
667
0
                                        encoder->output_length);
668
0
    }
669
670
0
    flb_log_event_encoder_destroy(encoder);
671
672
0
    if (ret == FLB_INPUT_INGRESS_BUSY) {
673
0
        return FLB_INPUT_INGRESS_BUSY;
674
0
    }
675
676
0
    if (ret != FLB_EVENT_ENCODER_SUCCESS) {
677
0
        return -5;
678
0
    }
679
680
0
    return 0;
681
0
}
682
683
static int process_payload_profiles_ng(struct flb_opentelemetry *ctx,
684
                                       flb_sds_t tag,
685
                                       struct flb_http_request *request,
686
                                       char *payload,
687
                                       size_t payload_size)
688
0
{
689
0
    struct cprof *profiles_context;
690
0
    size_t        offset;
691
0
    int           ret;
692
693
0
    if (request->content_type == NULL) {
694
0
        flb_error("[otel] content type missing");
695
0
        return -1;
696
0
    }
697
0
    else if (opentelemetry_is_json_content_type(request->content_type) == FLB_TRUE) {
698
0
        flb_error("[otel] unsuported profiles encoding type : %s",
699
0
                  request->content_type);
700
701
0
        return -1;
702
0
    }
703
0
    else if (opentelemetry_is_protobuf_content_type(request->content_type) ==
704
0
             FLB_TRUE) {
705
0
        profiles_context = NULL;
706
0
        offset = 0;
707
708
0
        ret = cprof_decode_opentelemetry_create(&profiles_context,
709
0
                                                (uint8_t *) payload,
710
0
                                                payload_size,
711
0
                                                &offset);
712
713
0
        if (ret != CPROF_DECODE_OPENTELEMETRY_SUCCESS) {
714
0
            flb_error("[otel] profile decoding error : %d",
715
0
                      ret);
716
717
0
            return -1;
718
0
        }
719
720
0
        if (ctx->encode_profiles_as_log) {
721
0
            ret = ingest_profiles_context_as_log_entry(ctx,
722
0
                                                       tag,
723
0
                                                       profiles_context);
724
725
0
            cprof_decode_opentelemetry_destroy(profiles_context);
726
0
        }
727
0
        else {
728
0
            ret = opentelemetry_ingest_profiles(ctx,
729
0
                                                tag,
730
0
                                                flb_sds_len(tag),
731
0
                                                profiles_context,
732
0
                                                payload_size);
733
734
0
            if (!opentelemetry_uses_worker_ingress_queue(ctx)) {
735
0
                cprof_decode_opentelemetry_destroy(profiles_context);
736
0
            }
737
0
        }
738
739
0
        if (ret == FLB_INPUT_INGRESS_BUSY) {
740
0
            return ret;
741
0
        }
742
743
0
        if (ret != 0) {
744
0
            flb_error("[otel] profile ingestion error : %d",
745
0
                      ret);
746
747
0
            return -1;
748
0
        }
749
750
0
        ret = 0;
751
0
    }
752
0
    else {
753
0
        flb_plg_error(ctx->ins, "Unsupported content type %s", request->content_type);
754
755
0
        ret = -1;
756
0
    }
757
758
0
    return ret;
759
0
}
760
761
static int send_export_service_response_ng(struct flb_http_response *response,
762
                                           int result,
763
                                           char payload_type)
764
0
{
765
0
    switch (payload_type) {
766
0
    case 'M':
767
0
        return send_export_metrics_service_response_ng(response, result);
768
0
    case 'T':
769
0
        return send_export_traces_service_response_ng(response, result);
770
0
    case 'L':
771
0
        return  send_export_logs_service_response_ng(response, result);
772
0
    case 'P':
773
0
        return send_export_profiles_service_response_ng(response, result);
774
0
    default:
775
0
        return -1;
776
0
    }
777
0
}
778
779
static int send_ingress_busy_response_ng(struct flb_http_response *response,
780
                                         int grpc_request)
781
0
{
782
0
    if (grpc_request == FLB_TRUE) {
783
0
        return send_grpc_error_response_ng(response, 14, "server overloaded");
784
0
    }
785
786
0
    return send_response_ng(response,
787
0
                            503,
788
0
                            "server overloaded: deferred ingress queue is full\n");
789
0
}
790
791
/*
792
 * Protocol handle for requests coming from HTTP/2 server backend. Note that
793
 * if the payload is compressed (Content-Encoding) it will be decompressed
794
 * before this function is called.
795
 *
796
 * For gRPC payloads where the gRPC message is compressed (do not confuse with
797
 * Content-Encoding), each message will be decompressed within this callback.
798
 */
799
int opentelemetry_prot_handle_ng(struct flb_http_request *request,
800
                                 struct flb_http_response *response)
801
0
{
802
0
    int ret = -1;
803
0
    size_t auth_len = 0;
804
0
    int grpc_request = FLB_FALSE;
805
0
    int grpc_uncompressed = FLB_FALSE;
806
0
    size_t grpc_offset = 0;
807
0
    uint64_t  grpc_size = 0;
808
0
    flb_sds_t tag = NULL;
809
0
    char *auth_header = NULL;
810
0
    char payload_type;
811
0
    char *encoding = NULL;
812
0
    size_t encoding_size = 0;
813
0
    char *buf = (char *) request->body;
814
0
    size_t request_body_size = 0;
815
0
    char *payload = NULL;
816
0
    size_t payload_size = 0;
817
0
    size_t max_grpc_size = 16 * 1024 * 1024; /* 16M limit per message */
818
0
    struct flb_opentelemetry *context;
819
820
0
    context = (struct flb_opentelemetry *) response->stream->user_data;
821
822
0
    if (request->path[0] != '/') {
823
0
        send_response_ng(response, 400, "error: invalid request\n");
824
0
        return -1;
825
0
    }
826
827
0
    if (strcmp(request->path, "/v1/metrics") == 0 ||
828
0
        strcmp(request->path, "/v1/traces") == 0  ||
829
0
        strcmp(request->path, "/v1/logs") == 0) {
830
0
        grpc_request = FLB_FALSE;
831
0
    }
832
0
    else if(strcmp(request->path, "/opentelemetry.proto.collector.metrics.v1.MetricsService/Export") == 0 ||
833
0
            strcmp(request->path, "/opentelemetry.proto.collector.traces.v1.TracesService/Export") == 0 ||
834
0
            strcmp(request->path, "/opentelemetry.proto.collector.logs.v1.LogsService/Export") == 0 ||
835
0
            strcmp(request->path, "/opentelemetry.proto.collector.metric.v1.MetricService/Export") == 0 ||
836
0
            strcmp(request->path, "/opentelemetry.proto.collector.trace.v1.TraceService/Export") == 0 ||
837
0
            strcmp(request->path, "/opentelemetry.proto.collector.log.v1.LogService/Export") == 0) {
838
0
        grpc_request = FLB_TRUE;
839
0
    }
840
0
    else if (context->profile_support_enabled &&
841
0
             is_profiles_export_path(request->path) == FLB_TRUE) {
842
0
        grpc_request = FLB_TRUE;
843
0
    }
844
0
    else {
845
0
        send_response_ng(response, 404, "error: invalid endpoint\n");
846
0
        return -1;
847
0
    }
848
849
    /* ToDo: Fix me */
850
    /* HTTP/1.1 needs Host header */
851
0
    if (request->protocol_version == HTTP_PROTOCOL_VERSION_11 &&
852
0
        request->host == NULL) {
853
0
        if (grpc_request) {
854
0
            send_grpc_error_response_ng(response, 3, "missing host header");
855
0
            return -1;
856
0
        }
857
0
        return -1;
858
0
    }
859
860
0
    if (context->oauth2_ctx) {
861
0
        auth_header = flb_http_request_get_header(request, "authorization");
862
0
        if (auth_header != NULL) {
863
0
            auth_len = strlen(auth_header);
864
0
        }
865
866
0
        ret = flb_oauth2_jwt_validate(context->oauth2_ctx, auth_header, auth_len);
867
0
        if (ret != FLB_OAUTH2_JWT_OK) {
868
0
            flb_plg_error(context->ins,
869
0
                          "OAuth2 validation failed: %s (rejecting request with 401)",
870
0
                          flb_oauth2_jwt_status_message(ret));
871
872
0
            if (grpc_request) {
873
0
                send_grpc_error_response_ng(response, 16, "unauthorized");
874
0
            }
875
0
            else {
876
0
                send_response_ng(response, 401, NULL);
877
0
            }
878
879
0
            return -1;
880
0
        }
881
0
    }
882
883
0
    if (request->method != HTTP_METHOD_POST) {
884
0
        if (grpc_request) {
885
0
            send_grpc_error_response_ng(response, 3, "invalid HTTP method");
886
0
        }
887
0
        else {
888
0
            send_response_ng(response, 400, "error: invalid HTTP method\n");
889
0
        }
890
0
        return -1;
891
0
    }
892
893
    /* check content-length */
894
0
    if (request->content_length <= 0) {
895
0
        if (grpc_request) {
896
0
            send_grpc_error_response_ng(response, 3, "invalid content-length");
897
0
        }
898
0
        else {
899
0
            send_response_ng(response, 400, "error: invalid content-length\n");
900
0
        }
901
0
        return -1;
902
0
    }
903
904
0
    if (request->body == NULL) {
905
0
        if (grpc_request) {
906
0
            send_grpc_error_response_ng(response, 3, "invalid payload");
907
0
        }
908
0
        else {
909
0
            send_response_ng(response, 400, "error: invalid payload\n");
910
0
        }
911
0
        return -1;
912
0
    }
913
0
    request_body_size = cfl_sds_len(request->body);
914
915
    /* If this is a gRPC request validate the content-type */
916
0
    if (grpc_request && request->content_type == NULL) {
917
0
        send_grpc_error_response_ng(response, 3, "missing content-type");
918
0
        return -1;
919
0
    }
920
921
    /* Check if the payload is gRPC compressed */
922
0
    if (grpc_request &&
923
0
        opentelemetry_is_grpc_content_type(request->content_type) == FLB_TRUE) {
924
925
0
next_grpc_message:
926
927
0
        if (grpc_offset > request_body_size ||
928
0
            request_body_size - grpc_offset < 5) {
929
0
            send_grpc_error_response_ng(response, 3, "invalid gRPC packet");
930
0
            return -1;
931
0
        }
932
933
        /* gRPC message size */
934
0
        grpc_size = ((uint64_t) (uint8_t) buf[1] << 24) |
935
0
                    ((uint64_t) (uint8_t) buf[2] << 16) |
936
0
                    ((uint64_t) (uint8_t) buf[3] << 8)  |
937
0
                    ((uint64_t) (uint8_t) buf[4]);
938
939
0
        if (grpc_size == 0 || grpc_size > max_grpc_size) {
940
0
            send_grpc_error_response_ng(response, 3, "gRPC message size out of valid range");
941
0
            return -1;
942
0
        }
943
944
0
        if (request_body_size - grpc_offset < grpc_size + 5) {
945
0
            send_grpc_error_response_ng(response, 3, "invalid gRPC packet");
946
0
            return -1;
947
0
        }
948
949
        /* check if the message is compressed */
950
0
        if (buf[0] == 0x1) {
951
            /* get compression type */
952
0
            ret = http_header_lookup(HTTP_PROTOCOL_VERSION_20, request,
953
0
                                     "grpc-encoding", &encoding, &encoding_size);
954
955
            /* malformed gRPC message */
956
0
            if (ret == -1) {
957
0
                send_grpc_error_response_ng(response, 3, "missing gRPC encoding");
958
0
                return -1;
959
0
            }
960
961
            /* buf: skip header */
962
0
            buf += 5;
963
964
0
            if (strncasecmp(encoding, "gzip", 4) == 0 && encoding_size == 4) {
965
0
                ret = uncompress_gzip(context,
966
0
                                      &payload, &payload_size,
967
0
                                      buf, grpc_size);
968
0
            }
969
0
            else if (strncasecmp(encoding, "zlib", 4) == 0 && encoding_size == 4) {
970
0
                ret = uncompress_zlib(context,
971
0
                                      &payload, &payload_size,
972
0
                                      buf, grpc_size);
973
0
            }
974
0
            else if (strncasecmp(encoding, "zstd", 4) == 0 && encoding_size == 4) {
975
0
                ret = uncompress_zstd(context,
976
0
                                      &payload, &payload_size,
977
0
                                      buf, grpc_size);
978
0
            }
979
0
            else if (strncasecmp(encoding, "snappy", 6) == 0 && encoding_size == 6) {
980
0
                ret = uncompress_snappy(context,
981
0
                                        &payload, &payload_size,
982
0
                                        buf, grpc_size);
983
0
            }
984
0
            else if (strncasecmp(encoding, "deflate", 7) == 0 && encoding_size == 7) {
985
0
                ret = uncompress_deflate(context,
986
0
                                        &payload, &payload_size,
987
0
                                        buf, grpc_size);
988
0
            }
989
0
            else {
990
0
                send_grpc_error_response_ng(response, 12, "unsupported gRPC encoding");
991
0
                return -1;
992
0
            }
993
994
0
            if (ret <= 0) {
995
0
                send_grpc_error_response_ng(response, 13, "decompression error");
996
0
                return -1;
997
0
            }
998
999
0
            grpc_uncompressed = FLB_TRUE;
1000
0
        }
1001
0
        else {
1002
            /* uncompressed payload */
1003
0
            payload = buf + 5;
1004
0
            payload_size = grpc_size;
1005
0
            grpc_uncompressed = FLB_FALSE;
1006
0
        }
1007
1008
        /* mark the end of this gRPC message */
1009
0
        grpc_offset += grpc_size + 5;
1010
0
    }
1011
0
    else {
1012
0
        grpc_request = FLB_FALSE;
1013
0
        payload = request->body;
1014
0
        payload_size = cfl_sds_len(request->body);
1015
0
    }
1016
1017
0
    if (strcmp(request->path, "/v1/metrics") == 0 ||
1018
0
        strcmp(request->path, "/opentelemetry.proto.collector.metric.v1.MetricService/Export") == 0 ||
1019
0
        strcmp(request->path, "/opentelemetry.proto.collector.metrics.v1.MetricsService/Export") == 0) {
1020
0
        payload_type = 'M';
1021
0
        tag = opentelemetry_prot_create_request_tag(context, "v1_metrics");
1022
0
        if (tag == NULL) {
1023
0
            ret = -1;
1024
0
            if (grpc_request == FLB_TRUE) {
1025
0
                send_grpc_error_response_ng(response, 13, "internal error");
1026
0
            }
1027
0
            else {
1028
0
                send_response_ng(response, 500, "internal error: cannot allocate request tag\n");
1029
0
            }
1030
0
            goto cleanup;
1031
0
        }
1032
1033
0
        ret = process_payload_metrics_ng(context, tag, request,
1034
0
                                         payload, payload_size);
1035
0
    }
1036
0
    else if (strcmp(request->path, "/v1/traces") == 0 ||
1037
0
             strcmp(request->path, "/opentelemetry.proto.collector.trace.v1.TraceService/Export") == 0 ||
1038
0
             strcmp(request->path, "/opentelemetry.proto.collector.traces.v1.TracesService/Export") == 0) {
1039
0
        payload_type = 'T';
1040
0
        tag = opentelemetry_prot_create_request_tag(context, "v1_traces");
1041
0
        if (tag == NULL) {
1042
0
            ret = -1;
1043
0
            if (grpc_request == FLB_TRUE) {
1044
0
                send_grpc_error_response_ng(response, 13, "internal error");
1045
0
            }
1046
0
            else {
1047
0
                send_response_ng(response, 500, "internal error: cannot allocate request tag\n");
1048
0
            }
1049
0
            goto cleanup;
1050
0
        }
1051
1052
0
        ret = opentelemetry_process_traces(context, request->content_type,
1053
0
                                           tag, flb_sds_len(tag),
1054
0
                                           payload, payload_size);
1055
0
    }
1056
0
    else if (strcmp(request->path, "/v1/logs") == 0 ||
1057
0
             strcmp(request->path, "/opentelemetry.proto.collector.log.v1.LogService/Export") == 0 ||
1058
0
             strcmp(request->path, "/opentelemetry.proto.collector.logs.v1.LogsService/Export") == 0) {
1059
0
        payload_type = 'L';
1060
0
        tag = opentelemetry_prot_create_request_tag(context, "v1_logs");
1061
0
        if (tag == NULL) {
1062
0
            ret = -1;
1063
0
            if (grpc_request == FLB_TRUE) {
1064
0
                send_grpc_error_response_ng(response, 13, "internal error");
1065
0
            }
1066
0
            else {
1067
0
                send_response_ng(response, 500, "internal error: cannot allocate request tag\n");
1068
0
            }
1069
0
            goto cleanup;
1070
0
        }
1071
1072
0
        ret = opentelemetry_process_logs(context, request->content_type, tag, flb_sds_len(tag),
1073
0
                                         payload, payload_size);
1074
0
    }
1075
0
    else if (context->profile_support_enabled &&
1076
0
             is_profiles_export_path(request->path) == FLB_TRUE) {
1077
0
        payload_type = 'P';
1078
0
        tag = opentelemetry_prot_create_request_tag(context, "v1development_profiles");
1079
0
        if (tag == NULL) {
1080
0
            ret = -1;
1081
0
            if (grpc_request == FLB_TRUE) {
1082
0
                send_grpc_error_response_ng(response, 13, "internal error");
1083
0
            }
1084
0
            else {
1085
0
                send_response_ng(response, 500, "internal error: cannot allocate request tag\n");
1086
0
            }
1087
0
            goto cleanup;
1088
0
        }
1089
0
        ret = process_payload_profiles_ng(context, tag, request, payload, payload_size);
1090
0
    }
1091
1092
0
cleanup:
1093
0
    if (grpc_request) {
1094
        /* check if we have uncompressed a gRPC message, if so, release it */
1095
0
        if (grpc_uncompressed == FLB_TRUE) {
1096
0
            flb_free(payload);
1097
0
            grpc_uncompressed = FLB_FALSE;
1098
0
        }
1099
1100
        /* check if we have more gRPC messages to process */
1101
0
        if (grpc_offset < request_body_size) {
1102
0
            buf = (char *) request->body + grpc_offset;
1103
0
            goto next_grpc_message;
1104
0
        }
1105
1106
0
        if (ret == FLB_INPUT_INGRESS_BUSY) {
1107
0
            send_ingress_busy_response_ng(response, grpc_request);
1108
0
        }
1109
0
        else {
1110
0
            send_export_service_response_ng(response, ret, payload_type);
1111
0
        }
1112
0
    }
1113
0
    else {
1114
0
        if (ret == 0) {
1115
0
            send_response_ng(response, context->successful_response_code, NULL);
1116
0
        }
1117
0
        else if (ret == FLB_INPUT_INGRESS_BUSY) {
1118
0
            send_ingress_busy_response_ng(response, grpc_request);
1119
0
        }
1120
0
        else {
1121
0
            send_response_ng(response, 400, "invalid request: deserialisation error\n");
1122
0
        }
1123
0
    }
1124
1125
0
    flb_sds_destroy(tag);
1126
1127
0
    return ret;
1128
0
}