MINOR: httpclient: request streaming with a callback
This patch add a way to handle HTTP requests streaming using a
callback.
The end of the data must be specified by using the "end" parameter in
httpclient_req_xfer().
diff --git a/include/haproxy/http_client-t.h b/include/haproxy/http_client-t.h
index fa0f8fb..6e820c4 100644
--- a/include/haproxy/http_client-t.h
+++ b/include/haproxy/http_client-t.h
@@ -7,16 +7,19 @@
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 */
@@ -41,6 +44,7 @@
/* 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,
diff --git a/include/haproxy/http_client.h b/include/haproxy/http_client.h
index 13673e8..1d99aa7 100644
--- a/include/haproxy/http_client.h
+++ b/include/haproxy/http_client.h
@@ -10,7 +10,7 @@
struct appctx *httpclient_start(struct httpclient *hc);
int httpclient_res_xfer(struct httpclient *hc, struct buffer *dst);
int httpclient_req_gen(struct httpclient *hc, const struct ist url, enum http_meth_t meth, const struct http_hdr *hdrs, const struct ist payload);
-
+int httpclient_req_xfer(struct httpclient *hc, struct ist src, int end);
/* Return the amount of data available in the httpclient response buffer */
static inline int httpclient_data(struct httpclient *hc)
diff --git a/src/http_client.c b/src/http_client.c
index 7756e82..a07cf9e 100644
--- a/src/http_client.c
+++ b/src/http_client.c
@@ -19,6 +19,7 @@
#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>
@@ -303,7 +304,10 @@
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);
@@ -331,6 +335,44 @@
}
/*
+ * 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
*
@@ -532,9 +574,34 @@
* 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 */