blob: 4a95b9237b893f2619d0f1acd96f0ae53416a54a [file] [log] [blame]
William Lallemand83614a92021-08-13 14:47:57 +02001/*
2 * HTTP Client
3 *
4 * Copyright (C) 2021 HAProxy Technologies, William Lallemand <wlallemand@haproxy.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 * This file implements an HTTP Client API.
12 *
13 */
14#include <haproxy/connection-t.h>
15#include <haproxy/server-t.h>
16
17#include <haproxy/cfgparse.h>
18#include <haproxy/connection.h>
19#include <haproxy/global.h>
20#include <haproxy/log.h>
21#include <haproxy/proxy.h>
22#include <haproxy/tools.h>
23
24#include <string.h>
25
26
27static struct proxy *httpclient_proxy;
28static struct server *httpclient_srv_raw;
29static struct server *httpclient_srv_ssl;
30
31/*
32 * Initialize the proxy for the HTTP client with 2 servers, one for raw HTTP,
33 * the other for HTTPS.
34 */
35
36static int httpclient_init()
37{
38 int err_code = 0;
39 char *errmsg = NULL;
40
41 httpclient_proxy = alloc_new_proxy("<HTTPCLIENT>", PR_CAP_LISTEN|PR_CAP_INT, &errmsg);
42 if (!httpclient_proxy) {
43 err_code |= ERR_ALERT | ERR_FATAL;
44 goto err;
45 }
46
47 httpclient_proxy->options2 |= PR_O2_INDEPSTR;
48 httpclient_proxy->mode = PR_MODE_HTTP;
49 httpclient_proxy->maxconn = 0;
50 httpclient_proxy->accept = NULL;
51 httpclient_proxy->timeout.client = TICK_ETERNITY;
52 /* The HTTP Client use the "option httplog" with the global log server */
53 httpclient_proxy->conf.logformat_string = default_http_log_format;
54 httpclient_proxy->http_needed = 1;
55
56 /* clear HTTP server */
57 httpclient_srv_raw = new_server(httpclient_proxy);
58 if (!httpclient_srv_raw) {
59 err_code |= ERR_ALERT | ERR_FATAL;
60 memprintf(&errmsg, "out of memory.");
61 goto err;
62 }
63
64 httpclient_srv_raw->iweight = 0;
65 httpclient_srv_raw->uweight = 0;
66 httpclient_srv_raw->xprt = xprt_get(XPRT_RAW);
67 httpclient_srv_raw->id = strdup("<HTTPCLIENT>");
68 if (!httpclient_srv_raw->id)
69 goto err;
70
71 /* SSL HTTP server */
72 httpclient_srv_ssl = new_server(httpclient_proxy);
73 if (!httpclient_srv_ssl) {
74 memprintf(&errmsg, "out of memory.");
75 err_code |= ERR_ALERT | ERR_FATAL;
76 goto err;
77 }
78 httpclient_srv_ssl->iweight = 0;
79 httpclient_srv_ssl->uweight = 0;
80 httpclient_srv_ssl->xprt = xprt_get(XPRT_SSL);
81 httpclient_srv_ssl->use_ssl = 1;
82 httpclient_srv_ssl->id = strdup("<HTTPCLIENT>");
83 if (!httpclient_srv_ssl->id)
84 goto err;
85
86 /* add the proxy in the proxy list only if everything successed */
87 httpclient_proxy->next = proxies_list;
88 proxies_list = httpclient_proxy;
89
90 return 0;
91
92err:
93 ha_alert("httpclient: cannot initialize.\n");
94 free(errmsg);
95 free_server(httpclient_srv_raw);
96 free_server(httpclient_srv_ssl);
97 free_proxy(httpclient_proxy);
98 return err_code;
99}
100
101/*
102 * Post config parser callback, this is used to copy the log line from the
103 * global section and put it in the server proxy
104 */
105static int httpclient_cfg_postparser()
106{
107 struct logsrv *logsrv;
108 struct proxy *curproxy = httpclient_proxy;
109
110 /* copy logs from "global" log list */
111 list_for_each_entry(logsrv, &global.logsrvs, list) {
112 struct logsrv *node = malloc(sizeof(*node));
113
114 if (!node) {
115 ha_alert("httpclient: cannot allocate memory.\n");
116 goto err;
117 }
118
119 memcpy(node, logsrv, sizeof(*node));
120 LIST_INIT(&node->list);
121 LIST_APPEND(&curproxy->logsrvs, &node->list);
122 }
123 if (curproxy->conf.logformat_string) {
124 char *err = NULL;
125
126 curproxy->conf.args.ctx = ARGC_LOG;
127 if (!parse_logformat_string(curproxy->conf.logformat_string, curproxy, &curproxy->logformat,
128 LOG_OPT_MANDATORY|LOG_OPT_MERGE_SPACES,
129 SMP_VAL_FE_LOG_END, &err)) {
130 ha_alert("httpclient: failed to parse log-format : %s.\n", err);
131 free(err);
132 goto err;
133 }
134 curproxy->conf.args.file = NULL;
135 curproxy->conf.args.line = 0;
136 }
137 return 0;
138err:
139 return 1;
140}
141
142static void httpclient_deinit()
143{
144 free_server(httpclient_srv_raw);
145 free_server(httpclient_srv_ssl);
146 free_proxy(httpclient_proxy);
147
148}
149
150/* initialize the proxy and servers for the HTTP client */
151
152INITCALL0(STG_REGISTER, httpclient_init);
153REGISTER_CONFIG_POSTPARSER("httpclient", httpclient_cfg_postparser);
154REGISTER_POST_DEINIT(httpclient_deinit);