mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2024-12-15 16:04:37 +00:00
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().
This commit is contained in:
parent
04065b87ce
commit
0da616ee18
@ -7,16 +7,19 @@ struct httpclient {
|
||||
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 @@ struct httpclient {
|
||||
/* 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,
|
||||
|
@ -10,7 +10,7 @@ struct httpclient *httpclient_new(void *caller, enum http_meth_t meth, struct is
|
||||
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)
|
||||
|
@ -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 @@ int httpclient_req_gen(struct httpclient *hc, const struct ist url, enum http_me
|
||||
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);
|
||||
|
||||
@ -330,6 +334,44 @@ int httpclient_res_xfer(struct httpclient *hc, struct buffer *dst)
|
||||
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
|
||||
@ -532,9 +574,34 @@ static void httpclient_applet_io_handler(struct appctx *appctx)
|
||||
* 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 */
|
||||
|
Loading…
Reference in New Issue
Block a user