mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-11 17:46:57 +02: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 {
|
||||||
struct ist url; /* URL of the request */
|
struct ist url; /* URL of the request */
|
||||||
enum http_meth_t meth; /* method of the request */
|
enum http_meth_t meth; /* method of the request */
|
||||||
struct buffer buf; /* output buffer */
|
struct buffer buf; /* output buffer, HTX */
|
||||||
} req;
|
} req;
|
||||||
struct {
|
struct {
|
||||||
struct ist vsn;
|
struct ist vsn;
|
||||||
uint16_t status;
|
uint16_t status;
|
||||||
struct ist reason;
|
struct ist reason;
|
||||||
struct http_hdr *hdrs; /* headers */
|
struct http_hdr *hdrs; /* headers */
|
||||||
struct buffer buf; /* input buffer */
|
struct buffer buf; /* input buffer, raw HTTP */
|
||||||
} res;
|
} res;
|
||||||
struct {
|
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
|
/* callbacks used to receive the response, if not set, the IO
|
||||||
* handler will consume the data without doing anything */
|
* handler will consume the data without doing anything */
|
||||||
void (*res_stline)(struct httpclient *hc); /* start line received */
|
void (*res_stline)(struct httpclient *hc); /* start line received */
|
||||||
@ -41,6 +44,7 @@ struct httpclient {
|
|||||||
/* States of the HTTP Client Appctx */
|
/* States of the HTTP Client Appctx */
|
||||||
enum {
|
enum {
|
||||||
HTTPCLIENT_S_REQ = 0,
|
HTTPCLIENT_S_REQ = 0,
|
||||||
|
HTTPCLIENT_S_REQ_BODY,
|
||||||
HTTPCLIENT_S_RES_STLINE,
|
HTTPCLIENT_S_RES_STLINE,
|
||||||
HTTPCLIENT_S_RES_HDR,
|
HTTPCLIENT_S_RES_HDR,
|
||||||
HTTPCLIENT_S_RES_BODY,
|
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);
|
struct appctx *httpclient_start(struct httpclient *hc);
|
||||||
int httpclient_res_xfer(struct httpclient *hc, struct buffer *dst);
|
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_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 */
|
/* Return the amount of data available in the httpclient response buffer */
|
||||||
static inline int httpclient_data(struct httpclient *hc)
|
static inline int httpclient_data(struct httpclient *hc)
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include <haproxy/cfgparse.h>
|
#include <haproxy/cfgparse.h>
|
||||||
#include <haproxy/connection.h>
|
#include <haproxy/connection.h>
|
||||||
#include <haproxy/global.h>
|
#include <haproxy/global.h>
|
||||||
|
#include <haproxy/istbuf.h>
|
||||||
#include <haproxy/h1_htx.h>
|
#include <haproxy/h1_htx.h>
|
||||||
#include <haproxy/http.h>
|
#include <haproxy/http.h>
|
||||||
#include <haproxy/http_client.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;
|
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);
|
htx_to_buf(htx, &hc->req.buf);
|
||||||
|
|
||||||
@ -330,6 +334,44 @@ int httpclient_res_xfer(struct httpclient *hc, struct buffer *dst)
|
|||||||
return ret;
|
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
|
* Start the HTTP client
|
||||||
* Create the appctx, session, stream and wakeup the applet
|
* 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 */
|
* just push this entirely */
|
||||||
b_xfer(&req->buf, &hc->req.buf, b_data(&hc->req.buf));
|
b_xfer(&req->buf, &hc->req.buf, b_data(&hc->req.buf));
|
||||||
channel_add_input(req, b_data(&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 */
|
goto more; /* we need to leave the IO handler once we wrote the request */
|
||||||
break;
|
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:
|
case HTTPCLIENT_S_RES_STLINE:
|
||||||
/* copy the start line in the hc structure,then remove the htx block */
|
/* copy the start line in the hc structure,then remove the htx block */
|
||||||
|
Loading…
Reference in New Issue
Block a user