msg->msg_state = HTTP_MSG_RQBEFORE;
req->analysers = 0;
s->logs.logwait = 0;
- stream_int_cond_close(req->prod, NULL);
+ stream_int_retnclose(req->prod, NULL);
return 0;
}
/* keep-alive not possible */
memcpy(rdr.str + rdr.len, "\r\nConnection: close\r\n\r\n", 23);
rdr.len += 23;
- buffer_write(req->prod->ob, rdr.str, rdr.len);
- stream_int_cond_close(req->prod, NULL);
+ stream_int_retnclose(req->prod, &rdr);
goto return_prx_cond;
}
}
txn->req.msg_state = HTTP_MSG_ERROR;
txn->status = 400;
/* Note: we don't send any error if some data were already sent */
- stream_int_cond_close(req->prod, (txn->rsp.msg_state < HTTP_MSG_BODY) ? error_message(s, HTTP_ERR_400) : NULL);
-
- buffer_auto_read(req);
- buffer_auto_close(req);
+ stream_int_retnclose(req->prod, (txn->rsp.msg_state < HTTP_MSG_BODY) ? error_message(s, HTTP_ERR_400) : NULL);
req->analysers = 0;
s->fe->counters.failed_req++;
if (s->listener->counters)
return_bad_res: /* let's centralize all bad resuests */
txn->rsp.msg_state = HTTP_MSG_ERROR;
txn->status = 502;
- stream_int_cond_close(res->cons, NULL);
-
- buffer_auto_close(res);
- buffer_auto_read(res);
+ /* don't send any error message as we're in the body */
+ stream_int_retnclose(res->cons, NULL);
res->analysers = 0;
s->be->counters.failed_resp++;
if (s->srv) {
* and the request is cleared so that no server connection can be initiated.
* The buffer is marked for read shutdown on the other side to protect the
* message, and the buffer write is enabled. The message is contained in a
- * "chunk". If it is null, then an empty message is used. The reply buffer
- * doesn't need to be empty before this. The goal of this function is to
- * return error messages to a client.
+ * "chunk". If it is null, then an empty message is used. The reply buffer does
+ * not need to be empty before this, and its contents will not be overwritten.
+ * The primary goal of this function is to return error messages to a client.
*/
void stream_int_retnclose(struct stream_interface *si, const struct chunk *msg)
{
+ buffer_auto_read(si->ib);
buffer_abort(si->ib);
- buffer_erase(si->ob);
- buffer_shutr_now(si->ob);
- if (msg && msg->len)
+ buffer_auto_close(si->ib);
+ buffer_erase(si->ib);
+ if (likely(msg && msg->len))
buffer_write(si->ob, msg->str, msg->len);
si->ob->wex = tick_add_ifset(now_ms, si->ob->wto);
+ buffer_auto_read(si->ob);
buffer_auto_close(si->ob);
-}
-
-/* This function aborts all of the client's requests and stops the server's
- * response with the data that are already present. If the response buffer
- * empty, then the message in arguments will be sent. This ensures that
- * we won't mix an HTTP response with pending data. The buffer is marked for
- * read shutdown on the server side to protect the message or any pending
- * data, and the buffer write is enabled. The message is contained in a
- * "chunk". If it is null, then an empty message is used. The reply buffer
- * doesn't need to be empty before this. The goal of this function is to
- * return error messages to a client but only when it is possible.
- */
-void stream_int_cond_close(struct stream_interface *si, const struct chunk *msg)
-{
- buffer_abort(si->ib);
- buffer_erase(si->ib); /* remove any pending request */
buffer_shutr_now(si->ob);
- if (!si->ob->l && msg && msg->len)
- buffer_write(si->ob, msg->str, msg->len);
-
- si->ob->wex = tick_add_ifset(now_ms, si->ob->wto);
- buffer_auto_close(si->ob);
}
/* default update function for scheduled tasks, not used for embedded tasks */