mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-03-05 19:10:45 +00:00
MINOR: http-htx: Use a dedicated function to parse http reply arguments
A dedicated function to parse arguments and create an http_reply object is added. It is used to parse http return rule. Thus, following arguments are parsed by this function : ... [status <code>] [content-type <type>] [ { default-errorfiles | errorfile <file> | errorfiles <name> | file <file> | lf-file <file> | string <str> | lf-string <fmt> } ] [ hdr <name> <fmt> ]* Because the status code argument is optional, a default status code must be defined when this function is called.
This commit is contained in:
parent
18630643a9
commit
47e791e220
@ -61,6 +61,8 @@ unsigned int http_get_htx_fhdr(const struct htx *htx, const struct ist hdr,
|
||||
int http_str_to_htx(struct buffer *buf, struct ist raw);
|
||||
|
||||
void release_http_reply(struct http_reply *http_reply);
|
||||
struct http_reply *http_parse_http_reply(const char **args, int *orig_arg, struct proxy *px,
|
||||
int default_status, char **errmsg);
|
||||
|
||||
struct buffer *http_load_errorfile(const char *file, char **errmsg);
|
||||
struct buffer *http_load_errormsg(const char *key, const struct ist msg, char **errmsg);
|
||||
|
373
src/http_act.c
373
src/http_act.c
@ -11,8 +11,6 @@
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
@ -1980,381 +1978,24 @@ static int check_http_return_action(struct act_rule *rule, struct proxy *px, cha
|
||||
}
|
||||
|
||||
/* Parse a "return" action. It returns ACT_RET_PRS_OK on success,
|
||||
* ACT_RET_PRS_ERR on error. This function creates one of the following http
|
||||
* replies :
|
||||
*
|
||||
* - HTTP_REPLY_EMPTY : dummy response, no payload
|
||||
* - HTTP_REPLY_ERRMSG : implicit error message depending on the status code or explicit one
|
||||
* - HTTP_REPLY_ERRFILES : points on an http-errors section (resolved during post-parsing)
|
||||
* - HTTP_REPLY_RAW : explicit file object ('file' argument)
|
||||
* - HTTP_REPLY_LOGFMT : explicit log-format string ('content' argument)
|
||||
*
|
||||
* The content-type must be defined for non-empty payload. It is ignored for
|
||||
* error messages (implicit or explicit). When an http-errors section is
|
||||
* referenced, action is set to -1 and the real action is resolved during the
|
||||
* configuration validity check.
|
||||
* ACT_RET_PRS_ERR on error. It relies on http_parse_http_reply() to set
|
||||
* <.arg.http_reply>.
|
||||
*/
|
||||
static enum act_parse_ret parse_http_return(const char **args, int *orig_arg, struct proxy *px,
|
||||
struct act_rule *rule, char **err)
|
||||
{
|
||||
struct logformat_node *lf, *lfb;
|
||||
struct http_reply *reply = NULL;
|
||||
struct http_reply_hdr *hdr, *hdrb;
|
||||
struct stat stat;
|
||||
const char *act_arg = NULL;
|
||||
char *obj = NULL;
|
||||
int cur_arg, cap, objlen = 0, fd = -1;
|
||||
/* Prepare parsing of log-format strings */
|
||||
px->conf.args.ctx = ((rule->from == ACT_F_HTTP_REQ) ? ARGC_HRQ : ARGC_HRS);
|
||||
rule->arg.http_reply = http_parse_http_reply(args, orig_arg, px, 200, err);
|
||||
if (!rule->arg.http_reply)
|
||||
return ACT_RET_PRS_ERR;
|
||||
|
||||
reply = calloc(1, sizeof(*reply));
|
||||
if (!reply) {
|
||||
memprintf(err, "out of memory");
|
||||
goto error;
|
||||
}
|
||||
LIST_INIT(&reply->hdrs);
|
||||
reply->type = HTTP_REPLY_EMPTY;
|
||||
reply->status = 200;
|
||||
|
||||
cur_arg = *orig_arg;
|
||||
while (*args[cur_arg]) {
|
||||
if (strcmp(args[cur_arg], "status") == 0) {
|
||||
cur_arg++;
|
||||
if (!*args[cur_arg]) {
|
||||
memprintf(err, "'%s' expects <status_code> as argument", args[cur_arg-1]);
|
||||
goto error;
|
||||
}
|
||||
reply->status = atol(args[cur_arg]);
|
||||
if (reply->status < 200 || reply->status > 599) {
|
||||
memprintf(err, "Unexpected status code '%d'", reply->status);
|
||||
goto error;
|
||||
}
|
||||
cur_arg++;
|
||||
}
|
||||
else if (strcmp(args[cur_arg], "content-type") == 0) {
|
||||
cur_arg++;
|
||||
if (!*args[cur_arg]) {
|
||||
memprintf(err, "'%s' expects <ctype> as argument", args[cur_arg-1]);
|
||||
goto error;
|
||||
}
|
||||
free(reply->ctype);
|
||||
reply->ctype = strdup(args[cur_arg]);
|
||||
cur_arg++;
|
||||
}
|
||||
else if (strcmp(args[cur_arg], "errorfiles") == 0) {
|
||||
if (reply->type != HTTP_REPLY_EMPTY) {
|
||||
memprintf(err, "unexpected '%s' argument, '%s' already defined", args[cur_arg], act_arg);
|
||||
goto error;
|
||||
}
|
||||
act_arg = args[cur_arg];
|
||||
cur_arg++;
|
||||
if (!*args[cur_arg]) {
|
||||
memprintf(err, "'%s' expects <name> as argument", args[cur_arg-1]);
|
||||
goto error;
|
||||
}
|
||||
reply->body.http_errors = strdup(args[cur_arg]);
|
||||
if (!reply->body.http_errors) {
|
||||
memprintf(err, "out of memory");
|
||||
goto error;
|
||||
}
|
||||
reply->type = HTTP_REPLY_ERRFILES;
|
||||
cur_arg++;
|
||||
}
|
||||
else if (strcmp(args[cur_arg], "default-errorfiles") == 0) {
|
||||
if (reply->type != HTTP_REPLY_EMPTY) {
|
||||
memprintf(err, "unexpected '%s' argument, '%s' already defined", args[cur_arg], act_arg);
|
||||
goto error;
|
||||
}
|
||||
act_arg = args[cur_arg];
|
||||
reply->type = HTTP_REPLY_ERRMSG;
|
||||
cur_arg++;
|
||||
}
|
||||
else if (strcmp(args[cur_arg], "errorfile") == 0) {
|
||||
if (reply->type != HTTP_REPLY_EMPTY) {
|
||||
memprintf(err, "unexpected '%s' argument, '%s' already defined", args[cur_arg], act_arg);
|
||||
goto error;
|
||||
}
|
||||
act_arg = args[cur_arg];
|
||||
cur_arg++;
|
||||
if (!*args[cur_arg]) {
|
||||
memprintf(err, "'%s' expects <fmt> as argument", args[cur_arg-1]);
|
||||
goto error;
|
||||
}
|
||||
reply->body.errmsg = http_load_errorfile(args[cur_arg], err);
|
||||
if (!reply->body.errmsg) {
|
||||
goto error;
|
||||
}
|
||||
reply->type = HTTP_REPLY_ERRMSG;
|
||||
cur_arg++;
|
||||
}
|
||||
else if (strcmp(args[cur_arg], "file") == 0) {
|
||||
if (reply->type != HTTP_REPLY_EMPTY) {
|
||||
memprintf(err, "unexpected '%s' argument, '%s' already defined", args[cur_arg], act_arg);
|
||||
goto error;
|
||||
}
|
||||
act_arg = args[cur_arg];
|
||||
cur_arg++;
|
||||
if (!*args[cur_arg]) {
|
||||
memprintf(err, "'%s' expects <file> as argument", args[cur_arg-1]);
|
||||
goto error;
|
||||
}
|
||||
fd = open(args[cur_arg], O_RDONLY);
|
||||
if ((fd < 0) || (fstat(fd, &stat) < 0)) {
|
||||
memprintf(err, "error opening file '%s'", args[cur_arg]);
|
||||
goto error;
|
||||
}
|
||||
if (stat.st_size > global.tune.bufsize) {
|
||||
memprintf(err, "file '%s' exceeds the buffer size (%lld > %d)",
|
||||
args[cur_arg], (long long)stat.st_size, global.tune.bufsize);
|
||||
goto error;
|
||||
}
|
||||
objlen = stat.st_size;
|
||||
obj = malloc(objlen);
|
||||
if (!obj || read(fd, obj, objlen) != objlen) {
|
||||
memprintf(err, "error reading file '%s'", args[cur_arg]);
|
||||
goto error;
|
||||
}
|
||||
close(fd);
|
||||
fd = -1;
|
||||
reply->type = HTTP_REPLY_RAW;
|
||||
chunk_initlen(&reply->body.obj, obj, global.tune.bufsize, objlen);
|
||||
obj = NULL;
|
||||
cur_arg++;
|
||||
}
|
||||
else if (strcmp(args[cur_arg], "string") == 0) {
|
||||
if (reply->type != HTTP_REPLY_EMPTY) {
|
||||
memprintf(err, "unexpected '%s' argument, '%s' already defined", args[cur_arg], act_arg);
|
||||
goto error;
|
||||
}
|
||||
act_arg = args[cur_arg];
|
||||
cur_arg++;
|
||||
if (!*args[cur_arg]) {
|
||||
memprintf(err, "'%s' expects <str> as argument", args[cur_arg-1]);
|
||||
goto error;
|
||||
}
|
||||
obj = strdup(args[cur_arg]);
|
||||
objlen = strlen(args[cur_arg]);
|
||||
if (!obj) {
|
||||
memprintf(err, "out of memory");
|
||||
goto error;
|
||||
}
|
||||
reply->type = HTTP_REPLY_RAW;
|
||||
chunk_initlen(&reply->body.obj, obj, global.tune.bufsize, objlen);
|
||||
obj = NULL;
|
||||
cur_arg++;
|
||||
}
|
||||
else if (strcmp(args[cur_arg], "lf-file") == 0) {
|
||||
if (reply->type != HTTP_REPLY_EMPTY) {
|
||||
memprintf(err, "unexpected '%s' argument, '%s' already defined", args[cur_arg], act_arg);
|
||||
goto error;
|
||||
}
|
||||
act_arg = args[cur_arg];
|
||||
cur_arg++;
|
||||
if (!*args[cur_arg]) {
|
||||
memprintf(err, "'%s' expects <file> as argument", args[cur_arg-1]);
|
||||
goto error;
|
||||
}
|
||||
fd = open(args[cur_arg], O_RDONLY);
|
||||
if ((fd < 0) || (fstat(fd, &stat) < 0)) {
|
||||
memprintf(err, "error opening file '%s'", args[cur_arg]);
|
||||
goto error;
|
||||
}
|
||||
if (stat.st_size > global.tune.bufsize) {
|
||||
memprintf(err, "file '%s' exceeds the buffer size (%lld > %d)",
|
||||
args[cur_arg], (long long)stat.st_size, global.tune.bufsize);
|
||||
goto error;
|
||||
}
|
||||
objlen = stat.st_size;
|
||||
obj = malloc(objlen + 1);
|
||||
if (!obj || read(fd, obj, objlen) != objlen) {
|
||||
memprintf(err, "error reading file '%s'", args[cur_arg]);
|
||||
goto error;
|
||||
}
|
||||
close(fd);
|
||||
fd = -1;
|
||||
obj[objlen] = '\0';
|
||||
reply->type = HTTP_REPLY_LOGFMT;
|
||||
cur_arg++;
|
||||
}
|
||||
else if (strcmp(args[cur_arg], "lf-string") == 0) {
|
||||
if (reply->type != HTTP_REPLY_EMPTY) {
|
||||
memprintf(err, "unexpected '%s' argument, '%s' already defined", args[cur_arg], act_arg);
|
||||
goto error;
|
||||
}
|
||||
act_arg = args[cur_arg];
|
||||
cur_arg++;
|
||||
if (!*args[cur_arg]) {
|
||||
memprintf(err, "'%s' expects <fmt> as argument", args[cur_arg-1]);
|
||||
goto error;
|
||||
}
|
||||
obj = strdup(args[cur_arg]);
|
||||
objlen = strlen(args[cur_arg]);
|
||||
reply->type = HTTP_REPLY_LOGFMT;
|
||||
cur_arg++;
|
||||
}
|
||||
else if (strcmp(args[cur_arg], "hdr") == 0) {
|
||||
cur_arg++;
|
||||
if (!*args[cur_arg] || !*args[cur_arg+1]) {
|
||||
memprintf(err, "'%s' expects <name> and <value> as arguments", args[cur_arg-1]);
|
||||
goto error;
|
||||
}
|
||||
if (strcasecmp(args[cur_arg], "content-length") == 0 ||
|
||||
strcasecmp(args[cur_arg], "transfer-encoding") == 0 ||
|
||||
strcasecmp(args[cur_arg], "content-type") == 0) {
|
||||
ha_warning("parsing [%s:%d] : 'http-%s return' : header '%s' ignored.\n",
|
||||
px->conf.args.file, px->conf.args.line,
|
||||
(rule->from == ACT_F_HTTP_REQ ? "request" : "response"),
|
||||
args[cur_arg]);
|
||||
cur_arg += 2;
|
||||
continue;
|
||||
}
|
||||
hdr = calloc(1, sizeof(*hdr));
|
||||
if (!hdr) {
|
||||
memprintf(err, "'%s' : out of memory", args[cur_arg-1]);
|
||||
goto error;
|
||||
}
|
||||
LIST_INIT(&hdr->value);
|
||||
hdr->name = ist(strdup(args[cur_arg]));
|
||||
if (!isttest(hdr->name)) {
|
||||
memprintf(err, "out of memory");
|
||||
goto error;
|
||||
}
|
||||
LIST_ADDQ(&reply->hdrs, &hdr->list);
|
||||
|
||||
if (rule->from == ACT_F_HTTP_REQ) {
|
||||
px->conf.args.ctx = ARGC_HRQ;
|
||||
cap = (px->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR;
|
||||
}
|
||||
else {
|
||||
px->conf.args.ctx = ARGC_HRS;
|
||||
cap = (px->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR;
|
||||
}
|
||||
if (!parse_logformat_string(args[cur_arg+1], px, &hdr->value, LOG_OPT_HTTP, cap, err))
|
||||
goto error;
|
||||
|
||||
free(px->conf.lfs_file);
|
||||
px->conf.lfs_file = strdup(px->conf.args.file);
|
||||
px->conf.lfs_line = px->conf.args.line;
|
||||
cur_arg += 2;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (reply->type == HTTP_REPLY_EMPTY) { /* no payload */
|
||||
if (reply->ctype) {
|
||||
ha_warning("parsing [%s:%d] : 'http-%s return' : content-type '%s' ignored because"
|
||||
" neither errorfile nor payload defined.\n",
|
||||
px->conf.args.file, px->conf.args.line,
|
||||
(rule->from == ACT_F_HTTP_REQ ? "request" : "response"),
|
||||
reply->ctype);
|
||||
free(reply->ctype);
|
||||
reply->ctype = NULL;
|
||||
}
|
||||
}
|
||||
else if (reply->type == HTTP_REPLY_ERRFILES || reply->type == HTTP_REPLY_ERRMSG) { /* errorfiles or errorfile */
|
||||
|
||||
if (reply->type != HTTP_REPLY_ERRMSG || !reply->body.errmsg) {
|
||||
/* default errorfile or errorfiles: check the status */
|
||||
int rc;
|
||||
|
||||
for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
|
||||
if (http_err_codes[rc] == reply->status)
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc >= HTTP_ERR_SIZE) {
|
||||
memprintf(err, "status code '%d' not handled by default with '%s' argument.",
|
||||
reply->status, act_arg);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (reply->ctype) {
|
||||
ha_warning("parsing [%s:%d] : 'http-%s return' : content-type '%s' ignored when the "
|
||||
"returned response is an erorrfile.\n",
|
||||
px->conf.args.file, px->conf.args.line,
|
||||
(rule->from == ACT_F_HTTP_REQ ? "request" : "response"),
|
||||
reply->ctype);
|
||||
free(reply->ctype);
|
||||
reply->ctype = NULL;
|
||||
}
|
||||
if (!LIST_ISEMPTY(&reply->hdrs)) {
|
||||
ha_warning("parsing [%s:%d] : 'http-%s return' : hdr parameters ignored when the "
|
||||
"returned response is an erorrfile.\n",
|
||||
px->conf.args.file, px->conf.args.line,
|
||||
(rule->from == ACT_F_HTTP_REQ ? "request" : "response"));
|
||||
list_for_each_entry_safe(hdr, hdrb, &reply->hdrs, list) {
|
||||
LIST_DEL(&hdr->list);
|
||||
list_for_each_entry_safe(lf, lfb, &hdr->value, list) {
|
||||
LIST_DEL(&lf->list);
|
||||
release_sample_expr(lf->expr);
|
||||
free(lf->arg);
|
||||
free(lf);
|
||||
}
|
||||
istfree(&hdr->name);
|
||||
free(hdr);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (reply->type == HTTP_REPLY_RAW) { /* explicit parameter using 'file' parameter*/
|
||||
if (!reply->ctype && objlen) {
|
||||
memprintf(err, "a content type must be defined when non-empty payload is configured");
|
||||
goto error;
|
||||
}
|
||||
if (reply->ctype && !b_data(&reply->body.obj)) {
|
||||
ha_warning("parsing [%s:%d] : 'http-%s return' : content-type '%s' ignored when the "
|
||||
"configured payload is empty.\n",
|
||||
px->conf.args.file, px->conf.args.line,
|
||||
(rule->from == ACT_F_HTTP_REQ ? "request" : "response"),
|
||||
reply->ctype);
|
||||
free(reply->ctype);
|
||||
reply->ctype = NULL;
|
||||
}
|
||||
if (b_room(&reply->body.obj) < global.tune.maxrewrite) {
|
||||
ha_warning("parsing [%s:%d] : 'http-%s return' : the payload runs over the buffer space reserved to headers rewriting."
|
||||
" It may lead to internal errors if strict rewriting mode is enabled.\n",
|
||||
px->conf.args.file, px->conf.args.line,
|
||||
(rule->from == ACT_F_HTTP_REQ ? "request" : "response"));
|
||||
}
|
||||
}
|
||||
else if (reply->type == HTTP_REPLY_LOGFMT) { /* log-format payload using 'lf-file' of 'lf-string' parameter */
|
||||
LIST_INIT(&reply->body.fmt);
|
||||
if (!reply->ctype) {
|
||||
memprintf(err, "a content type must be defined with a log-format payload");
|
||||
goto error;
|
||||
}
|
||||
if (rule->from == ACT_F_HTTP_REQ) {
|
||||
px->conf.args.ctx = ARGC_HRQ;
|
||||
cap = (px->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR;
|
||||
}
|
||||
else {
|
||||
px->conf.args.ctx = ARGC_HRS;
|
||||
cap = (px->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR;
|
||||
}
|
||||
if (!parse_logformat_string(obj, px, &reply->body.fmt, LOG_OPT_HTTP, cap, err))
|
||||
goto error;
|
||||
|
||||
free(px->conf.lfs_file);
|
||||
px->conf.lfs_file = strdup(px->conf.args.file);
|
||||
px->conf.lfs_line = px->conf.args.line;
|
||||
}
|
||||
|
||||
rule->arg.http_reply = reply;
|
||||
rule->flags |= ACT_FLAG_FINAL;
|
||||
rule->action = ACT_CUSTOM;
|
||||
rule->check_ptr = check_http_return_action;
|
||||
rule->action_ptr = http_action_return;
|
||||
rule->release_ptr = release_http_return;
|
||||
|
||||
free(obj);
|
||||
*orig_arg = cur_arg;
|
||||
return ACT_RET_PRS_OK;
|
||||
|
||||
error:
|
||||
free(obj);
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
release_http_reply(reply);
|
||||
return ACT_RET_PRS_ERR;
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
350
src/http_htx.c
350
src/http_htx.c
@ -1241,6 +1241,356 @@ out:
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Parse an "http reply". It returns the reply on success or NULL on error. This
|
||||
* function creates one of the following http replies :
|
||||
*
|
||||
* - HTTP_REPLY_EMPTY : dummy response, no payload
|
||||
* - HTTP_REPLY_ERRMSG : implicit error message depending on the status code or explicit one
|
||||
* - HTTP_REPLY_ERRFILES : points on an http-errors section (resolved during post-parsing)
|
||||
* - HTTP_REPLY_RAW : explicit file object ('file' argument)
|
||||
* - HTTP_REPLY_LOGFMT : explicit log-format string ('content' argument)
|
||||
*
|
||||
* The content-type must be defined for non-empty payload. It is ignored for
|
||||
* error messages (implicit or explicit). When an http-errors section is
|
||||
* referenced (HTTP_REPLY_ERRFILES), the real error message should be resolved
|
||||
* during the configuration validity check or dynamically. It is the caller
|
||||
* responsibility to choose. If no status code is configured, <default_status>
|
||||
* is set.
|
||||
*/
|
||||
struct http_reply *http_parse_http_reply(const char **args, int *orig_arg, struct proxy *px,
|
||||
int default_status, char **errmsg)
|
||||
{
|
||||
struct logformat_node *lf, *lfb;
|
||||
struct http_reply *reply = NULL;
|
||||
struct http_reply_hdr *hdr, *hdrb;
|
||||
struct stat stat;
|
||||
const char *act_arg = NULL;
|
||||
char *obj = NULL;
|
||||
int cur_arg, cap, objlen = 0, fd = -1;
|
||||
|
||||
|
||||
reply = calloc(1, sizeof(*reply));
|
||||
if (!reply) {
|
||||
memprintf(errmsg, "out of memory");
|
||||
goto error;
|
||||
}
|
||||
LIST_INIT(&reply->hdrs);
|
||||
reply->type = HTTP_REPLY_EMPTY;
|
||||
reply->status = default_status;
|
||||
|
||||
cap = ((px->conf.args.ctx == ARGC_HRQ)
|
||||
? ((px->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR)
|
||||
: ((px->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR));
|
||||
|
||||
cur_arg = *orig_arg;
|
||||
while (*args[cur_arg]) {
|
||||
if (strcmp(args[cur_arg], "status") == 0) {
|
||||
cur_arg++;
|
||||
if (!*args[cur_arg]) {
|
||||
memprintf(errmsg, "'%s' expects <status_code> as argument", args[cur_arg-1]);
|
||||
goto error;
|
||||
}
|
||||
reply->status = atol(args[cur_arg]);
|
||||
if (reply->status < 200 || reply->status > 599) {
|
||||
memprintf(errmsg, "Unexpected status code '%d'", reply->status);
|
||||
goto error;
|
||||
}
|
||||
cur_arg++;
|
||||
}
|
||||
else if (strcmp(args[cur_arg], "content-type") == 0) {
|
||||
cur_arg++;
|
||||
if (!*args[cur_arg]) {
|
||||
memprintf(errmsg, "'%s' expects <ctype> as argument", args[cur_arg-1]);
|
||||
goto error;
|
||||
}
|
||||
free(reply->ctype);
|
||||
reply->ctype = strdup(args[cur_arg]);
|
||||
cur_arg++;
|
||||
}
|
||||
else if (strcmp(args[cur_arg], "errorfiles") == 0) {
|
||||
if (reply->type != HTTP_REPLY_EMPTY) {
|
||||
memprintf(errmsg, "unexpected '%s' argument, '%s' already defined", args[cur_arg], act_arg);
|
||||
goto error;
|
||||
}
|
||||
act_arg = args[cur_arg];
|
||||
cur_arg++;
|
||||
if (!*args[cur_arg]) {
|
||||
memprintf(errmsg, "'%s' expects <name> as argument", args[cur_arg-1]);
|
||||
goto error;
|
||||
}
|
||||
reply->body.http_errors = strdup(args[cur_arg]);
|
||||
if (!reply->body.http_errors) {
|
||||
memprintf(errmsg, "out of memory");
|
||||
goto error;
|
||||
}
|
||||
reply->type = HTTP_REPLY_ERRFILES;
|
||||
cur_arg++;
|
||||
}
|
||||
else if (strcmp(args[cur_arg], "default-errorfiles") == 0) {
|
||||
if (reply->type != HTTP_REPLY_EMPTY) {
|
||||
memprintf(errmsg, "unexpected '%s' argument, '%s' already defined", args[cur_arg], act_arg);
|
||||
goto error;
|
||||
}
|
||||
act_arg = args[cur_arg];
|
||||
reply->type = HTTP_REPLY_ERRMSG;
|
||||
cur_arg++;
|
||||
}
|
||||
else if (strcmp(args[cur_arg], "errorfile") == 0) {
|
||||
if (reply->type != HTTP_REPLY_EMPTY) {
|
||||
memprintf(errmsg, "unexpected '%s' argument, '%s' already defined", args[cur_arg], act_arg);
|
||||
goto error;
|
||||
}
|
||||
act_arg = args[cur_arg];
|
||||
cur_arg++;
|
||||
if (!*args[cur_arg]) {
|
||||
memprintf(errmsg, "'%s' expects <fmt> as argument", args[cur_arg-1]);
|
||||
goto error;
|
||||
}
|
||||
reply->body.errmsg = http_load_errorfile(args[cur_arg], errmsg);
|
||||
if (!reply->body.errmsg) {
|
||||
goto error;
|
||||
}
|
||||
reply->type = HTTP_REPLY_ERRMSG;
|
||||
cur_arg++;
|
||||
}
|
||||
else if (strcmp(args[cur_arg], "file") == 0) {
|
||||
if (reply->type != HTTP_REPLY_EMPTY) {
|
||||
memprintf(errmsg, "unexpected '%s' argument, '%s' already defined", args[cur_arg], act_arg);
|
||||
goto error;
|
||||
}
|
||||
act_arg = args[cur_arg];
|
||||
cur_arg++;
|
||||
if (!*args[cur_arg]) {
|
||||
memprintf(errmsg, "'%s' expects <file> as argument", args[cur_arg-1]);
|
||||
goto error;
|
||||
}
|
||||
fd = open(args[cur_arg], O_RDONLY);
|
||||
if ((fd < 0) || (fstat(fd, &stat) < 0)) {
|
||||
memprintf(errmsg, "error opening file '%s'", args[cur_arg]);
|
||||
goto error;
|
||||
}
|
||||
if (stat.st_size > global.tune.bufsize) {
|
||||
memprintf(errmsg, "file '%s' exceeds the buffer size (%lld > %d)",
|
||||
args[cur_arg], (long long)stat.st_size, global.tune.bufsize);
|
||||
goto error;
|
||||
}
|
||||
objlen = stat.st_size;
|
||||
obj = malloc(objlen);
|
||||
if (!obj || read(fd, obj, objlen) != objlen) {
|
||||
memprintf(errmsg, "error reading file '%s'", args[cur_arg]);
|
||||
goto error;
|
||||
}
|
||||
close(fd);
|
||||
fd = -1;
|
||||
reply->type = HTTP_REPLY_RAW;
|
||||
chunk_initlen(&reply->body.obj, obj, global.tune.bufsize, objlen);
|
||||
obj = NULL;
|
||||
cur_arg++;
|
||||
}
|
||||
else if (strcmp(args[cur_arg], "string") == 0) {
|
||||
if (reply->type != HTTP_REPLY_EMPTY) {
|
||||
memprintf(errmsg, "unexpected '%s' argument, '%s' already defined", args[cur_arg], act_arg);
|
||||
goto error;
|
||||
}
|
||||
act_arg = args[cur_arg];
|
||||
cur_arg++;
|
||||
if (!*args[cur_arg]) {
|
||||
memprintf(errmsg, "'%s' expects <str> as argument", args[cur_arg-1]);
|
||||
goto error;
|
||||
}
|
||||
obj = strdup(args[cur_arg]);
|
||||
objlen = strlen(args[cur_arg]);
|
||||
if (!obj) {
|
||||
memprintf(errmsg, "out of memory");
|
||||
goto error;
|
||||
}
|
||||
reply->type = HTTP_REPLY_RAW;
|
||||
chunk_initlen(&reply->body.obj, obj, global.tune.bufsize, objlen);
|
||||
obj = NULL;
|
||||
cur_arg++;
|
||||
}
|
||||
else if (strcmp(args[cur_arg], "lf-file") == 0) {
|
||||
if (reply->type != HTTP_REPLY_EMPTY) {
|
||||
memprintf(errmsg, "unexpected '%s' argument, '%s' already defined", args[cur_arg], act_arg);
|
||||
goto error;
|
||||
}
|
||||
act_arg = args[cur_arg];
|
||||
cur_arg++;
|
||||
if (!*args[cur_arg]) {
|
||||
memprintf(errmsg, "'%s' expects <file> as argument", args[cur_arg-1]);
|
||||
goto error;
|
||||
}
|
||||
fd = open(args[cur_arg], O_RDONLY);
|
||||
if ((fd < 0) || (fstat(fd, &stat) < 0)) {
|
||||
memprintf(errmsg, "error opening file '%s'", args[cur_arg]);
|
||||
goto error;
|
||||
}
|
||||
if (stat.st_size > global.tune.bufsize) {
|
||||
memprintf(errmsg, "file '%s' exceeds the buffer size (%lld > %d)",
|
||||
args[cur_arg], (long long)stat.st_size, global.tune.bufsize);
|
||||
goto error;
|
||||
}
|
||||
objlen = stat.st_size;
|
||||
obj = malloc(objlen + 1);
|
||||
if (!obj || read(fd, obj, objlen) != objlen) {
|
||||
memprintf(errmsg, "error reading file '%s'", args[cur_arg]);
|
||||
goto error;
|
||||
}
|
||||
close(fd);
|
||||
fd = -1;
|
||||
obj[objlen] = '\0';
|
||||
reply->type = HTTP_REPLY_LOGFMT;
|
||||
cur_arg++;
|
||||
}
|
||||
else if (strcmp(args[cur_arg], "lf-string") == 0) {
|
||||
if (reply->type != HTTP_REPLY_EMPTY) {
|
||||
memprintf(errmsg, "unexpected '%s' argument, '%s' already defined", args[cur_arg], act_arg);
|
||||
goto error;
|
||||
}
|
||||
act_arg = args[cur_arg];
|
||||
cur_arg++;
|
||||
if (!*args[cur_arg]) {
|
||||
memprintf(errmsg, "'%s' expects <fmt> as argument", args[cur_arg-1]);
|
||||
goto error;
|
||||
}
|
||||
obj = strdup(args[cur_arg]);
|
||||
objlen = strlen(args[cur_arg]);
|
||||
reply->type = HTTP_REPLY_LOGFMT;
|
||||
cur_arg++;
|
||||
}
|
||||
else if (strcmp(args[cur_arg], "hdr") == 0) {
|
||||
cur_arg++;
|
||||
if (!*args[cur_arg] || !*args[cur_arg+1]) {
|
||||
memprintf(errmsg, "'%s' expects <name> and <value> as arguments", args[cur_arg-1]);
|
||||
goto error;
|
||||
}
|
||||
if (strcasecmp(args[cur_arg], "content-length") == 0 ||
|
||||
strcasecmp(args[cur_arg], "transfer-encoding") == 0 ||
|
||||
strcasecmp(args[cur_arg], "content-type") == 0) {
|
||||
ha_warning("parsing [%s:%d] : header '%s' always ignored by the http reply.\n",
|
||||
px->conf.args.file, px->conf.args.line, args[cur_arg]);
|
||||
cur_arg += 2;
|
||||
continue;
|
||||
}
|
||||
hdr = calloc(1, sizeof(*hdr));
|
||||
if (!hdr) {
|
||||
memprintf(errmsg, "'%s' : out of memory", args[cur_arg-1]);
|
||||
goto error;
|
||||
}
|
||||
LIST_INIT(&hdr->value);
|
||||
hdr->name = ist(strdup(args[cur_arg]));
|
||||
if (!isttest(hdr->name)) {
|
||||
memprintf(errmsg, "out of memory");
|
||||
goto error;
|
||||
}
|
||||
LIST_ADDQ(&reply->hdrs, &hdr->list);
|
||||
if (!parse_logformat_string(args[cur_arg+1], px, &hdr->value, LOG_OPT_HTTP, cap, errmsg))
|
||||
goto error;
|
||||
|
||||
free(px->conf.lfs_file);
|
||||
px->conf.lfs_file = strdup(px->conf.args.file);
|
||||
px->conf.lfs_line = px->conf.args.line;
|
||||
cur_arg += 2;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (reply->type == HTTP_REPLY_EMPTY) { /* no payload */
|
||||
if (reply->ctype) {
|
||||
ha_warning("parsing [%s:%d] : content-type '%s' ignored by the http reply because"
|
||||
" neither errorfile nor payload defined.\n",
|
||||
px->conf.args.file, px->conf.args.line, reply->ctype);
|
||||
free(reply->ctype);
|
||||
reply->ctype = NULL;
|
||||
}
|
||||
}
|
||||
else if (reply->type == HTTP_REPLY_ERRFILES || reply->type == HTTP_REPLY_ERRMSG) { /* errorfiles or errorfile */
|
||||
|
||||
if (reply->type != HTTP_REPLY_ERRMSG || !reply->body.errmsg) {
|
||||
/* default errorfile or errorfiles: check the status */
|
||||
int rc;
|
||||
|
||||
for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
|
||||
if (http_err_codes[rc] == reply->status)
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc >= HTTP_ERR_SIZE) {
|
||||
memprintf(errmsg, "status code '%d' not handled by default with '%s' argument.",
|
||||
reply->status, act_arg);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (reply->ctype) {
|
||||
ha_warning("parsing [%s:%d] : content-type '%s' ignored by the http reply when used "
|
||||
"with an erorrfile.\n",
|
||||
px->conf.args.file, px->conf.args.line, reply->ctype);
|
||||
free(reply->ctype);
|
||||
reply->ctype = NULL;
|
||||
}
|
||||
if (!LIST_ISEMPTY(&reply->hdrs)) {
|
||||
ha_warning("parsing [%s:%d] : hdr parameters ignored by the http reply when used "
|
||||
"with an erorrfile.\n",
|
||||
px->conf.args.file, px->conf.args.line);
|
||||
list_for_each_entry_safe(hdr, hdrb, &reply->hdrs, list) {
|
||||
LIST_DEL(&hdr->list);
|
||||
list_for_each_entry_safe(lf, lfb, &hdr->value, list) {
|
||||
LIST_DEL(&lf->list);
|
||||
release_sample_expr(lf->expr);
|
||||
free(lf->arg);
|
||||
free(lf);
|
||||
}
|
||||
istfree(&hdr->name);
|
||||
free(hdr);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (reply->type == HTTP_REPLY_RAW) { /* explicit parameter using 'file' parameter*/
|
||||
if (!reply->ctype && objlen) {
|
||||
memprintf(errmsg, "a content type must be defined when non-empty payload is configured");
|
||||
goto error;
|
||||
}
|
||||
if (reply->ctype && !b_data(&reply->body.obj)) {
|
||||
ha_warning("parsing [%s:%d] : content-type '%s' ignored by the http reply when used "
|
||||
"with an emtpy payload.\n",
|
||||
px->conf.args.file, px->conf.args.line, reply->ctype);
|
||||
free(reply->ctype);
|
||||
reply->ctype = NULL;
|
||||
}
|
||||
if (b_room(&reply->body.obj) < global.tune.maxrewrite) {
|
||||
ha_warning("parsing [%s:%d] : http reply payload runs over the buffer space reserved to headers rewriting."
|
||||
" It may lead to internal errors if strict rewriting mode is enabled.\n",
|
||||
px->conf.args.file, px->conf.args.line);
|
||||
}
|
||||
}
|
||||
else if (reply->type == HTTP_REPLY_LOGFMT) { /* log-format payload using 'lf-file' of 'lf-string' parameter */
|
||||
LIST_INIT(&reply->body.fmt);
|
||||
if (!reply->ctype) {
|
||||
memprintf(errmsg, "a content type must be defined with a log-format payload");
|
||||
goto error;
|
||||
}
|
||||
if (!parse_logformat_string(obj, px, &reply->body.fmt, LOG_OPT_HTTP, cap, errmsg))
|
||||
goto error;
|
||||
|
||||
free(px->conf.lfs_file);
|
||||
px->conf.lfs_file = strdup(px->conf.args.file);
|
||||
px->conf.lfs_line = px->conf.args.line;
|
||||
}
|
||||
|
||||
free(obj);
|
||||
*orig_arg = cur_arg;
|
||||
return reply;
|
||||
|
||||
error:
|
||||
free(obj);
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
release_http_reply(reply);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Parses the "errorloc[302|303]" proxy keyword */
|
||||
static int proxy_parse_errorloc(char **args, int section, struct proxy *curpx,
|
||||
struct proxy *defpx, const char *file, int line,
|
||||
|
Loading…
Reference in New Issue
Block a user