William Lallemand | 83614a9 | 2021-08-13 14:47:57 +0200 | [diff] [blame^] | 1 | /* |
| 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 | |
| 27 | static struct proxy *httpclient_proxy; |
| 28 | static struct server *httpclient_srv_raw; |
| 29 | static 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 | |
| 36 | static 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 | |
| 92 | err: |
| 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 | */ |
| 105 | static 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; |
| 138 | err: |
| 139 | return 1; |
| 140 | } |
| 141 | |
| 142 | static 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 | |
| 152 | INITCALL0(STG_REGISTER, httpclient_init); |
| 153 | REGISTER_CONFIG_POSTPARSER("httpclient", httpclient_cfg_postparser); |
| 154 | REGISTER_POST_DEINIT(httpclient_deinit); |