} st; /* status line : field, length */
} sl; /* start line */
unsigned long long hdr_content_len; /* cache for parsed header value */
+ int err_pos; /* err handling: -2=block, -1=pass, 0+=detected */
};
/* This is an HTTP transaction. It contains both a request message and a
#define PR_O2_SPLIC_RTR 0x00000002 /* transfer responses using linux kernel's splice() */
#define PR_O2_SPLIC_AUT 0x00000004 /* automatically use linux kernel's splice() */
#define PR_O2_SPLIC_ANY (PR_O2_SPLIC_REQ|PR_O2_SPLIC_RTR|PR_O2_SPLIC_AUT)
+#define PR_O2_REQBUG_OK 0x00000008 /* let buggy requests pass through */
+#define PR_O2_RSPBUG_OK 0x00000010 /* let buggy responses pass through */
/* This structure is used to apply fast weighted round robin on a server group */
struct fwrr_group {
{ "splice-response", PR_O2_SPLIC_RTR, PR_CAP_FE|PR_CAP_BE, 0 },
{ "splice-auto", PR_O2_SPLIC_AUT, PR_CAP_FE|PR_CAP_BE, 0 },
#endif
+ { "accept-invalid-http-request", PR_O2_REQBUG_OK, PR_CAP_FE, 0 },
+ { "accept-invalid-http-response", PR_O2_RSPBUG_OK, PR_CAP_BE, 0 },
{ NULL, 0, 0, 0 }
};
txn->rsp.msg_state = HTTP_MSG_RPBEFORE; /* at the very beginning of the response */
txn->req.sol = txn->req.eol = NULL;
txn->req.som = txn->req.eoh = 0; /* relative to the buffer */
+ txn->req.err_pos = txn->rsp.err_pos = -2; /* block buggy requests/responses */
+ if (p->options2 & PR_O2_REQBUG_OK)
+ txn->req.err_pos = -1; /* let buggy requests pass */
txn->auth_hdr.len = -1;
if (p->nb_req_cap > 0) {
EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_sp, HTTP_MSG_HDR_L1_SP);
}
- goto http_msg_invalid;
+ if (likely(msg->err_pos < -1) || *ptr == '\n')
+ goto http_msg_invalid;
+
+ if (msg->err_pos == -1) /* capture error pointer */
+ msg->err_pos = ptr - buf->data; /* >= 0 now */
+
+ /* and we still accept this non-token character */
+ EAT_AND_JUMP_OR_RETURN(http_msg_hdr_name, HTTP_MSG_HDR_NAME);
http_msg_hdr_l1_sp:
case HTTP_MSG_HDR_L1_SP:
s->rep->rto = s->req->wto = s->be->timeout.server;
s->req->cto = s->be->timeout.connect;
s->conn_retries = s->be->conn_retries;
+ if (s->be->options2 & PR_O2_RSPBUG_OK)
+ s->txn.rsp.err_pos = -1; /* let buggy responses pass */
s->flags |= SN_BE_ASSIGNED;
break;
}
s->rep->rto = s->req->wto = s->be->timeout.server;
s->req->cto = s->be->timeout.connect;
s->conn_retries = s->be->conn_retries;
+ if (s->be->options2 & PR_O2_RSPBUG_OK)
+ s->txn.rsp.err_pos = -1; /* let buggy responses pass */
s->flags |= SN_BE_ASSIGNED;
}
} while (s->be != cur_proxy); /* we loop only if s->be has changed */
t->rep->rto = t->req->wto = t->be->timeout.server;
t->req->cto = t->be->timeout.connect;
t->conn_retries = t->be->conn_retries;
+ if (t->be->options2 & PR_O2_RSPBUG_OK)
+ t->txn.rsp.err_pos = -1; /* let buggy responses pass */
last_hdr = 1;
break;
t->rep->rto = t->req->wto = t->be->timeout.server;
t->req->cto = t->be->timeout.connect;
t->conn_retries = t->be->conn_retries;
+ if (t->be->options2 & PR_O2_RSPBUG_OK)
+ t->txn.rsp.err_pos = -1; /* let buggy responses pass */
done = 1;
break;