diff --git a/src/backend.c b/src/backend.c index 3f30bea04..b8bf7dd66 100644 --- a/src/backend.c +++ b/src/backend.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -256,11 +257,11 @@ struct server *get_server_ph_post(struct session *s) struct proxy *px = s->be; unsigned int plen = px->url_param_len; unsigned long len = msg->body_len; - const char *params = req->p + msg->sov; + const char *params = b_ptr(req, (int)(msg->sov - req->o)); const char *p = params; - if (len > req->i - (msg->sov - msg->som)) - len = req->i - (msg->sov - msg->som); + if (len > buffer_len(req) - (msg->sov - msg->som)) + len = buffer_len(req) - (msg->sov - msg->som); if (len == 0) return NULL; @@ -342,7 +343,7 @@ struct server *get_server_hh(struct session *s) ctx.idx = 0; /* if the message is chunked, we skip the chunk size, but use the value as len */ - http_find_header2(px->hh_name, plen, s->req->p + msg->sol, &txn->hdr_idx, &ctx); + http_find_header2(px->hh_name, plen, b_ptr(s->req, (int)(msg->sol - s->req->o)), &txn->hdr_idx, &ctx); /* if the header is not found or empty, let's fallback to round robin */ if (!ctx.idx || !ctx.vlen) @@ -405,6 +406,7 @@ struct server *get_server_rch(struct session *s) int ret; struct sample smp; struct arg args[2]; + int rewind; /* tot_weight appears to mean srv_count */ if (px->lbprm.tot_weight == 0) @@ -417,9 +419,13 @@ struct server *get_server_rch(struct session *s) args[0].data.str.len = px->hh_len; args[1].type = ARGT_STOP; + b_rew(s->req, rewind = s->req->o); + ret = smp_fetch_rdp_cookie(px, s, NULL, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, args, &smp); len = smp.data.str.len; + b_adv(s->req, rewind); + if (ret == 0 || (smp.flags & SMP_F_MAY_CHANGE) || len == 0) return NULL; @@ -563,7 +569,7 @@ int assign_server(struct session *s) if (s->txn.req.msg_state < HTTP_MSG_BODY) break; srv = get_server_uh(s->be, - s->req->p + s->txn.req.sol + s->txn.req.sl.rq.u, + b_ptr(s->req, (int)(s->txn.req.sol + s->txn.req.sl.rq.u - s->req->o)), s->txn.req.sl.rq.u_l); break; @@ -573,7 +579,7 @@ int assign_server(struct session *s) break; srv = get_server_ph(s->be, - s->req->p + s->txn.req.sol + s->txn.req.sl.rq.u, + b_ptr(s->req, (int)(s->txn.req.sol + s->txn.req.sl.rq.u - s->req->o)), s->txn.req.sl.rq.u_l); if (!srv && s->txn.meth == HTTP_METH_POST) @@ -892,17 +898,20 @@ static void assign_tproxy_address(struct session *s) if (srv->bind_hdr_occ) { char *vptr; int vlen; + int rewind; /* bind to the IP in a header */ ((struct sockaddr_in *)&s->req->cons->addr.from)->sin_family = AF_INET; ((struct sockaddr_in *)&s->req->cons->addr.from)->sin_port = 0; ((struct sockaddr_in *)&s->req->cons->addr.from)->sin_addr.s_addr = 0; + b_rew(s->req, rewind = s->req->o); if (http_get_hdr(&s->txn.req, srv->bind_hdr_name, srv->bind_hdr_len, &s->txn.hdr_idx, srv->bind_hdr_occ, NULL, &vptr, &vlen)) { ((struct sockaddr_in *)&s->req->cons->addr.from)->sin_addr.s_addr = htonl(inetaddr_host_lim(vptr, vptr + vlen)); } + b_adv(s->req, rewind); } break; default: @@ -923,17 +932,20 @@ static void assign_tproxy_address(struct session *s) if (s->be->bind_hdr_occ) { char *vptr; int vlen; + int rewind; /* bind to the IP in a header */ ((struct sockaddr_in *)&s->req->cons->addr.from)->sin_family = AF_INET; ((struct sockaddr_in *)&s->req->cons->addr.from)->sin_port = 0; ((struct sockaddr_in *)&s->req->cons->addr.from)->sin_addr.s_addr = 0; + b_rew(s->req, rewind = s->req->o); if (http_get_hdr(&s->txn.req, s->be->bind_hdr_name, s->be->bind_hdr_len, &s->txn.hdr_idx, s->be->bind_hdr_occ, NULL, &vptr, &vlen)) { ((struct sockaddr_in *)&s->req->cons->addr.from)->sin_addr.s_addr = htonl(inetaddr_host_lim(vptr, vptr + vlen)); } + b_adv(s->req, rewind); } break; default: diff --git a/src/proto_http.c b/src/proto_http.c index 5250f2359..ccf0ab27e 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -3634,18 +3634,30 @@ int http_process_request_body(struct session *s, struct buffer *req, int an_bit) return 0; } -/* send a server's name with an outgoing request over an established connection */ +/* send a server's name with an outgoing request over an established connection. + * Note: this function is designed to be called once the request has been scheduled + * for being forwarded. This is the reason why it rewinds the buffer before + * proceeding. + */ int http_send_name_header(struct http_txn *txn, struct proxy* be, const char* srv_name) { struct hdr_ctx ctx; char *hdr_name = be->server_id_hdr_name; int hdr_name_len = be->server_id_hdr_len; - + struct buffer *req = txn->req.buf; char *hdr_val; + unsigned int old_o, old_i; ctx.idx = 0; + old_o = req->o; + if (old_o) { + /* The request was already skipped, let's restore it */ + b_rew(req, old_o); + } + + old_i = req->i; while (http_find_header2(hdr_name, hdr_name_len, txn->req.buf->p + txn->req.sol, &txn->hdr_idx, &ctx)) { /* remove any existing values from the header */ http_remove_header2(&txn->req, &txn->hdr_idx, &ctx); @@ -3660,6 +3672,14 @@ int http_send_name_header(struct http_txn *txn, struct proxy* be, const char* sr hdr_val += strlcpy2(hdr_val, srv_name, trash + trashlen - hdr_val); http_header_add_tail2(&txn->req, &txn->hdr_idx, trash, hdr_val - trash); + if (old_o) { + /* If this was a forwarded request, we must readjust the amount of + * data to be forwarded in order to take into account the size + * variations. + */ + b_adv(req, old_o + req->i - old_i); + } + return 0; }