• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

FluentDo / agent / 20228176797

15 Dec 2025 10:04AM UTC coverage: 56.274% (+0.001%) from 56.273%
20228176797

Pull #164

github

web-flow
Merge d8ab8776e into ef9d95dd0
Pull Request #164: ci: update version

17770 of 33640 branches covered (52.82%)

Branch coverage included in aggregate %.

86713 of 152029 relevant lines covered (57.04%)

5764.62 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

42.9
source/src/flb_http_client.c
1
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2

3
/*  Fluent Bit
4
 *  ==========
5
 *  Copyright (C) 2015-2024 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
/*
21
 * This is a very simple HTTP Client interface which aims to provide an
22
 * easy way to issue HTTP requests and handle reponses from the input/output
23
 * plugins.
24
 *
25
 * It scope is:
26
 *
27
 * - Use upstream connections.
28
 * - Support 'retry' in case the HTTP server timeouts a connection.
29
 * - Get return Status, Headers and Body content if found.
30
 * - If Upstream supports keepalive, adjust headers
31
 */
32

33
#define _GNU_SOURCE
34
#include <string.h>
35

36
#include <fluent-bit/flb_info.h>
37
#include <fluent-bit/flb_kv.h>
38
#include <fluent-bit/flb_log.h>
39
#include <fluent-bit/flb_mem.h>
40
#include <fluent-bit/flb_lock.h>
41
#include <fluent-bit/flb_http_common.h>
42
#include <fluent-bit/flb_http_client.h>
43
#include <fluent-bit/flb_http_client_debug.h>
44
#include <fluent-bit/flb_utils.h>
45
#include <fluent-bit/flb_base64.h>
46
#include <fluent-bit/tls/flb_tls.h>
47
#include <time.h>
48
#include <fluent-bit/flb_signv4_ng.h>
49

50
void flb_http_client_debug(struct flb_http_client *c,
×
51
                           struct flb_callback *cb_ctx)
52
{
53
#ifdef FLB_HAVE_HTTP_CLIENT_DEBUG
54
    if (cb_ctx) {
55
        flb_http_client_debug_enable(c, cb_ctx);
56
    }
57
#endif
58
}
×
59

60
/*
61
 * Removes the port from the host header
62
 */
63
int flb_http_strip_port_from_host(struct flb_http_client *c)
1✔
64
{
65
    struct mk_list *head;
1✔
66
    struct flb_kv *kv;
1✔
67
    char *out_host;
1✔
68
    struct flb_upstream *u;
1✔
69

70
    u = c->u_conn->upstream;
1✔
71

72
    if (!c->host) {
1✔
73
        if (!u->proxied_host) {
×
74
            out_host = u->tcp_host;
×
75
        } else {
76
            out_host = u->proxied_host;
77
        }
78
    } else {
79
        out_host = (char *) c->host;
80
    }
81

82
    mk_list_foreach(head, &c->headers) {
1✔
83
        kv = mk_list_entry(head, struct flb_kv, _head);
1✔
84
        if (strcasecmp("Host", kv->key) == 0) {
1✔
85
            flb_sds_destroy(kv->val);
1✔
86
            kv->val = NULL;
1✔
87
            kv->val = flb_sds_create(out_host);
1✔
88
            if (!kv->val) {
1✔
89
                flb_errno();
×
90
                return -1;
×
91
            }
92
            return 0;
93
        }
94
    }
95

96
    return -1;
97
}
98

99
int flb_http_allow_duplicated_headers(struct flb_http_client *c, int allow)
1✔
100
{
101
    if (allow != FLB_TRUE && allow != FLB_FALSE) {
1✔
102
        return -1;
103
    }
104

105
    c->allow_dup_headers = allow;
1✔
106
    return 0;
1✔
107
}
108

109
/* check if there is enough space in the client header buffer */
110
static int header_available(struct flb_http_client *c, int bytes)
215✔
111
{
112
    int available;
215✔
113

114
    available = c->header_size - c->header_len;
215✔
115
    if (available < bytes) {
215✔
116
        return -1;
×
117
    }
118

119
    return 0;
120
}
121

122
/* Try to find a header value in the buffer */
123
static int header_lookup(struct flb_http_client *c,
107✔
124
                         const char *header, int header_len,
125
                         const char **out_val, int *out_len)
126
{
127
    char *p;
107✔
128
    char *crlf;
107✔
129
    char *end;
107✔
130

131
    if (!c->resp.data) {
107✔
132
        return FLB_HTTP_MORE;
133
    }
134

135
    /* Lookup the beginning of the header */
136
    p = strcasestr(c->resp.data, header);
107✔
137
    end = strstr(c->resp.data, "\r\n\r\n");
107✔
138
    if (!p) {
107✔
139
        if (end) {
59✔
140
            /* The headers are complete but the header is not there */
141
            return FLB_HTTP_NOT_FOUND;
142
        }
143

144
        /* We need more data */
145
        return FLB_HTTP_MORE;
×
146
    }
147

148
    /* Exclude matches in the body */
149
    if (end && p > end) {
48✔
150
        return FLB_HTTP_NOT_FOUND;
151
    }
152

153
    /* Lookup CRLF (end of line \r\n) */
154
    crlf = strstr(p, "\r\n");
48✔
155
    if (!crlf) {
48✔
156
        return FLB_HTTP_MORE;
157
    }
158

159
    p += header_len;
48✔
160

161
    *out_val = p;
48✔
162
    *out_len = (crlf - p);
48✔
163

164
    return FLB_HTTP_OK;
48✔
165
}
166

167
/* HTTP/1.1: Check if we have a Chunked Transfer Encoding */
168
static int check_chunked_encoding(struct flb_http_client *c)
12✔
169
{
170
    int ret;
12✔
171
    int len;
12✔
172
    const char *header = NULL;
12✔
173

174
    ret = header_lookup(c, "Transfer-Encoding: ", 19,
12✔
175
                        &header, &len);
176
    if (ret == FLB_HTTP_NOT_FOUND) {
12✔
177
        /* If the header is missing, this is fine */
178
        c->resp.chunked_encoding = FLB_FALSE;
3✔
179
        return FLB_HTTP_OK;
3✔
180
    }
181
    else if (ret == FLB_HTTP_MORE) {
9✔
182
        return FLB_HTTP_MORE;
183
    }
184

185
    if (strncasecmp(header, "chunked", len) == 0) {
9✔
186
        c->resp.chunked_encoding = FLB_TRUE;
9✔
187
    }
188

189
    return FLB_HTTP_OK;
190
}
191

192
/* Check response for a 'Content-Length' header */
193
static int check_content_length(struct flb_http_client *c)
51✔
194
{
195
    int ret;
51✔
196
    int len;
51✔
197
    const char *header;
51✔
198
    char tmp[256];
51✔
199

200
    if (c->resp.status == 204) {
51✔
201
        c->resp.content_length = -1;
3✔
202
        return FLB_HTTP_OK;
3✔
203
    }
204

205
    ret = header_lookup(c, "Content-Length: ", 16,
48✔
206
                        &header, &len);
207
    if (ret == FLB_HTTP_MORE) {
48✔
208
        return FLB_HTTP_MORE;
209
    }
210
    else if (ret == FLB_HTTP_NOT_FOUND) {
48✔
211
        return FLB_HTTP_NOT_FOUND;
212
    }
213

214
    if (len > sizeof(tmp) - 1) {
39✔
215
        /* Value too long */
216
        return FLB_HTTP_ERROR;
217
    }
218

219
    /* Copy to temporary buffer */
220
    memcpy(tmp, header, len);
39✔
221
    tmp[len] = '\0';
39✔
222

223
    c->resp.content_length = atoi(tmp);
39✔
224
    return FLB_HTTP_OK;
39✔
225
}
226

227
/* Check response for a 'Connection' header */
228
static int check_connection(struct flb_http_client *c)
47✔
229
{
230
    int ret;
47✔
231
    int len;
47✔
232
    const char *header;
47✔
233
    char *buf;
47✔
234

235
    ret = header_lookup(c, "Connection: ", 12,
47✔
236
                        &header, &len);
237
    if (ret == FLB_HTTP_NOT_FOUND) {
47✔
238
        return FLB_HTTP_NOT_FOUND;
239
    }
240
    else if (ret == FLB_HTTP_MORE) {
×
241
        return FLB_HTTP_MORE;
242
    }
243

244
    buf = flb_malloc(len + 1);
×
245
    if (!buf) {
×
246
        flb_errno();
×
247
        return FLB_HTTP_ERROR;
×
248
    }
249

250
    memcpy(buf, header, len);
×
251
    buf[len] = '\0';
×
252

253
    if (strncasecmp(buf, "close", 5) == 0) {
×
254
        c->resp.connection_close = FLB_TRUE;
×
255
    }
256
    else if (strcasestr(buf, "keep-alive")) {
×
257
        c->resp.connection_close = FLB_FALSE;
×
258
    }
259
    flb_free(buf);
×
260
    return FLB_HTTP_OK;
×
261

262
}
263

264
static inline void consume_bytes(char *buf, int bytes, int length)
13✔
265
{
266
    memmove(buf, buf + bytes, length - bytes);
13✔
267
}
268

269
static inline void http_client_response_reset(struct flb_http_client *c)
51✔
270
{
271
    c->resp.data_len = 0;
51✔
272
    c->resp.status = 0;
51✔
273
    c->resp.content_length = -1;
51✔
274
    c->resp.chunked_encoding = FLB_FALSE;
51✔
275
    c->resp.connection_close = -1;
51✔
276
    c->resp.headers_end = NULL;
51✔
277
    c->resp.payload = NULL;
51✔
278
    c->resp.payload_size = 0;
51✔
279
    c->resp.chunk_processed_end = NULL;
51✔
280
}
281

282
static int process_chunked_data(struct flb_http_client *c)
10✔
283
{
284
    long len;
10✔
285
    long drop;
10✔
286
    long val;
10✔
287
    char *p;
10✔
288
    char tmp[32];
10✔
289
    int found_full_chunk = FLB_FALSE;
10✔
290
    struct flb_http_client_response *r = &c->resp;
10✔
291

292

293
 chunk_start:
14✔
294
    p = strstr(r->chunk_processed_end, "\r\n");
14✔
295
    if (!p) {
14✔
296
        return FLB_HTTP_MORE;
297
    }
298

299
    /* Hexa string length */
300
    len = (p - r->chunk_processed_end);
13✔
301
    if ((len > sizeof(tmp) - 1) || len == 0) {
13✔
302
        return FLB_HTTP_ERROR;
303
    }
304
    p += 2;
13✔
305

306
    /* Copy hexa string to temporary buffer */
307
    memcpy(tmp, r->chunk_processed_end, len);
13✔
308
    tmp[len] = '\0';
13✔
309

310
    /* Convert hexa string to decimal */
311
    errno = 0;
13✔
312
    val = strtol(tmp, NULL, 16);
13✔
313
    if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
13✔
314
        || (errno != 0 && val == 0)) {
13✔
315
        flb_errno();
×
316
        return FLB_HTTP_ERROR;
×
317
    }
318
    if (val < 0) {
13✔
319
        return FLB_HTTP_ERROR;
320
    }
321
    /*
322
     * 'val' contains the expected number of bytes, check current lengths
323
     * and do buffer adjustments.
324
     *
325
     * we do val + 2 because the chunk always ends with \r\n
326
     */
327
    val += 2;
13✔
328

329
    /* Number of bytes after the Chunk header */
330
    len = r->data_len - (p - r->data);
13✔
331
    if (len < val) {
13✔
332
        return FLB_HTTP_MORE;
333
    }
334

335
    /* From the current chunk we expect it ends with \r\n */
336
    if (p[val -2] != '\r' || p[val - 1] != '\n') {
13✔
337
        return FLB_HTTP_ERROR;
338
    }
339

340
    /*
341
     * At this point we are just fine, the chunk is valid, next steps:
342
     *
343
     * 1. check possible last chunk
344
     * 2. drop chunk header from the buffer
345
     * 3. remove chunk ending \r\n
346
     */
347

348
    found_full_chunk = FLB_TRUE;
13✔
349
    /* 1. Validate ending chunk */
350
    if (val - 2 == 0) {
13✔
351
        /*
352
         * For an ending chunk we expect:
353
         *
354
         * 0\r\n
355
         * \r\n
356
         *
357
         * so at least we need 5 bytes in the buffer
358
         */
359
        len = r->data_len - (r->chunk_processed_end - r->data);
9✔
360
        if (len < 5) {
9✔
361
            return FLB_HTTP_MORE;
362
        }
363

364
        if (r->chunk_processed_end[3] != '\r' ||
9✔
365
            r->chunk_processed_end[4] != '\n') {
9✔
366
            return FLB_HTTP_ERROR;
367
        }
368
    }
369

370
    /* 2. Drop chunk header */
371
    drop = (p - r->chunk_processed_end);
13✔
372
    len =  r->data_len - (r->chunk_processed_end - r->data);
13✔
373
    consume_bytes(r->chunk_processed_end, drop, len);
13✔
374
    r->data_len -= drop;
13✔
375
    r->data[r->data_len] = '\0';
13✔
376

377
    /* 3. Remove chunk ending \r\n */
378
    drop = 2;
13✔
379
    r->chunk_processed_end += labs(val - 2);
13✔
380
    len = r->data_len - (r->chunk_processed_end - r->data);
13✔
381
    consume_bytes(r->chunk_processed_end, drop, len);
13✔
382
    r->data_len -= drop;
13✔
383

384
    /* Always append a NULL byte */
385
    r->data[r->data_len] = '\0';
13✔
386

387
    /* Always update payload size after full chunk */
388
    r->payload_size = r->data_len - (r->headers_end - r->data);
13✔
389

390
    /* Is this the last chunk ? */
391
    if ((val - 2 == 0)) {
13✔
392
        /* Update payload size */
393
        return FLB_HTTP_OK;
394
    }
395

396
    /* If we have some remaining bytes, start over */
397
    len = r->data_len - (r->chunk_processed_end - r->data);
4✔
398
    if (len > 0) {
4✔
399
        goto chunk_start;
4✔
400
    }
401

402
    if (found_full_chunk == FLB_TRUE) {
403
        return FLB_HTTP_CHUNK_AVAILABLE;
404
    }
405

406
    return FLB_HTTP_MORE;
407
}
408

409
static int process_data(struct flb_http_client *c)
52✔
410
{
411
    int ret;
52✔
412
    char code[4];
52✔
413
    char *tmp;
52✔
414

415
    if (c->resp.data_len < 15) {
52✔
416
        /* we need more data */
417
        return FLB_HTTP_MORE;
418
    }
419

420
    /* HTTP response status */
421
    if (c->resp.status <= 0) {
52✔
422
        memcpy(code, c->resp.data + 9, 3);
51✔
423
        code[3] = '\0';
51✔
424
        c->resp.status = atoi(code);
51✔
425
        if (c->resp.status < 100 || c->resp.status > 599) {
51✔
426
            return FLB_HTTP_ERROR;
427
        }
428
    }
429

430
    /* Try to lookup content length */
431
    if (c->resp.content_length == -1 && c->resp.chunked_encoding == FLB_FALSE) {
52✔
432
        ret = check_content_length(c);
51✔
433
        if (ret == FLB_HTTP_ERROR) {
51✔
434
            return FLB_HTTP_ERROR;
435
        }
436
    }
437

438
    /* Chunked encoding for HTTP/1.1 (no content length of course) */
439
    if ((c->flags & FLB_HTTP_11) && c->resp.content_length == -1) {
52✔
440
        if (c->resp.chunked_encoding == FLB_FALSE) {
13✔
441
            ret = check_chunked_encoding(c);
12✔
442
            if (ret == FLB_HTTP_ERROR) {
12✔
443
                return FLB_HTTP_ERROR;
444
            }
445
        }
446
    }
447

448
    if (!c->resp.headers_end) {
52✔
449
        tmp = strstr(c->resp.data, "\r\n\r\n");
51✔
450
        if (tmp) {
51✔
451
            c->resp.headers_end = tmp + 4;
51✔
452
            if (c->resp.chunked_encoding == FLB_TRUE) {
51✔
453
                c->resp.chunk_processed_end = c->resp.headers_end;
9✔
454
            }
455

456
            /* Mark the payload */
457
            if ((tmp - c->resp.data + 4) < c->resp.data_len) {
51✔
458
                c->resp.payload = tmp += 4;
36✔
459
                c->resp.payload_size = (c->resp.data_len - (tmp - c->resp.data));
36✔
460
            }
461
        }
462
        else {
463
            return FLB_HTTP_MORE;
464
        }
465
    }
466

467
    /* Re-check if an ending exists, if so process payload if required */
468
    if (c->resp.headers_end) {
52✔
469
        /* Mark the payload */
470
        if (!c->resp.payload &&
52✔
471
            c->resp.headers_end - c->resp.data < c->resp.data_len) {
16✔
472
            c->resp.payload = c->resp.headers_end;
1✔
473
            c->resp.payload_size = (c->resp.data_len - (c->resp.headers_end - c->resp.data));
1✔
474
        }
475

476
        if (c->resp.content_length >= 0) {
52✔
477
            c->resp.payload_size = c->resp.data_len;
39✔
478
            c->resp.payload_size -= (c->resp.headers_end - c->resp.data);
39✔
479
            if (c->resp.payload_size >= c->resp.content_length) {
39✔
480
                return FLB_HTTP_OK;
481
            }
482
        }
483
        else if (c->resp.chunked_encoding == FLB_TRUE) {
13✔
484
            ret = process_chunked_data(c);
10✔
485
            if (ret == FLB_HTTP_ERROR) {
10✔
486
                return FLB_HTTP_ERROR;
487
            }
488
            else if (ret == FLB_HTTP_OK || ret == FLB_HTTP_CHUNK_AVAILABLE) {
10✔
489
                return ret;
490
            }
491
        }
492
        else {
493
            return FLB_HTTP_OK;
494
        }
495
    }
496
    else if (c->resp.headers_end && c->resp.content_length <= 0) {
497
        return FLB_HTTP_OK;
498
    }
499

500
    return FLB_HTTP_MORE;
501
}
502

503
#if defined FLB_HAVE_TESTS_OSSFUZZ
504
int fuzz_process_data(struct flb_http_client *c);
505
int fuzz_process_data(struct flb_http_client *c) {
506
        return process_data(c);
507
}
508

509
int fuzz_check_connection(struct flb_http_client *c);
510
int fuzz_check_connection(struct flb_http_client *c) {
511
    return check_connection(c);
512
}
513

514
#endif
515

516
static int proxy_parse(const char *proxy, struct flb_http_client *c)
×
517
{
518
    int len;
×
519
    int port;
×
520
    int off = 0;
×
521
    const char *s;
×
522
    const char *e;
×
523
    const char *host;
×
524

525
    len = strlen(proxy);
×
526
    if (len < 7) {
×
527
        return -1;
528
    }
529

530
    /* Protocol lookup */
531
    if (strncmp(proxy, "http://", 7) == 0) {
×
532
        port = 80;
×
533
        off = 7;
×
534
        c->proxy.type = FLB_HTTP_PROXY_HTTP;
×
535
    }
536
    else if (strncmp(proxy, "https://", 8) == 0) {
×
537
        port = 443;
×
538
        off = 8;
×
539
        c->proxy.type = FLB_HTTP_PROXY_HTTPS;
×
540
    }
541
    else {
542
        return -1;
543
    }
544

545
    /* Separate host/ip from port if any */
546
    s = proxy + off;
×
547
    if (*s == '[') {
×
548
        /* IPv6 address (RFC 3986) */
549
        e = strchr(++s, ']');
×
550
        if (!e) {
×
551
            return -1;
552
        }
553
        host = strndup(s, e - s);
×
554
        s = e + 1;
×
555
    } else {
556
        e = s;
557
        while (!(*e == '\0' || *e == ':' || *e == '/')) {
×
558
            ++e;
×
559
        }
560
        if (e == s) {
×
561
            return -1;
562
        }
563
        host = strndup(s, e - s);
×
564
        s = e;
×
565
    }
566
    if (*s == ':') {
×
567
        port = atoi(++s);
×
568
    }
569

570
    flb_trace("[http_client] proxy type=%i host=%s port=%i",
×
571
              c->proxy.type, host, port);
572

573
    c->proxy.host = host;
×
574
    c->proxy.port = port;
×
575

576
    return 0;
×
577
}
578

579
static int add_host_and_content_length(struct flb_http_client *c)
89✔
580
{
581
    int len;
89✔
582
    flb_sds_t tmp;
89✔
583
    flb_sds_t host;
89✔
584
    char *out_host;
89✔
585
    int out_port;
89✔
586
    size_t size;
89✔
587
    struct flb_upstream *u = c->u_conn->upstream;
89✔
588

589
    if (!c->host) {
89✔
590
        if (u->proxied_host) {
31✔
591
            out_host = u->proxied_host;
592
        }
593
        else {
594
            out_host = u->tcp_host;
31✔
595
        }
596
    }
597
    else {
598
        out_host = (char *) c->host;
599
    }
600

601
    len = strlen(out_host);
89✔
602
    host = flb_sds_create_size(len + 32);
89✔
603
    if (!host) {
89✔
604
        flb_error("[http_client] cannot create temporal buffer");
×
605
        return -1;
×
606
    }
607

608
    if (c->port == 0) {
89✔
609
        if (u->proxied_port != 0 ) {
×
610
            out_port = u->proxied_port;
611
        }
612
        else {
613
            out_port = u->tcp_port;
×
614
        }
615
    }
616
    else {
617
        out_port = c->port;
618
    }
619

620
    if (c->flags & FLB_IO_TLS && out_port == 443) {
89✔
621
        tmp = flb_sds_copy(host, out_host, strlen(out_host));
×
622
    }
623
    else {
624
        tmp = flb_sds_printf(&host, "%s:%i", out_host, out_port);
89✔
625
    }
626

627
    if (!tmp) {
89✔
628
        flb_sds_destroy(host);
×
629
        flb_error("[http_client] cannot compose temporary host header");
×
630
        return -1;
×
631
    }
632
    host = tmp;
89✔
633
    tmp = NULL;
89✔
634

635
    flb_http_add_header(c, "Host", 4, host, flb_sds_len(host));
89✔
636
    flb_sds_destroy(host);
89✔
637

638
    /* Content-Length */
639
    if (c->body_len >= 0) {
89✔
640
        size = 32;
89✔
641
        tmp = flb_malloc(size);
89✔
642
        if (!tmp) {
89✔
643
            flb_errno();
×
644
            return -1;
×
645
        }
646
        len = snprintf(tmp, size - 1, "%i", c->body_len);
89✔
647
        flb_http_add_header(c, "Content-Length", 14, tmp, len);
89✔
648
        flb_free(tmp);
89✔
649
    }
650

651
    return 0;
652
}
653

654
struct flb_http_client *create_http_client(struct flb_connection *u_conn,
92✔
655
                                        int method, const char *uri,
656
                                        const char *body, size_t body_len,
657
                                        const char *host, int port,
658
                                        const char *proxy, int flags)
659
{
660
    int ret;
92✔
661
    char *p;
92✔
662
    char *buf = NULL;
92✔
663
    char *str_method = NULL;
92✔
664
    char *fmt_plain =                           \
92✔
665
        "%s %s HTTP/1.%i\r\n";
666
    char *fmt_proxy =                           \
92✔
667
        "%s http://%s:%i%s HTTP/1.%i\r\n"
668
        "Proxy-Connection: KeepAlive\r\n";
669
    // TODO: IPv6 should have the format of [ip]:port
670
    char *fmt_connect =                           \
92✔
671
        "%s %s:%i HTTP/1.%i\r\n"
672
        "Proxy-Connection: KeepAlive\r\n";
673

674
    struct flb_http_client *c;
92✔
675

676
    switch (method) {
92✔
677
    case FLB_HTTP_GET:
41✔
678
        str_method = "GET";
41✔
679
        break;
41✔
680
    case FLB_HTTP_POST:
51✔
681
        str_method = "POST";
51✔
682
        break;
51✔
683
    case FLB_HTTP_PUT:
×
684
        str_method = "PUT";
×
685
        break;
×
686
    case FLB_HTTP_DELETE:
×
687
        str_method = "DELETE";
×
688
        break;
×
689
    case FLB_HTTP_HEAD:
×
690
        str_method = "HEAD";
×
691
        break;
×
692
    case FLB_HTTP_CONNECT:
×
693
        str_method = "CONNECT";
×
694
        break;
×
695
    case FLB_HTTP_PATCH:
×
696
        str_method = "PATCH";
×
697
        break;
×
698
    };
92✔
699

700
    buf = flb_calloc(1, FLB_HTTP_BUF_SIZE);
92✔
701
    if (!buf) {
92✔
702
        flb_errno();
×
703
        return NULL;
×
704
    }
705

706
    /* FIXME: handler for HTTPS proxy */
707
    if (proxy) {
92✔
708
        flb_debug("[http_client] using http_proxy %s for header", proxy);
×
709
        ret = snprintf(buf, FLB_HTTP_BUF_SIZE,
×
710
                       fmt_proxy,
711
                       str_method,
712
                       host,
713
                       port,
714
                       uri,
715
                       flags & FLB_HTTP_10 ? 0 : 1);
×
716
    }
717
    else if (method == FLB_HTTP_CONNECT) {
92✔
718
        flb_debug("[http_client] using HTTP CONNECT for proxy: proxy host %s, proxy port %i", host, port);
×
719
        ret = snprintf(buf, FLB_HTTP_BUF_SIZE,
×
720
                       fmt_connect,
721
                       str_method,
722
                       host,
723
                       port,
724
                       flags & FLB_HTTP_10 ? 0 : 1);
×
725
    }
726
    else {
727
        flb_debug("[http_client] not using http_proxy for header");
92✔
728
        ret = snprintf(buf, FLB_HTTP_BUF_SIZE,
92✔
729
                       fmt_plain,
730
                       str_method,
731
                       uri,
732
                       flags & FLB_HTTP_10 ? 0 : 1);
92✔
733
    }
734

735
    if (ret == -1) {
92✔
736
        flb_errno();
×
737
        flb_free(buf);
×
738
        return NULL;
×
739
    }
740

741
    c = flb_calloc(1, sizeof(struct flb_http_client));
92✔
742
    if (!c) {
92✔
743
        flb_free(buf);
×
744
        return NULL;
×
745
    }
746

747
    c->u_conn      = u_conn;
92✔
748
    c->method      = method;
92✔
749
    c->uri         = uri;
92✔
750
    c->host        = host;
92✔
751
    c->port        = port;
92✔
752
    c->header_buf  = buf;
92✔
753
    c->header_size = FLB_HTTP_BUF_SIZE;
92✔
754
    c->header_len  = ret;
92✔
755
    c->flags       = flags;
92✔
756
    c->allow_dup_headers = FLB_TRUE;
92✔
757
    mk_list_init(&c->headers);
92✔
758

759
    /* Check if we have a query string */
760
    p = strchr(uri, '?');
92✔
761
    if (p) {
92✔
762
        p++;
12✔
763
        c->query_string = p;
12✔
764
    }
765

766
    /* Response */
767
    c->resp.content_length = -1;
92✔
768
    c->resp.connection_close = -1;
92✔
769

770
    if (body && body_len > 0) {
92✔
771
        c->body_buf = body;
39✔
772
        c->body_len = body_len;
39✔
773
    }
774

775
    /* 'Read' buffer size */
776
    c->resp.data = flb_malloc(FLB_HTTP_DATA_SIZE_MAX);
92✔
777
    if (!c->resp.data) {
92✔
778
        flb_errno();
×
779
        flb_http_client_destroy(c);
×
780
        return NULL;
×
781
    }
782
    c->resp.data[0] = '\0';
92✔
783
    c->resp.data_len  = 0;
92✔
784
    c->resp.data_size = FLB_HTTP_DATA_SIZE_MAX;
92✔
785
    c->resp.data_size_max = FLB_HTTP_DATA_SIZE_MAX;
92✔
786

787
    /* Tests */
788
    c->test_mode = FLB_FALSE;
92✔
789
    c->test_response.callback = NULL;
92✔
790

791
    return c;
92✔
792
}
793

794
struct flb_http_client *flb_http_dummy_client(struct flb_connection *u_conn,
3✔
795
                                              int method, const char *uri,
796
                                              const char *body, size_t body_len,
797
                                              const char *host, int port,
798
                                              const char *proxy, int flags)
799
{
800
    struct flb_http_client *c;
3✔
801

802
    c = create_http_client(u_conn, method, uri,
3✔
803
                           body, body_len,
804
                           host, port,
805
                           proxy, flags);
806

807
    if (!c) {
3✔
808
        return NULL;
809
    }
810

811
    return c;
812
}
813

814
struct flb_http_client *flb_http_client(struct flb_connection *u_conn,
89✔
815
                                        int method, const char *uri,
816
                                        const char *body, size_t body_len,
817
                                        const char *host, int port,
818
                                        const char *proxy, int flags)
819
{
820
    int ret;
89✔
821
    struct flb_http_client *c;
89✔
822

823
    c = create_http_client(u_conn, method, uri,
89✔
824
                           body, body_len,
825
                           host, port,
826
                           proxy, flags);
827

828
    if (!c) {
89✔
829
        return NULL;
830
    }
831

832
    /* Is Upstream connection using keepalive mode ? */
833
    if (flb_stream_get_flag_status(&u_conn->upstream->base, FLB_IO_TCP_KA)) {
89✔
834
        c->flags |= FLB_HTTP_KA;
8✔
835
    }
836

837
    if ((flags & FLB_HTTP_10) == 0) {
89✔
838
        c->flags |= FLB_HTTP_11;
89✔
839
    }
840

841
    ret = add_host_and_content_length(c);
89✔
842
    if (ret != 0) {
89✔
843
        flb_http_client_destroy(c);
×
844
        return NULL;
×
845
    }
846

847
    /* Check proxy data */
848
    if (proxy) {
89✔
849
        flb_debug("[http_client] Using http_proxy: %s", proxy);
×
850
        ret = proxy_parse(proxy, c);
×
851
        if (ret != 0) {
×
852
            flb_debug("[http_client] Something wrong with the http_proxy parsing");
×
853
            flb_http_client_destroy(c);
×
854
            return NULL;
×
855
        }
856
    }
857

858
    return c;
859
}
860

861
/*
862
 * By default the HTTP client have a fixed buffer to read a response for a
863
 * simple request. But in certain situations the caller might expect a
864
 * larger response that exceed the buffer limit.
865
 *
866
 * This function allows to set a maximum buffer size for the client
867
 * response where:
868
 *
869
 *   1. size =  0  no limit, read as much as possible.
870
 *   2. size =  N: specific limit, upon reach limit discard data (default: 4KB)
871
 */
872
int flb_http_buffer_size(struct flb_http_client *c, size_t size)
14✔
873
{
874
    if (size < c->resp.data_size_max && size != 0) {
14✔
875
        flb_error("[http] requested buffer size %lu (bytes) needs to be greater than "
1✔
876
                  "minimum size allowed %lu (bytes)",
877
                  size, c->resp.data_size_max);
878
        return -1;
1✔
879
    }
880

881
    c->resp.data_size_max = size;
13✔
882
    return 0;
13✔
883
}
884

885
size_t flb_http_buffer_available(struct flb_http_client *c)
52✔
886
{
887
    return (c->resp.data_size - c->resp.data_len);
52✔
888
}
889

890
/*
891
 * Increase the read buffer size based on the limits set by default or manually
892
 * through the flb_http_buffer_size() function.
893
 *
894
 * The parameter 'size' is the amount of extra memory requested.
895
 */
896
int flb_http_buffer_increase(struct flb_http_client *c, size_t size,
4✔
897
                             size_t *out_size)
898
{
899
    int off_payload = 0;
4✔
900
    int off_headers_end = 0;
4✔
901
    int off_chunk_processed_end = 0;
4✔
902
    char *tmp;
4✔
903
    size_t new_size;
4✔
904
    size_t allocated;
4✔
905

906
    *out_size = 0;
4✔
907
    new_size = c->resp.data_size + size;
4✔
908

909
    /* Limit exceeded, adjust */
910
    if (c->resp.data_size_max != 0) {
4✔
911
        if (new_size > c->resp.data_size_max) {
2✔
912
            new_size = c->resp.data_size_max;
1✔
913
            if (new_size <= c->resp.data_size) {
1✔
914
                /* Can't expand the buffer any further. */
915
                return -1;
916
            }
917
        }
918
    }
919

920

921
    if (c->resp.headers_end) {
3✔
922
        off_headers_end = c->resp.headers_end - c->resp.data;
×
923
    }
924
    if (c->resp.chunk_processed_end) {
3✔
925
        off_chunk_processed_end = c->resp.chunk_processed_end - c->resp.data;
×
926
    }
927

928
    /*
929
     * The payload is a reference to a position of 'data' buffer,
930
     * we need to adjust the pointer after a memory buffer size change.
931
     */
932
    if (c->resp.payload_size > 0) {
3✔
933
        off_payload = c->resp.payload - c->resp.data;
1✔
934
    }
935

936
    tmp = flb_realloc(c->resp.data, new_size);
3✔
937
    if (!tmp) {
3✔
938
        flb_errno();
×
939
        return -1;
×
940
    }
941
    else {
942
        allocated = new_size - c->resp.data_size;
3✔
943
        c->resp.data = tmp;
3✔
944
        c->resp.data_size = new_size;
3✔
945

946
        if (off_headers_end > 0) {
3✔
947
            c->resp.headers_end = c->resp.data + off_headers_end;
×
948
        }
949
        if (off_chunk_processed_end > 0) {
3✔
950
            c->resp.chunk_processed_end = c->resp.data + off_chunk_processed_end;
×
951
        }
952
        if (off_payload > 0) {
3✔
953
            c->resp.payload = c->resp.data + off_payload;
1✔
954
        }
955
    }
956

957
    *out_size = allocated;
3✔
958
    return 0;
3✔
959
}
960

961

962
/* Append a custom HTTP header to the request */
963
int flb_http_add_header(struct flb_http_client *c,
355✔
964
                        const char *key, size_t key_len,
965
                        const char *val, size_t val_len)
966
{
967
    struct flb_kv *kv;
355✔
968
    struct mk_list *tmp;
355✔
969
    struct mk_list *head;
355✔
970

971
    if (key_len < 1 || val_len < 1) {
355✔
972
        return -1;
973
    }
974

975
    /* Check any previous header to avoid duplicates */
976
    if (c->allow_dup_headers == FLB_FALSE) {
355✔
977
        mk_list_foreach_safe(head, tmp, &c->headers) {
×
978
            kv = mk_list_entry(head, struct flb_kv, _head);
×
979
            if (flb_sds_casecmp(kv->key, key, key_len) == 0) {
×
980
                /* the header already exists, remove it */
981
                flb_kv_item_destroy(kv);
×
982
                break;
×
983
            }
984
        }
985
    }
986

987
    /* register new header in the temporal kv list */
988
    kv = flb_kv_item_create_len(&c->headers,
355✔
989
                                (char *) key, key_len, (char *) val, val_len);
990
    if (!kv) {
355✔
991
        return -1;
992
    }
993

994
    return 0;
995
}
996

997
/*
998
 * flb_http_get_header looks up a first value of request header.
999
 * The return value should be destroyed after using.
1000
 * The return value is NULL, if the value is not found.
1001
 */
1002
flb_sds_t flb_http_get_header(struct flb_http_client *c,
11✔
1003
                              const char *key, size_t key_len)
1004
{
1005
    flb_sds_t ret_str;
11✔
1006
    struct flb_kv *kv;
11✔
1007
    struct mk_list *head = NULL;
11✔
1008
    struct mk_list *tmp  = NULL;
11✔
1009

1010
    mk_list_foreach_safe(head, tmp, &c->headers) {
27✔
1011
        kv = mk_list_entry(head, struct flb_kv, _head);
24✔
1012
        if (flb_sds_casecmp(kv->key, key, key_len) == 0) {
24✔
1013
            ret_str = flb_sds_create(kv->val);
8✔
1014
            return ret_str;
8✔
1015
        }
1016
    }
1017

1018
    return NULL;
1019
}
1020

1021
static int http_header_push(struct flb_http_client *c, struct flb_kv *header)
164✔
1022
{
1023
    char *tmp;
164✔
1024
    const char *key;
164✔
1025
    const char *val;
164✔
1026
    size_t key_len;
164✔
1027
    size_t val_len;
164✔
1028
    size_t required;
164✔
1029
    size_t new_size;
164✔
1030

1031
    key = header->key;
164✔
1032
    key_len = flb_sds_len(header->key);
164✔
1033
    val = header->val;
164✔
1034
    val_len = flb_sds_len(header->val);
164✔
1035

1036
    /*
1037
     * The new header will need enough space in the buffer:
1038
     *
1039
     * key      : length of the key
1040
     * separator: ': ' (2 bytes)
1041
     * val      : length of the key value
1042
     * CRLF     : '\r\n' (2 bytes)
1043
     */
1044
    required = key_len + 2 + val_len + 2;
164✔
1045

1046
    if (header_available(c, required) != 0) {
164✔
1047
        if (required < 512) {
×
1048
            new_size = c->header_size + 512;
×
1049
        }
1050
        else {
1051
            new_size = c->header_size + required;
×
1052
        }
1053
        tmp = flb_realloc(c->header_buf, new_size);
×
1054
        if (!tmp) {
×
1055
            flb_errno();
×
1056
            return -1;
×
1057
        }
1058
        c->header_buf  = tmp;
×
1059
        c->header_size = new_size;
×
1060
    }
1061

1062
    /* append the header key */
1063
    memcpy(c->header_buf + c->header_len,
164✔
1064
           key, key_len);
1065
    c->header_len += key_len;
164✔
1066

1067
    /* append the separator */
1068
    c->header_buf[c->header_len++] = ':';
164✔
1069
    c->header_buf[c->header_len++] = ' ';
164✔
1070

1071
    /* append the header value */
1072
    memcpy(c->header_buf + c->header_len,
164✔
1073
           val, val_len);
1074
    c->header_len += val_len;
164✔
1075

1076
    /* Append the ending header CRLF */
1077
    c->header_buf[c->header_len++] = '\r';
164✔
1078
    c->header_buf[c->header_len++] = '\n';
164✔
1079

1080
    return 0;
164✔
1081
}
1082

1083
static int http_headers_compose(struct flb_http_client *c)
51✔
1084
{
1085
    int ret;
51✔
1086
    struct mk_list *head;
51✔
1087
    struct flb_kv *header;
51✔
1088

1089
    /* Push header list to one buffer */
1090
    mk_list_foreach(head, &c->headers) {
215✔
1091
        header = mk_list_entry(head, struct flb_kv, _head);
164✔
1092
        ret = http_header_push(c, header);
164✔
1093
        if (ret != 0) {
164✔
1094
            flb_error("[http_client] cannot compose request headers");
×
1095
            return -1;
×
1096
        }
1097
    }
1098

1099
    return 0;
1100
}
1101

1102
static void http_headers_destroy(struct flb_http_client *c)
301✔
1103
{
1104
    flb_kv_release(&c->headers);
301✔
1105
}
1106

1107
int flb_http_set_keepalive(struct flb_http_client *c)
52✔
1108
{
1109
    /* check if 'keepalive' mode is enabled in the Upstream connection */
1110
    if (flb_stream_is_keepalive(c->u_conn->stream) == FLB_FALSE) {
52✔
1111
        return -1;
1112
    }
1113

1114
    /* append header */
1115
    return flb_http_add_header(c,
2✔
1116
                               FLB_HTTP_HEADER_CONNECTION,
1117
                               sizeof(FLB_HTTP_HEADER_CONNECTION) - 1,
1118
                               FLB_HTTP_HEADER_KA,
1119
                               sizeof(FLB_HTTP_HEADER_KA) - 1);
1120
}
1121

1122
/* Adds a header specifying that the payload is compressed with gzip */
1123
int flb_http_set_content_encoding_gzip(struct flb_http_client *c)
1✔
1124
{
1125
    int ret;
1✔
1126

1127
    ret = flb_http_add_header(c,
1✔
1128
                              FLB_HTTP_HEADER_CONTENT_ENCODING,
1129
                              sizeof(FLB_HTTP_HEADER_CONTENT_ENCODING) - 1,
1130
                              "gzip", 4);
1131
    return ret;
1✔
1132
}
1133

1134
int flb_http_set_content_encoding_zstd(struct flb_http_client *c)
×
1135
{
1136
    int ret;
×
1137

1138
    ret = flb_http_add_header(c,
×
1139
                              FLB_HTTP_HEADER_CONTENT_ENCODING,
1140
                              sizeof(FLB_HTTP_HEADER_CONTENT_ENCODING) - 1,
1141
                              "zstd", 4);
1142
    return ret;
×
1143
}
1144

1145
int flb_http_set_content_encoding_snappy(struct flb_http_client *c)
×
1146
{
1147
    int ret;
×
1148

1149
    ret = flb_http_add_header(c,
×
1150
                              FLB_HTTP_HEADER_CONTENT_ENCODING,
1151
                              sizeof(FLB_HTTP_HEADER_CONTENT_ENCODING) - 1,
1152
                              "snappy", 6);
1153
    return ret;
×
1154
}
1155

1156
int flb_http_set_read_idle_timeout(struct flb_http_client *c, int timeout)
1✔
1157
{
1158
    c->read_idle_timeout = timeout;
1✔
1159
    return 0;
1✔
1160
}
1161

1162
int flb_http_set_response_timeout(struct flb_http_client *c, int timeout)
1✔
1163
{
1164
    c->response_timeout = timeout;
1✔
1165
    return 0;
1✔
1166
}
1167

1168
int flb_http_set_callback_context(struct flb_http_client *c,
×
1169
                                  struct flb_callback *cb_ctx)
1170
{
1171
    c->cb_ctx = cb_ctx;
×
1172
    return 0;
×
1173
}
1174

1175
int flb_http_set_response_test(struct flb_http_client *c, char *test_name,
3✔
1176
                               const void *data, size_t len,
1177
                               int status,
1178
                               void (*resp_callback) (void *, int, void *, size_t, void *),
1179
                               void *resp_callback_data)
1180
{
1181
    if (!c) {
3✔
1182
        return -1;
1183
    }
1184

1185
    /*
1186
     * Enabling a test, set the http_client instance in 'test' mode, so no real
1187
     * http request is invoked, only the desired implemented test.
1188
     */
1189

1190
    /* Response test */
1191
    if (strcmp(test_name, "response") == 0) {
3✔
1192
        c->test_mode = FLB_TRUE;
3✔
1193
        c->test_response.rt_ctx = c;
3✔
1194
        c->test_response.rt_status = status;
3✔
1195
        c->test_response.rt_resp_callback = resp_callback;
3✔
1196
        c->test_response.rt_data = resp_callback_data;
3✔
1197
        if (data != NULL && len > 0) {
3✔
1198
            c->resp.payload = (char *)data;
3✔
1199
            c->resp.payload_size = len;
3✔
1200
            c->resp.status = status;
3✔
1201
        }
1202
    }
1203
    else {
1204
        return -1;
1205
    }
1206

1207
    return 0;
1208
}
1209

1210
static int flb_http_run_response_test(struct flb_http_client *c,
×
1211
                                      const void *data, size_t len)
1212
{
1213
    int ret = 0;
×
1214
    void *out_buf = NULL;
×
1215
    size_t out_size = 0;
×
1216
    struct flb_test_http_response  *htr;
×
1217

1218
    if (!c) {
×
1219
        return -1;
1220
    }
1221

1222
    htr = &c->test_response;
×
1223

1224
    /* Invoke the output plugin formatter test callback */
1225
    ret = htr->callback(c,
×
1226
                        data, len,
1227
                        &out_buf, &out_size);
1228

1229
    /* Call the runtime test callback checker */
1230
    if (htr->rt_resp_callback) {
×
1231
        htr->rt_resp_callback(htr->rt_ctx,
×
1232
                              ret,
1233
                              out_buf, out_size,
1234
                              htr->rt_data);
1235
    }
1236
    else {
1237
        flb_free(out_buf);
×
1238
    }
1239

1240
    return 0;
1241
}
1242

1243
/* Push some response into the http client */
1244
static int flb_http_stub_response(struct flb_http_client *c)
3✔
1245
{
1246
    int ret = 0;
3✔
1247

1248
    if (!c) {
3✔
1249
        return -1;
1250
    }
1251

1252
    /* If http client's test_responses is registered, run the stub. */
1253
    if (c->test_response.callback != NULL && c->resp.payload != NULL) {
3✔
1254
        ret = flb_http_run_response_test(c, c->resp.payload, c->resp.payload_size);
×
1255
    }
1256

1257
    return ret;
1258
}
1259

1260
int flb_http_add_auth_header(struct flb_http_client *c,
2✔
1261
                             const char *user, const char *passwd, const char *header) {
1262
    int ret;
2✔
1263
    int len_u;
2✔
1264
    int len_p;
2✔
1265
    int len_h;
2✔
1266
    int len_out;
2✔
1267
    char tmp[1024];
2✔
1268
    char *p;
2✔
1269
    size_t b64_len;
2✔
1270

1271
    /*
1272
     * We allow a max of 255 bytes for user and password (255 each), meaning
1273
     * we need at least:
1274
     *
1275
     * 'Basic base64(user : passwd)' => ~688 bytes
1276
     *
1277
     */
1278

1279
    len_u = strlen(user);
2✔
1280

1281
    if (passwd) {
2✔
1282
        len_p = strlen(passwd);
2✔
1283
    }
1284
    else {
1285
        len_p = 0;
1286
    }
1287

1288
    p = flb_malloc(len_u + len_p + 2);
2✔
1289
    if (!p) {
2✔
1290
        flb_errno();
×
1291
        return -1;
×
1292
    }
1293

1294
    memcpy(p, user, len_u);
2✔
1295
    p[len_u] = ':';
2✔
1296
    len_out = len_u + 1;
2✔
1297

1298
    if (passwd) {
2✔
1299
        memcpy(p + len_out, passwd, len_p);
2✔
1300
        len_out += len_p;
2✔
1301
    }
1302
    p[len_out] = '\0';
2✔
1303

1304
    memcpy(tmp, "Basic ", 6);
2✔
1305
    ret = flb_base64_encode((unsigned char *) tmp + 6, sizeof(tmp) - 7, &b64_len,
2✔
1306
                                (unsigned char *) p, len_out);
1307
    if (ret != 0) {
2✔
1308
        flb_free(p);
×
1309
        return -1;
×
1310
    }
1311

1312
    flb_free(p);
2✔
1313
    b64_len += 6;
2✔
1314

1315
    len_h = strlen(header);
2✔
1316
    ret = flb_http_add_header(c,
2✔
1317
                              header,
1318
                              len_h,
1319
                              tmp, b64_len);
1320
    return ret;
2✔
1321
}
1322

1323
int flb_http_basic_auth(struct flb_http_client *c,
1✔
1324
                        const char *user, const char *passwd)
1325
{
1326
    return flb_http_add_auth_header(c, user, passwd, FLB_HTTP_HEADER_AUTH);
1✔
1327
}
1328

1329
int flb_http_proxy_auth(struct flb_http_client *c,
1✔
1330
                        const char *user, const char *passwd)
1331
{
1332
    return flb_http_add_auth_header(c, user, passwd, FLB_HTTP_HEADER_PROXY_AUTH);
1✔
1333
}
1334

1335
int flb_http_bearer_auth(struct flb_http_client *c, const char *token)
×
1336
{
1337
    flb_sds_t header_buffer;
×
1338
    flb_sds_t header_line;
×
1339
    int       result;
×
1340

1341
    result = -1;
×
1342

1343
    if (token == NULL) {
×
1344
        token = "";
×
1345

1346
        /* Shouldn't we log this and return instead of sending
1347
         * a malformed value?
1348
         */
1349
    }
1350

1351
    header_buffer = flb_sds_create_size(strlen(token) + 64);
×
1352

1353
    if (header_buffer == NULL) {
×
1354
        return -1;
1355
    }
1356

1357
    header_line = flb_sds_printf(&header_buffer, "Bearer %s", token);
×
1358

1359
    if (header_line != NULL) {
×
1360
        result = flb_http_add_header(c,
×
1361
                                     FLB_HTTP_HEADER_AUTH,
1362
                                     strlen(FLB_HTTP_HEADER_AUTH),
1363
                                     header_line,
1364
                                     flb_sds_len(header_line));
1365
    }
1366

1367
    flb_sds_destroy(header_buffer);
×
1368

1369
    return result;
×
1370
}
1371

1372
/* flb_http_do_request only sends the http request the data.
1373
*  This is useful for processing the chunked responses on your own.
1374
*  If you do not want to process the response on your own or expect
1375
*  all response data before you process data, use flb_http_do instead.
1376
*/
1377
int flb_http_do_request(struct flb_http_client *c, size_t *bytes)
51✔
1378
{
1379
    int ret;
51✔
1380
    int crlf = 2;
51✔
1381
    int new_size;
51✔
1382
    size_t bytes_header = 0;
51✔
1383
    size_t bytes_body = 0;
51✔
1384
    char *tmp;
51✔
1385

1386
    /* Try to add keep alive header */
1387
    flb_http_set_keepalive(c);
51✔
1388

1389
    /* Append pending headers */
1390
    ret = http_headers_compose(c);
51✔
1391
    if (ret == -1) {
51✔
1392
        return FLB_HTTP_ERROR;
1393
    }
1394

1395
    /* check enough space for the ending CRLF */
1396
    if (header_available(c, crlf) != 0) {
51✔
1397
        new_size = c->header_size + 2;
×
1398
        tmp = flb_realloc(c->header_buf, new_size);
×
1399
        if (!tmp) {
×
1400
            flb_errno();
×
1401
            return FLB_HTTP_ERROR;
×
1402
        }
1403
        c->header_buf  = tmp;
×
1404
        c->header_size = new_size;
×
1405
    }
1406

1407
    /* Append the ending header CRLF */
1408
    c->header_buf[c->header_len++] = '\r';
51✔
1409
    c->header_buf[c->header_len++] = '\n';
51✔
1410

1411
#ifdef FLB_HAVE_HTTP_CLIENT_DEBUG
1412
    /* debug: request_headers callback */
1413
    flb_http_client_debug_cb(c, "_debug.http.request_headers");
1414

1415
    /* debug: request_payload callback */
1416
    if (c->body_len > 0) {
1417
        flb_http_client_debug_cb(c, "_debug.http.request_payload");
1418
    }
1419
#endif
1420

1421
    /* Write the header */
1422
    ret = flb_io_net_write(c->u_conn,
102✔
1423
                           c->header_buf, c->header_len,
51✔
1424
                           &bytes_header);
1425
    if (ret == -1) {
51✔
1426
        /* errno might be changed from the original call */
1427
        if (errno != 0) {
×
1428
            flb_errno();
×
1429
        }
1430
        return FLB_HTTP_ERROR;
×
1431
    }
1432

1433
    if (c->body_len > 0) {
51✔
1434
        ret = flb_io_net_write(c->u_conn,
76✔
1435
                               c->body_buf, c->body_len,
38✔
1436
                               &bytes_body);
1437
        if (ret == -1) {
38✔
1438
            flb_errno();
×
1439
            return FLB_HTTP_ERROR;
×
1440
        }
1441
    }
1442

1443
    /* number of sent bytes */
1444
    *bytes = (bytes_header + bytes_body);
51✔
1445

1446
    /* Initialize timeout tracking */
1447
    c->ts_start = time(NULL);
51✔
1448
    c->last_read_ts = c->ts_start;
51✔
1449

1450
    /* prep c->resp for incoming data */
1451
    http_client_response_reset(c);
51✔
1452

1453
    /* at this point we've sent our request so we expect more data in response*/
1454
    return FLB_HTTP_MORE;
51✔
1455
}
1456

1457
int flb_http_get_response_data(struct flb_http_client *c, size_t bytes_consumed)
51✔
1458
{
1459
    /* returns
1460
     *  FLB_HTTP_MORE - if we are waiting for more data to be received
1461
     *  FLB_HTTP_CHUNK_AVAILABLE - if this is a chunked transfer and one or more chunks
1462
     *                 have been received and it is not the end of the stream
1463
     *  FLB_HTTP_OK - if we have collected all response data and no errors were thrown
1464
     *                (in chunked transfers this means we've received the end chunk
1465
     *                and any remaining data to process from the end of stream, will be
1466
     *                contained in the response payload)
1467
     *  FLB_HTTP_ERROR - for any error
1468
     */
1469
    int ret = FLB_HTTP_MORE;
51✔
1470
    int r_bytes;
51✔
1471
    ssize_t available;
51✔
1472
    size_t out_size;
51✔
1473
    time_t now;
51✔
1474

1475
    /* If the caller has consumed some of the payload (via bytes_consumed)
1476
     * we consume those bytes off the payload
1477
     */
1478
    if( bytes_consumed > 0 ) {
51✔
1479
        if(bytes_consumed > c->resp.payload_size) {
×
1480
            flb_error("[http_client] attempting to consume more bytes than "
×
1481
                      "available. Attempted bytes_consumed=%zu payload_size=%zu ",
1482
                        bytes_consumed,
1483
                        c->resp.payload_size);
1484
            return FLB_HTTP_ERROR;
×
1485
        }
1486

1487
        c->resp.payload_size -= bytes_consumed;
×
1488
        c->resp.data_len -= bytes_consumed;
×
1489
        memmove(c->resp.payload, c->resp.payload+bytes_consumed, c->resp.payload_size);
×
1490
        c->resp.chunk_processed_end = c->resp.payload+c->resp.payload_size;
×
1491
        c->resp.data[c->resp.data_len] = '\0';
×
1492
    }
1493

1494
    while (ret == FLB_HTTP_MORE) {
103✔
1495
        available = flb_http_buffer_available(c) - 1;
52✔
1496
        if (available <= 1) {
52✔
1497
            /*
1498
             * If there is no more space available on our buffer, try to
1499
             * increase it.
1500
             */
1501
            ret = flb_http_buffer_increase(c, FLB_HTTP_DATA_CHUNK,
×
1502
                                           &out_size);
1503
            if (ret == -1) {
×
1504
                /*
1505
                 * We could not allocate more space, let the caller handle
1506
                 * this.
1507
                 */
1508
                flb_warn("[http_client] cannot increase buffer: current=%zu "
×
1509
                         "requested=%zu max=%zu", c->resp.data_size,
1510
                         c->resp.data_size + FLB_HTTP_DATA_CHUNK,
1511
                         c->resp.data_size_max);
1512
                flb_upstream_conn_recycle(c->u_conn, FLB_FALSE);
×
1513
                return FLB_HTTP_ERROR;
×
1514
            }
1515
            available = flb_http_buffer_available(c) - 1;
×
1516
        }
1517
        now = time(NULL);
52✔
1518

1519
        if (c->response_timeout > 0 && (now - c->ts_start) > c->response_timeout) {
52✔
1520
            flb_error("[http_client] response timeout reached (elapsed=%lds, limit=%ds)",
×
1521
                      (long)(now - c->ts_start), c->response_timeout);
1522
            flb_upstream_conn_recycle(c->u_conn, FLB_FALSE);
×
1523
            return FLB_HTTP_ERROR;
×
1524
        }
1525

1526
        if (c->read_idle_timeout > 0 &&  (now - c->last_read_ts) > c->read_idle_timeout) {
52✔
1527
            flb_error("[http_client] read idle timeout reached (idle=%lds, limit=%ds)",
×
1528
                      (long)(now - c->last_read_ts), c->read_idle_timeout);
1529
            flb_upstream_conn_recycle(c->u_conn, FLB_FALSE);
×
1530
            return FLB_HTTP_ERROR;
×
1531
        }
1532

1533
        r_bytes = flb_io_net_read(c->u_conn,
104✔
1534
                                  c->resp.data + c->resp.data_len,
52✔
1535
                                  available);
1536
        if (r_bytes <= 0) {
52✔
1537
            if (c->flags & FLB_HTTP_10) {
×
1538
                return FLB_HTTP_OK;
1539
            }
1540
        }
1541

1542
        /* Always append a NULL byte */
1543
        if (r_bytes >= 0) {
×
1544
            c->resp.data_len += r_bytes;
52✔
1545
            c->resp.data[c->resp.data_len] = '\0';
52✔
1546

1547
            if (r_bytes > 0) {
52✔
1548
                c->last_read_ts = now;
52✔
1549
            }
1550

1551
            ret = process_data(c);
52✔
1552
            if (ret == FLB_HTTP_ERROR) {
52✔
1553
                flb_warn("[http_client] malformed HTTP response from %s:%i on "
×
1554
                         "connection #%i",
1555
                         c->u_conn->upstream->tcp_host,
1556
                         c->u_conn->upstream->tcp_port,
1557
                         c->u_conn->fd);
1558
                return FLB_HTTP_ERROR;
×
1559
            }
1560
        }
1561
        else {
1562
            flb_error("[http_client] broken connection to %s:%i ?",
×
1563
                      c->u_conn->upstream->tcp_host,
1564
                      c->u_conn->upstream->tcp_port);
1565
            return FLB_HTTP_ERROR;
×
1566
        }
1567
    }
1568

1569
    return ret;
1570
}
1571

1572
int flb_http_do(struct flb_http_client *c, size_t *bytes)
50✔
1573
{
1574
    int ret;
50✔
1575

1576
    if (c->test_mode == FLB_TRUE) {
50✔
1577
        return flb_http_stub_response(c);
3✔
1578
    }
1579

1580
    ret = flb_http_do_request(c, bytes);
47✔
1581
    if (ret != 0) {
47✔
1582
        return ret;
1583
    }
1584

1585
    /* Read the server response, we need at least 19 bytes */
1586
    while (ret == FLB_HTTP_MORE || ret == FLB_HTTP_CHUNK_AVAILABLE) {
94✔
1587
        /*
1588
         * flb_http_do does not consume any bytes during processing
1589
         * so we always pass 0 consumed_bytes because we fetch until
1590
         * the end chunk before returning to the caller
1591
         */
1592
        ret = flb_http_get_response_data(c, 0);
47✔
1593
    }
1594

1595

1596
    if (ret != FLB_HTTP_OK) {
47✔
1597
        return ret;
1598
    }
1599

1600
    /* Check 'Connection' response header */
1601
    ret = check_connection(c);
47✔
1602
    if (ret == FLB_HTTP_ERROR) {
47✔
1603
        return ret;
1604
    }
1605
    else if (ret == FLB_HTTP_OK) {
47✔
1606
        /*
1607
         * If the server replied that the connection will be closed
1608
         * and our Upstream connection is in keepalive mode, we must
1609
         * inactivate the connection.
1610
         */
1611
        if (c->resp.connection_close == FLB_TRUE) {
×
1612
            /* Do not recycle the connection (no more keepalive) */
1613
            flb_upstream_conn_recycle(c->u_conn, FLB_FALSE);
×
1614
            flb_debug("[http_client] server %s:%i will close connection #%i",
×
1615
                      c->u_conn->upstream->tcp_host,
1616
                      c->u_conn->upstream->tcp_port,
1617
                      c->u_conn->fd);
1618
        }
1619
    }
1620
    else if (ret == FLB_HTTP_NOT_FOUND) {
1621
        /* Connection header not found, continue normally */
1622
    }
1623

1624
#ifdef FLB_HAVE_HTTP_CLIENT_DEBUG
1625
    flb_http_client_debug_cb(c, "_debug.http.response_headers");
1626
    if (c->resp.payload_size > 0) {
1627
        flb_http_client_debug_cb(c, "_debug.http.response_payload");
1628
    }
1629
#endif
1630

1631
    return 0;
1632
}
1633

1634
/*
1635
 * flb_http_client_proxy_connect opens a tunnel to a proxy server via
1636
 * http `CONNECT` method. This is needed for https traffic through a
1637
 * http proxy.
1638
 * More: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/CONNECT
1639
 */
1640
int flb_http_client_proxy_connect(struct flb_connection *u_conn)
×
1641
{
1642
    struct flb_upstream *u = u_conn->upstream;
×
1643
    struct flb_http_client *c;
×
1644
    size_t b_sent;
×
1645
    int ret = -1;
×
1646

1647
    /* Don't pass proxy when using FLB_HTTP_CONNECT */
1648
    flb_debug("[upstream] establishing http tunneling to proxy: host %s port %d", u->tcp_host, u->tcp_port);
×
1649
    c = flb_http_client(u_conn, FLB_HTTP_CONNECT, "", NULL,
×
1650
                        0, u->proxied_host, u->proxied_port, NULL, 0);
×
1651

1652
    /* Setup proxy's username and password */
1653
    if (u->proxy_username && u->proxy_password) {
×
1654
        flb_debug("[upstream] proxy uses username %s password %s", u->proxy_username, u->proxy_password);
×
1655
        flb_http_proxy_auth(c, u->proxy_username, u->proxy_password);
×
1656
    }
1657

1658
    flb_http_buffer_size(c, 4192);
×
1659

1660
    flb_http_add_header(c, "User-Agent", 10, "Fluent-Bit", 10);
×
1661

1662
    /* Send HTTP request */
1663
    ret = flb_http_do(c, &b_sent);
×
1664

1665
    /* Validate HTTP response */
1666
    if (ret != 0) {
×
1667
        flb_error("[upstream] error in flb_establish_proxy: %d", ret);
×
1668
        ret = -1;
1669
    }
1670
    else {
1671
        /* The request was issued successfully, validate the 'error' field */
1672
        flb_debug("[upstream] proxy returned %d", c->resp.status);
×
1673
        if (c->resp.status == 200) {
×
1674
            ret = 0;
1675
        }
1676
        else {
1677
            flb_error("flb_establish_proxy error: %s", c->resp.payload);
×
1678
            ret = -1;
1679
        }
1680
    }
1681

1682
    /* Cleanup */
1683
    flb_http_client_destroy(c);
×
1684

1685
    return ret;
×
1686
}
1687

1688
void flb_http_client_destroy(struct flb_http_client *c)
301✔
1689
{
1690
    http_headers_destroy(c);
301✔
1691
    flb_free(c->resp.data);
301✔
1692
    flb_free(c->header_buf);
301✔
1693
    flb_free((void *)c->proxy.host);
301✔
1694
    flb_free(c);
301✔
1695
}
301✔
1696

1697

1698

1699

1700

1701

1702

1703

1704

1705

1706

1707

1708

1709

1710

1711

1712

1713

1714
static int flb_http_client_session_read(struct flb_http_client_session *session);
1715
static int flb_http_client_session_write(struct flb_http_client_session *session);
1716

1717

1718

1719

1720

1721

1722

1723

1724

1725

1726
int flb_http_client_ng_init(struct flb_http_client_ng *client,
×
1727
                            struct flb_upstream_ha *upstream_ha,
1728
                            struct flb_upstream *upstream,
1729
                            int protocol_version,
1730
                            uint64_t flags)
1731
{
1732
    memset(client, 0, sizeof(struct flb_http_client_ng));
×
1733

1734
    client->temporary_buffer = cfl_sds_create_size(HTTP_CLIENT_TEMPORARY_BUFFER_SIZE);
×
1735

1736
    if (client->temporary_buffer == NULL) {
×
1737
        return -1;
1738
    }
1739

1740
    client->protocol_version = protocol_version;
×
1741
    client->upstream_ha = upstream_ha;
×
1742
    client->upstream = upstream;
×
1743
    client->flags = flags;
×
1744

1745
    cfl_list_init(&client->sessions);
×
1746

1747
    if (protocol_version == HTTP_PROTOCOL_VERSION_AUTODETECT) {
×
1748
        if (upstream->base.tls_context != NULL) {
×
1749
            flb_tls_set_alpn(upstream->base.tls_context, "h2,http/1.1,http/1.0");
×
1750
        }
1751
    }
1752
    else if (protocol_version == HTTP_PROTOCOL_VERSION_20) {
×
1753
        if (upstream->base.tls_context != NULL) {
×
1754
            flb_tls_set_alpn(upstream->base.tls_context, "h2");
×
1755
        }
1756
    }
1757
    else if (protocol_version == HTTP_PROTOCOL_VERSION_11) {
×
1758
        if (upstream->base.tls_context != NULL) {
×
1759
            flb_tls_set_alpn(upstream->base.tls_context, "http/1.1,http/1.0");
×
1760
        }
1761
    }
1762
    else if (protocol_version <= HTTP_PROTOCOL_VERSION_10) {
×
1763
        if (upstream->base.tls_context != NULL) {
×
1764
            flb_tls_set_alpn(upstream->base.tls_context, "http/1.0");
×
1765
        }
1766
    }
1767

1768
    flb_lock_init(&client->lock);
×
1769

1770
    return 0;
×
1771
}
1772

1773
struct flb_http_client_ng *flb_http_client_ng_create(
×
1774
                                struct flb_upstream_ha *upstream_ha,
1775
                                struct flb_upstream *upstream,
1776
                                int protocol_version,
1777
                                uint64_t flags)
1778
{
1779
    struct flb_http_client_ng *client;
×
1780
    int                        result;
×
1781

1782
    client = flb_calloc(1, sizeof(struct flb_http_client_ng));
×
1783

1784
    if (client != NULL) {
×
1785
        result = flb_http_client_ng_init(client,
×
1786
                                         upstream_ha,
1787
                                         upstream,
1788
                                         protocol_version,
1789
                                         flags);
1790

1791
        client->releasable = FLB_TRUE;
×
1792

1793
        if (result != 0) {
×
1794
            flb_http_client_ng_destroy(client);
×
1795

1796
            client = NULL;
×
1797
        }
1798
    }
1799

1800
    return client;
×
1801
}
1802

1803
void flb_http_client_ng_destroy(struct flb_http_client_ng *client)
×
1804
{
1805
    struct cfl_list                *iterator_backup;
×
1806
    struct cfl_list                *iterator;
×
1807
    struct flb_http_client_session *session;
×
1808

1809
    flb_lock_acquire(&client->lock,
×
1810
                     FLB_LOCK_INFINITE_RETRY_LIMIT,
1811
                     FLB_LOCK_DEFAULT_RETRY_DELAY);
1812

1813
    if (client->temporary_buffer != NULL) {
×
1814
        cfl_sds_destroy(client->temporary_buffer);
×
1815

1816
        client->temporary_buffer = NULL;
×
1817
    }
1818

1819
    cfl_list_foreach_safe(iterator,
×
1820
                          iterator_backup,
1821
                          &client->sessions) {
1822
        session = cfl_list_entry(iterator,
×
1823
                                 struct flb_http_client_session,
1824
                                 _head);
1825

1826
        flb_http_client_session_destroy(session);
×
1827
    }
1828

1829
    flb_lock_release(&client->lock,
×
1830
                     FLB_LOCK_INFINITE_RETRY_LIMIT,
1831
                     FLB_LOCK_DEFAULT_RETRY_DELAY);
1832

1833
    flb_lock_destroy(&client->lock);
×
1834
}
×
1835

1836
int flb_http_client_session_init(struct flb_http_client_session *session,
×
1837
                                 struct flb_http_client_ng *client,
1838
                                 int protocol_version,
1839
                                 struct flb_connection  *connection)
1840
{
1841
    int result;
×
1842

1843
    memset(session, 0, sizeof(struct flb_http_client_session));
×
1844

1845
    session->parent = client;
×
1846
    session->protocol_version = protocol_version;
×
1847
    session->connection = connection;
×
1848
    session->stream_sequence_number = 1;
×
1849

1850
    cfl_list_init(&session->streams);
×
1851
    cfl_list_init(&session->response_queue);
×
1852

1853
    cfl_list_entry_init(&session->_head);
×
1854

1855
    session->incoming_data = cfl_sds_create_size(1);
×
1856

1857
    if (session->incoming_data == NULL) {
×
1858
        return -1;
1859
    }
1860

1861
    session->outgoing_data = cfl_sds_create_size(1);
×
1862

1863
    if (session->outgoing_data == NULL) {
×
1864
        return -1;
1865
    }
1866

1867
    if (session->protocol_version == HTTP_PROTOCOL_VERSION_11 ||
×
1868
        session->protocol_version == HTTP_PROTOCOL_VERSION_10) {
1869
        session->http1.parent = session;
×
1870

1871
        result = flb_http1_client_session_init(&session->http1);
×
1872

1873
        if (result != 0) {
×
1874
            return result;
1875
        }
1876
    }
1877
    else if (session->protocol_version == HTTP_PROTOCOL_VERSION_20) {
×
1878
        session->http2.parent = session;
×
1879

1880
        result = flb_http2_client_session_init(&session->http2);
×
1881

1882
        if (result != 0) {
×
1883
            return result;
1884
        }
1885
    }
1886
    else {
1887
        return -1;
1888
    }
1889

1890
    return 0;
1891
}
1892

1893
struct flb_http_client_session *flb_http_client_session_create(struct flb_http_client_ng *client,
×
1894
                                                               int protocol_version,
1895
                                                               struct flb_connection  *connection)
1896
{
1897
    struct flb_http_client_session *session;
×
1898
    int                             result;
×
1899

1900
    session = flb_calloc(1, sizeof(struct flb_http_client_session));
×
1901

1902
    if (session != NULL) {
×
1903
        if (client != NULL) {
×
1904
            flb_lock_acquire(&client->lock,
×
1905
                            FLB_LOCK_INFINITE_RETRY_LIMIT,
1906
                            FLB_LOCK_DEFAULT_RETRY_DELAY);
1907
        }
1908

1909
        result = flb_http_client_session_init(session,
×
1910
                                              client,
1911
                                              protocol_version,
1912
                                              connection);
1913

1914
        if (client != NULL) {
×
1915
            flb_lock_release(&client->lock,
×
1916
                            FLB_LOCK_INFINITE_RETRY_LIMIT,
1917
                            FLB_LOCK_DEFAULT_RETRY_DELAY);
1918
        }
1919

1920
        session->releasable = FLB_TRUE;
×
1921

1922
        if (result != 0) {
×
1923
            flb_http_client_session_destroy(session);
×
1924

1925
            session = NULL;
×
1926
        }
1927
    }
1928

1929
    return session;
×
1930
}
1931

1932
struct flb_http_client_session *flb_http_client_session_begin(struct flb_http_client_ng *client)
×
1933
{
1934
    int                             protocol_version;
×
1935
    struct flb_upstream_node       *upstream_node;
×
1936
    struct flb_connection          *connection;
×
1937
    struct flb_upstream            *upstream;
×
1938
    struct flb_http_client_session *session;
×
1939
    const char                     *alpn;
×
1940

1941
    if (client->upstream_ha != NULL) {
×
1942
        upstream_node = flb_upstream_ha_node_get(client->upstream_ha);
×
1943

1944
        if (upstream_node == NULL) {
×
1945
            return NULL;
1946
        }
1947

1948
        upstream = upstream_node->u;
×
1949

1950
        connection = flb_upstream_conn_get(upstream_node->u);
×
1951
    }
1952
    else {
1953
        upstream_node = NULL;
×
1954

1955
        upstream = client->upstream;
×
1956

1957
        connection = flb_upstream_conn_get(client->upstream);
×
1958
    }
1959

1960
    if (connection == NULL) {
×
1961
        return NULL;
1962
    }
1963

1964
    protocol_version = client->protocol_version;
×
1965

1966
    if (protocol_version == HTTP_PROTOCOL_VERSION_AUTODETECT) {
×
1967
        if (connection->tls_session != NULL) {
×
1968
            alpn = flb_tls_session_get_alpn(connection->tls_session);
×
1969

1970
            if (alpn != NULL) {
×
1971
                if (strcasecmp(alpn, "h2") == 0) {
×
1972
                    protocol_version = HTTP_PROTOCOL_VERSION_20;
1973
                }
1974
                else if (strcasecmp(alpn, "http/1.1") == 0) {
×
1975
                    protocol_version = HTTP_PROTOCOL_VERSION_11;
1976
                }
1977
                else if (strcasecmp(alpn, "http/1.0") == 0) {
×
1978
                    protocol_version = HTTP_PROTOCOL_VERSION_10;
1979
                }
1980
            }
1981
        }
1982
    }
1983

1984
    if (protocol_version == HTTP_PROTOCOL_VERSION_AUTODETECT) {
1985
        protocol_version = HTTP_PROTOCOL_VERSION_11;
1986
    }
1987

1988
    if (protocol_version == HTTP_PROTOCOL_VERSION_20) {
×
1989
        flb_stream_disable_keepalive(&upstream->base);
×
1990
    }
1991

1992
    session = flb_http_client_session_create(client, protocol_version, connection);
×
1993

1994
    if (session == NULL) {
×
1995
        flb_upstream_conn_release(connection);
×
1996
    }
1997

1998
    session->upstream_node = upstream_node;
×
1999

2000
    return session;
×
2001
}
2002

2003
void flb_http_client_session_destroy(struct flb_http_client_session *session)
×
2004
{
2005
    struct cfl_list         *iterator_backup;
×
2006
    struct cfl_list         *iterator;
×
2007
    struct flb_http_stream  *stream;
×
2008

2009
    if (session != NULL) {
×
2010
        cfl_list_foreach_safe(iterator,
×
2011
                              iterator_backup,
2012
                              &session->streams) {
2013
            stream = cfl_list_entry(iterator, struct flb_http_stream, _head);
×
2014

2015
            flb_http_stream_destroy(stream);
×
2016
        }
2017

2018
        if (session->connection != NULL) {
×
2019
            flb_upstream_conn_release(session->connection);
×
2020
        }
2021

2022
        if (!cfl_list_entry_is_orphan(&session->_head)) {
×
2023
            cfl_list_del(&session->_head);
×
2024
        }
2025

2026
        if (session->incoming_data != NULL) {
×
2027
            cfl_sds_destroy(session->incoming_data);
×
2028
        }
2029

2030
        if (session->outgoing_data != NULL) {
×
2031
            cfl_sds_destroy(session->outgoing_data);
×
2032
        }
2033

2034
        flb_http1_client_session_destroy(&session->http1);
×
2035
        flb_http2_client_session_destroy(&session->http2);
×
2036

2037
        if (session->releasable) {
×
2038
            flb_free(session);
×
2039
        }
2040
    }
2041
}
×
2042

2043
struct flb_http_request *flb_http_client_request_begin(struct flb_http_client_session *session)
×
2044
{
2045
    int                     stream_id;
×
2046
    struct flb_http_stream *stream;
×
2047
    int                     result;
×
2048

2049
    stream_id = session->stream_sequence_number;
×
2050
    session->stream_sequence_number += 2;
×
2051

2052
    stream = flb_http_stream_create(session,
×
2053
                                    stream_id,
2054
                                    HTTP_STREAM_ROLE_CLIENT,
2055
                                    session);
2056

2057
    if (stream == NULL) {
×
2058
        return NULL;
2059
    }
2060

2061
    stream->request.protocol_version = session->protocol_version;
×
2062

2063
    if (stream->request.protocol_version == HTTP_PROTOCOL_VERSION_20) {
×
2064
        result = flb_http2_request_begin(&stream->request);
×
2065
    }
2066
    else if (stream->request.protocol_version == HTTP_PROTOCOL_VERSION_11 ||
×
2067
             stream->request.protocol_version == HTTP_PROTOCOL_VERSION_10) {
2068
        result = flb_http1_request_begin(&stream->request);
×
2069
    }
2070
    else {
2071
        result = -1;
2072
    }
2073

2074
    if (result != 0) {
×
2075
        flb_http_stream_destroy(stream);
×
2076

2077
        return NULL;
×
2078
    }
2079

2080
    cfl_list_add(&stream->_head, &session->streams);
×
2081

2082
    return &stream->request;
×
2083
}
2084

2085
struct flb_http_response *flb_http_client_request_execute_step(
×
2086
                            struct flb_http_request *request)
2087
{
2088
    struct flb_http_response       *response;
×
2089
    struct flb_http_client_session *session;
×
2090
    int                             result;
×
2091

2092
    session = (struct flb_http_client_session *) request->stream->parent;
×
2093
    response = &request->stream->response;
×
2094

2095
    /* We allow this to enable request mocking, there is no
2096
     * other legitimate use for it.
2097
     */
2098
    if (session->connection == NULL) {
×
2099
        return response;
2100
    }
2101

2102
    if (session->outgoing_data != NULL &&
×
2103
        cfl_sds_len(session->outgoing_data) > 0)
×
2104
    {
2105
        result = flb_http_client_session_write(session);
×
2106

2107
        if (result != 0) {
×
2108
            return NULL;
2109
        }
2110

2111
        result = flb_http_client_session_read(session);
×
2112

2113
        if (result != 0) {
×
2114
            return NULL;
2115
        }
2116
    }
2117

2118
    if (request->stream->status == HTTP_STREAM_STATUS_SENDING_HEADERS) {
×
2119
        result = flb_http_request_commit(request);
×
2120

2121
        if (result != 0) {
×
2122
            return NULL;
2123
        }
2124

2125
        result = flb_http_client_session_write(session);
×
2126

2127
        if (result != 0) {
×
2128
            return NULL;
2129
        }
2130

2131
        request->stream->status = HTTP_STREAM_STATUS_RECEIVING_HEADERS;
×
2132
    }
2133
    else if (request->stream->status == HTTP_STREAM_STATUS_RECEIVING_HEADERS ||
×
2134
             request->stream->status == HTTP_STREAM_STATUS_RECEIVING_DATA ) {
2135
        result = flb_http_client_session_read(session);
×
2136

2137
        if (result != 0) {
×
2138
            return NULL;
2139
        }
2140

2141
        if (session->outgoing_data != NULL &&
×
2142
            cfl_sds_len(session->outgoing_data) > 0)
×
2143
        {
2144
            result = flb_http_client_session_write(session);
×
2145

2146
            if (result != 0) {
×
2147
                return NULL;
2148
            }
2149
        }
2150
    }
2151

2152
    if (request->stream->status != HTTP_STREAM_STATUS_RECEIVING_HEADERS &&
×
2153
        request->stream->status != HTTP_STREAM_STATUS_RECEIVING_DATA &&
×
2154
        request->stream->status != HTTP_STREAM_STATUS_CLOSED &&
×
2155
        request->stream->status != HTTP_STREAM_STATUS_READY ) {
2156
        return NULL;
2157
    }
2158

2159
    return response;
2160
}
2161

2162
struct flb_http_response *flb_http_client_request_execute(struct flb_http_request *request)
×
2163
{
2164
    struct flb_http_response *response;
×
2165

2166
    do {
×
2167
        response = flb_http_client_request_execute_step(request);
×
2168
    } while (response != NULL &&
×
2169
             request->stream->status != HTTP_STREAM_STATUS_READY &&
×
2170
             request->stream->status != HTTP_STREAM_STATUS_CLOSED);
2171

2172
    return response;
×
2173
}
2174

2175
static int flb_http_client_session_read(struct flb_http_client_session *session)
×
2176
{
2177
    ssize_t result;
×
2178

2179
    result = flb_io_net_read(session->connection,
×
2180
                             (void *) session->parent->temporary_buffer,
×
2181
                             cfl_sds_avail(session->parent->temporary_buffer));
×
2182

2183
    if (result <= 0) {
×
2184
        return -1;
2185
    }
2186

2187
    result = (ssize_t) flb_http_client_session_ingest(
×
2188
                            session,
2189
                            (unsigned char *) session->parent->temporary_buffer,
×
2190
                            result);
2191

2192
    if (result < 0) {
×
2193
        return -2;
×
2194
    }
2195

2196
    return 0;
2197
}
2198

2199

2200
void flb_http_client_request_destroy(struct flb_http_request *request,
×
2201
                                     int destroy_session)
2202
{
2203
    if (destroy_session == FLB_TRUE) {
×
2204
        flb_http_client_session_destroy((struct flb_http_client_session *)
×
2205
                                         request->stream->parent);
×
2206
    }
2207
    else {
2208
        flb_http_request_destroy(request);
×
2209
    }
2210
}
×
2211

2212

2213
static int flb_http_client_session_write(struct flb_http_client_session *session)
×
2214
{
2215
    size_t data_length;
×
2216
    size_t data_sent;
×
2217
    int    result;
×
2218

2219
    if (session == NULL) {
×
2220
        return -1;
2221
    }
2222

2223
    if (session->outgoing_data == NULL) {
×
2224
        return 0;
2225
    }
2226

2227
    data_length = cfl_sds_len(session->outgoing_data);
×
2228

2229
    if (data_length > 0) {
×
2230
        result = flb_io_net_write(session->connection,
×
2231
                                  (void *) session->outgoing_data,
×
2232
                                  data_length,
2233
                                  &data_sent);
2234

2235
        if (result == -1) {
×
2236
            return -2;
2237
        }
2238

2239

2240
        if (data_sent < data_length) {
×
2241
            memmove(session->outgoing_data,
×
2242
                    &session->outgoing_data[data_sent],
×
2243
                    data_length - data_sent);
2244

2245
            cfl_sds_set_len(session->outgoing_data,
×
2246
                            data_length - data_sent);
2247
        }
2248
        else {
2249
            cfl_sds_set_len(session->outgoing_data, 0);
×
2250
        }
2251
    }
2252

2253
    return 0;
2254
}
2255

2256
int flb_http_client_session_ingest(struct flb_http_client_session *session,
×
2257
                                   unsigned char *buffer,
2258
                                   size_t length)
2259
{
2260
    if (session->protocol_version == HTTP_PROTOCOL_VERSION_11 ||
×
2261
        session->protocol_version == HTTP_PROTOCOL_VERSION_10) {
2262
        return flb_http1_client_session_ingest(&session->http1,
×
2263
                                               buffer,
2264
                                               length);
2265
    }
2266
    else if (session->protocol_version == HTTP_PROTOCOL_VERSION_20) {
×
2267
        return flb_http2_client_session_ingest(&session->http2,
×
2268
                                               buffer,
2269
                                               length);
2270
    }
2271

2272
    return -20;
2273
}
2274

2275
static int flb_http_encode_basic_auth_value(cfl_sds_t *output_buffer,
×
2276
                                            char *username,
2277
                                            char *password)
2278
{
2279
    size_t    encoded_value_length;
×
2280
    cfl_sds_t encoded_value;
×
2281
    cfl_sds_t sds_result;
×
2282
    cfl_sds_t raw_value;
×
2283
    int       result;
×
2284

2285
    *output_buffer = NULL;
×
2286

2287
    raw_value = cfl_sds_create_size(strlen(username) +
×
2288
                                    strlen(password) + 2);
×
2289

2290
    if (raw_value == NULL) {
×
2291
        return -1;
2292
    }
2293

2294
    sds_result = cfl_sds_printf(&raw_value,
×
2295
                                "%s:%s",
2296
                                username,
2297
                                password);
2298

2299
    if (sds_result == NULL) {
×
2300
        cfl_sds_destroy(raw_value);
×
2301

2302
        return -1;
×
2303
    }
2304

2305
    encoded_value = cfl_sds_create_size(cfl_sds_len(raw_value) * 2 + 1);
×
2306

2307
    if (encoded_value == NULL) {
×
2308
        cfl_sds_destroy(raw_value);
×
2309

2310
        return -1;
×
2311
    }
2312

2313
    result = flb_base64_encode((unsigned char *) encoded_value,
×
2314
                                cfl_sds_alloc(encoded_value),
2315
                                &encoded_value_length,
2316
                                (unsigned char *) raw_value,
2317
                                cfl_sds_len(raw_value));
2318

2319
    if (result == 0) {
×
2320
        *output_buffer = cfl_sds_create_size(cfl_sds_len(encoded_value) + 6);
×
2321

2322
        if (*output_buffer != NULL) {
×
2323
            sds_result = cfl_sds_printf(output_buffer, "Basic %s", encoded_value);
×
2324

2325
            if (sds_result != NULL) {
×
2326
                *output_buffer = sds_result;
×
2327
            }
2328
            else {
2329
                result = -1;
×
2330
            }
2331
        }
2332
        else {
2333
            result = -1;
2334
        }
2335
    }
2336
    else {
2337
        result = -1;
2338
    }
2339

2340
    cfl_sds_destroy(encoded_value);
×
2341
    cfl_sds_destroy(raw_value);
×
2342

2343
    return 0;
×
2344
}
2345

2346
static int flb_http_encode_bearer_auth_value(cfl_sds_t *output_buffer,
×
2347
                                             char *token)
2348
{
2349
    cfl_sds_t sds_result;
×
2350

2351
    *output_buffer = NULL;
×
2352

2353
    *output_buffer = cfl_sds_create_size(strlen(token) + 9);
×
2354

2355
    if (*output_buffer == NULL) {
×
2356
        return -1;
2357
    }
2358

2359
    sds_result = cfl_sds_printf(output_buffer,
×
2360
                                "Bearer %s",
2361
                                token);
2362

2363
    if (sds_result == NULL) {
×
2364
        cfl_sds_destroy(*output_buffer);
×
2365
        *output_buffer = NULL;
×
2366

2367
        return -1;
×
2368
    }
2369

2370
    *output_buffer = sds_result;
×
2371

2372
    return 0;
×
2373
}
2374

2375

2376
int flb_http_request_set_authorization(struct flb_http_request *request,
×
2377
                                       int type, ...)
2378
{
2379
    cfl_sds_t   header_value;
×
2380
    const char *header_name;
×
2381
    va_list     arguments;
×
2382
    char       *username;
×
2383
    char       *password;
×
2384
    int         result;
×
2385
    char       *token;
×
2386

2387
    va_start(arguments, type);
×
2388

2389
    if (type == HTTP_WWW_AUTHORIZATION_SCHEME_BASIC) {
×
2390
        header_name = "authorization";
×
2391

2392
        username = va_arg(arguments, char *);
×
2393
        password = va_arg(arguments, char *);
×
2394

2395
        result = flb_http_encode_basic_auth_value(&header_value,
×
2396
                                                  username,
2397
                                                  password);
2398

2399
        if (result != 0) {
×
2400
            va_end(arguments);
×
2401

2402
            return -1;
×
2403
        }
2404
    }
2405
    else if (type == HTTP_WWW_AUTHORIZATION_SCHEME_BEARER) {
×
2406
        header_name = "authorization";
×
2407

2408
        token = va_arg(arguments, char *);
×
2409

2410
        result = flb_http_encode_bearer_auth_value(&header_value,
×
2411
                                                   token);
2412

2413
        if (result != 0) {
×
2414
            va_end(arguments);
×
2415

2416
            return -1;
×
2417
        }
2418
    }
2419
    else if (type == HTTP_PROXY_AUTHORIZATION_SCHEME_BASIC) {
×
2420
        header_name = "proxy-authorization";
×
2421

2422
        username = va_arg(arguments, char *);
×
2423
        password = va_arg(arguments, char *);
×
2424

2425
        result = flb_http_encode_basic_auth_value(&header_value,
×
2426
                                                  username,
2427
                                                  password);
2428

2429
        if (result != 0) {
×
2430
            va_end(arguments);
×
2431

2432
            return -1;
×
2433
        }
2434
    }
2435
    else if (type == HTTP_PROXY_AUTHORIZATION_SCHEME_BEARER) {
×
2436
        header_name = "proxy-authorization";
×
2437

2438
        token = va_arg(arguments, char *);
×
2439

2440
        result = flb_http_encode_bearer_auth_value(&header_value,
×
2441
                                                   token);
2442

2443
        if (result != 0) {
×
2444
            va_end(arguments);
×
2445

2446
            return -1;
×
2447
        }
2448
    }
2449
    else {
2450
        va_end(arguments);
×
2451

2452
        return -1;
×
2453
    }
2454

2455
    va_end(arguments);
×
2456

2457
    result = flb_http_request_set_header(request,
×
2458
                                         (char *) header_name, 0,
2459
                                         (char *) header_value, 0);
2460

2461
    cfl_sds_destroy(header_value);
×
2462

2463
    if (result != 0) {
×
2464
        result = -1;
×
2465
    }
2466

2467
    return result;
2468
}
2469

2470

2471

2472

2473
int flb_http_request_set_parameters_internal(
×
2474
    struct flb_http_request *request,
2475
    va_list arguments)
2476
{
2477
    char                           *compression_algorithm;
×
2478
    struct flb_config_map_val      *config_map_list_entry;
×
2479
    int                             failure_detected;
×
2480
    size_t                          header_data_type;
×
2481
    char                           *content_type;
×
2482
    char                           *bearer_token;
×
2483
    struct flb_aws_provider        *aws_provider;
×
2484
    struct flb_slist_entry         *header_value;
×
2485
    char                          **header_array;
×
2486
    char                           *aws_service;
×
2487
    struct mk_list                 *header_list;
×
2488
    struct flb_slist_entry         *header_name;
×
2489
    char                           *aws_region;
×
2490
    size_t                          value_type;
×
2491
    char                           *user_agent;
×
2492
    struct mk_list                 *iterator;
×
2493
    size_t                          body_len;
×
2494
    char                           *username;
×
2495
    char                           *password;
×
2496
    int                             result;
×
2497
    size_t                          index;
×
2498
    size_t                          method;
×
2499
    char                           *host;
×
2500
    unsigned char                  *body;
×
2501
    char                           *uri;
×
2502
    char                           *url;
×
2503

2504
    failure_detected = FLB_FALSE;
×
2505

2506
    do {
×
2507
        value_type = va_arg(arguments, size_t);
×
2508

2509
        if (value_type == FLB_HTTP_CLIENT_ARGUMENT_TYPE_METHOD) {
×
2510
            method = va_arg(arguments, size_t);
×
2511

2512
            flb_http_request_set_method(request, (int) method);
×
2513
        }
2514
        else if (value_type == FLB_HTTP_CLIENT_ARGUMENT_TYPE_HOST) {
2515
            host = va_arg(arguments, char *);
×
2516

2517
            flb_http_request_set_host(request, host);
×
2518
        }
2519
        else if (value_type == FLB_HTTP_CLIENT_ARGUMENT_TYPE_URL) {
2520
            url = va_arg(arguments, char *);
×
2521

2522
            flb_http_request_set_url(request, url);
×
2523
        }
2524
        else if (value_type == FLB_HTTP_CLIENT_ARGUMENT_TYPE_URI) {
2525
            uri = va_arg(arguments, char *);
×
2526

2527
            flb_http_request_set_uri(request, uri);
×
2528
        }
2529
        else if (value_type == FLB_HTTP_CLIENT_ARGUMENT_TYPE_USER_AGENT) {
2530
            user_agent = va_arg(arguments, char *);
×
2531

2532
            flb_http_request_set_user_agent(request, user_agent);
×
2533
        }
2534
        else if (value_type == FLB_HTTP_CLIENT_ARGUMENT_TYPE_CONTENT_TYPE) {
2535
            content_type = va_arg(arguments, char *);
×
2536

2537
            result = flb_http_request_set_content_type(request, content_type);
×
2538

2539
            if (request == NULL) {
×
2540
                flb_debug("http request : error setting content type");
×
2541

2542
                failure_detected = FLB_TRUE;
2543
            }
2544
        }
2545
        else if (value_type == FLB_HTTP_CLIENT_ARGUMENT_TYPE_BODY) {
2546
            body = va_arg(arguments, unsigned char *);
×
2547
            body_len = va_arg(arguments, size_t);
×
2548
            compression_algorithm = va_arg(arguments, char *);
×
2549

2550
            result = flb_http_request_set_body(request,
×
2551
                                               body,
2552
                                               body_len,
2553
                                               compression_algorithm);
2554

2555
            if (request == NULL) {
×
2556
                flb_debug("http request creation error");
×
2557

2558
                failure_detected = FLB_TRUE;
2559
            }
2560
        }
2561
        else if (value_type == FLB_HTTP_CLIENT_ARGUMENT_TYPE_HEADERS) {
2562
            header_data_type = va_arg(arguments, size_t);
×
2563

2564
            if (header_data_type == FLB_HTTP_CLIENT_HEADER_ARRAY) {
×
2565
                header_array = va_arg(arguments, char **);
×
2566
                if (header_array != NULL) {
×
2567
                    for (index = 0 ;
2568
                        header_array[index+0] != NULL &&
×
2569
                        header_array[index+1] != NULL;
×
2570
                        index += 2) {
×
2571
                        result = flb_http_request_set_header(request,
×
2572
                                                             header_array[index+0], 0,
2573
                                                             header_array[index+1], 0);
2574

2575
                        if (result != 0) {
×
2576
                            flb_debug("http request header addition error");
×
2577

2578
                            failure_detected = FLB_TRUE;
2579

2580
                            break;
2581
                        }
2582
                    }
2583
                }
2584
            }
2585
            else if (header_data_type == FLB_HTTP_CLIENT_HEADER_CONFIG_MAP_LIST) {
×
2586
                header_list = va_arg(arguments, struct mk_list *);
×
2587

2588
                flb_config_map_foreach(iterator, config_map_list_entry, header_list) {
×
2589
                    header_name = mk_list_entry_first(config_map_list_entry->val.list,
×
2590
                                                      struct flb_slist_entry,
2591
                                                      _head);
2592

2593
                    header_value = mk_list_entry_last(config_map_list_entry->val.list,
×
2594
                                                      struct flb_slist_entry,
2595
                                                      _head);
2596

2597
                    result = flb_http_request_set_header(request,
×
2598
                                                         header_name->str, 0,
2599
                                                         header_value->str, 0);
2600

2601
                    if (result != 0) {
×
2602
                        flb_debug("http request header addition error");
×
2603

2604
                        failure_detected = FLB_TRUE;
2605

2606
                        break;
2607
                    }
2608
                }
2609
            }
2610
            else {
2611
                failure_detected = FLB_TRUE;
2612
            }
2613
        }
2614
        else if (value_type == FLB_HTTP_CLIENT_ARGUMENT_TYPE_AUTH_BASIC) {
2615
            username = va_arg(arguments, char *);
×
2616
            password = va_arg(arguments, char *);
×
2617

2618
            flb_http_request_set_authorization(request,
×
2619
                                            HTTP_WWW_AUTHORIZATION_SCHEME_BASIC,
2620
                                            username,
2621
                                            password);
2622
        }
2623
        else if (value_type == FLB_HTTP_CLIENT_ARGUMENT_TYPE_AUTH_BEARER_TOKEN) {
2624
            bearer_token = va_arg(arguments, char *);
×
2625

2626
            flb_http_request_set_authorization(request,
×
2627
                                            HTTP_WWW_AUTHORIZATION_SCHEME_BEARER,
2628
                                            bearer_token);
2629
        }
2630
        else if (value_type == FLB_HTTP_CLIENT_ARGUMENT_TYPE_AUTH_SIGNV4) {
2631
            aws_region = va_arg(arguments, char *);
×
2632
            aws_service = va_arg(arguments, char *);
×
2633
            aws_provider = va_arg(arguments, struct flb_aws_provider *);
×
2634

2635
            result = flb_http_request_perform_signv4_signature(request,
×
2636
                                                               aws_region,
2637
                                                               aws_service,
2638
                                                               aws_provider);
2639
        }
2640
    } while (!failure_detected &&
×
2641
             value_type != FLB_HTTP_CLIENT_ARGUMENT_TYPE_TERMINATOR);
×
2642

2643
    if (failure_detected) {
×
2644
        return -1;
×
2645
    }
2646

2647
    return 0;
2648
}
2649

2650
int flb_http_request_set_parameters_unsafe(
×
2651
    struct flb_http_request *request,
2652
    ...)
2653
{
2654
    va_list arguments;
×
2655
    int     result;
×
2656

2657
    va_start(arguments, request);
×
2658

2659
    result = flb_http_request_set_parameters_internal(request, arguments);
×
2660

2661
    va_end(arguments);
×
2662

2663
    return result;
×
2664
}
2665

2666
struct flb_http_request *flb_http_client_request_builder_unsafe(
×
2667
    struct flb_http_client_ng *client,
2668
    ...)
2669
{
2670
    va_list                         arguments;
×
2671
    struct flb_http_request        *request;
×
2672
    struct flb_http_client_session *session;
×
2673
    int                             result;
×
2674

2675
    session = flb_http_client_session_begin(client);
×
2676

2677
    if (session == NULL) {
×
2678
        flb_debug("http session creation error");
×
2679

2680
        return NULL;
×
2681
    }
2682

2683
    request = flb_http_client_request_begin(session);
×
2684

2685
    if (request == NULL) {
×
2686
        flb_debug("http request creation error");
×
2687

2688
        flb_http_client_session_destroy(session);
×
2689

2690
        return NULL;
×
2691
    }
2692

2693
    flb_http_request_set_port(request, client->upstream->tcp_port);
×
2694

2695
    va_start(arguments, client);
×
2696

2697
    result = flb_http_request_set_parameters_internal(request, arguments);
×
2698

2699
    va_end(arguments);
×
2700

2701
    if (result != 0) {
×
2702
        flb_http_client_session_destroy(session);
×
2703

2704
        /*
2705
         * The request instance is recursively disposed of
2706
         */
2707
        request = NULL;
×
2708
    }
2709

2710
    return request;
2711
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc