struct {
struct ist url; /* URL of the request */
enum http_meth_t meth; /* method of the request */
- struct buffer buf; /* output buffer */
+ struct buffer buf; /* output buffer, HTX */
} req;
struct {
struct ist vsn;
uint16_t status;
struct ist reason;
struct http_hdr *hdrs; /* headers */
- struct buffer buf; /* input buffer */
+ struct buffer buf; /* input buffer, raw HTTP */
} res;
struct {
+ /* callbacks used to send the request, */
+ void (*req_payload)(struct httpclient *hc); /* send a payload */
+
/* callbacks used to receive the response, if not set, the IO
* handler will consume the data without doing anything */
void (*res_stline)(struct httpclient *hc); /* start line received */
/* States of the HTTP Client Appctx */
enum {
HTTPCLIENT_S_REQ = 0,
+ HTTPCLIENT_S_REQ_BODY,
HTTPCLIENT_S_RES_STLINE,
HTTPCLIENT_S_RES_HDR,
HTTPCLIENT_S_RES_BODY,
#include <haproxy/cfgparse.h>
#include <haproxy/connection.h>
#include <haproxy/global.h>
+#include <haproxy/istbuf.h>
#include <haproxy/h1_htx.h>
#include <haproxy/http.h>
#include <haproxy/http_client.h>
goto error;
}
- htx->flags |= HTX_FL_EOM;
+ /* If req.payload was set, does not set the end of stream which *MUST*
+ * be set in the callback */
+ if (!hc->ops.req_payload)
+ htx->flags |= HTX_FL_EOM;
htx_to_buf(htx, &hc->req.buf);
return ret;
}
+/*
+ * Transfer raw HTTP payload from src, and insert it into HTX format in the
+ * httpclient.
+ *
+ * Must be used to transfer the request body.
+ * Then wakeup the httpclient so it can transfer it.
+ *
+ * <end> tries to add the ending data flag if it succeed to copy all data.
+ *
+ * Return the number of bytes copied from src.
+ */
+int httpclient_req_xfer(struct httpclient *hc, struct ist src, int end)
+{
+ int ret = 0;
+ struct htx *htx;
+
+ htx = htx_from_buf(&hc->req.buf);
+ if (!htx)
+ goto error;
+
+ if (hc->appctx)
+ appctx_wakeup(hc->appctx);
+
+ ret += htx_add_data(htx, src);
+
+
+ /* if we copied all the data and the end flag is set */
+ if ((istlen(src) == ret) && end) {
+ htx->flags |= HTX_FL_EOM;
+ }
+ htx_to_buf(htx, &hc->req.buf);
+
+error:
+
+ return ret;
+}
+
+
/*
* Start the HTTP client
* Create the appctx, session, stream and wakeup the applet
* just push this entirely */
b_xfer(&req->buf, &hc->req.buf, b_data(&hc->req.buf));
channel_add_input(req, b_data(&req->buf));
- appctx->st0 = HTTPCLIENT_S_RES_STLINE;
+ appctx->st0 = HTTPCLIENT_S_REQ_BODY;
goto more; /* we need to leave the IO handler once we wrote the request */
break;
+ case HTTPCLIENT_S_REQ_BODY:
+ /* call the payload callback */
+ {
+ if (hc->ops.req_payload) {
+ int ret;
+
+ ret = b_xfer(&req->buf, &hc->req.buf, b_data(&hc->req.buf));
+ if (ret)
+ channel_add_input(req, b_data(&req->buf));
+
+ /* call the request callback */
+ hc->ops.req_payload(hc);
+ }
+
+ htx = htxbuf(&req->buf);
+ if (!htx)
+ goto more;
+
+ /* if the request contains the HTX_FL_EOM, we finished the request part. */
+ if (htx->flags & HTX_FL_EOM)
+ appctx->st0 = HTTPCLIENT_S_RES_STLINE;
+
+ goto more; /* we need to leave the IO handler once we wrote the request */
+ }
+ break;
case HTTPCLIENT_S_RES_STLINE:
/* copy the start line in the hc structure,then remove the htx block */