Skip to content

Commit

Permalink
http, httpauth, websock: support large req body and add body handler
Browse files Browse the repository at this point in the history
Support large req body.
Allow set body handler.
Use type mbuf for body parameter.
  • Loading branch information
fAuernigg committed Aug 25, 2022
1 parent bf5fe9e commit 678f2e7
Show file tree
Hide file tree
Showing 6 changed files with 279 additions and 49 deletions.
8 changes: 6 additions & 2 deletions include/re_http.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,12 +144,13 @@ typedef int (http_data_h)(const uint8_t *buf, size_t size,
const struct http_msg *msg, void *arg);
typedef void (http_conn_h)(struct tcp_conn *tc, struct tls_conn *sc,
void *arg);
typedef size_t (http_req_bodyh)(uint8_t **pbuf, void *arg);

int http_client_alloc(struct http_cli **clip, struct dnsc *dnsc);
int http_client_set_config(struct http_cli *cli, struct http_conf *conf);
int http_request(struct http_req **reqp, struct http_cli *cli, const char *met,
const char *uri, http_resp_h *resph, http_data_h *datah,
void *arg, const char *fmt, ...);
http_req_bodyh *req_bodyh, void *arg, const char *fmt, ...);
void http_req_set_conn_handler(struct http_req *req, http_conn_h *connh);
void http_client_set_laddr(struct http_cli *cli, const struct sa *addr);
void http_client_set_laddr6(struct http_cli *cli, const struct sa *addr);
Expand Down Expand Up @@ -228,7 +229,7 @@ int http_reqconn_set_authtoken(struct http_reqconn *conn,
int http_reqconn_set_tokentype(struct http_reqconn *conn,
const struct pl *tokentype);
int http_reqconn_set_method(struct http_reqconn *conn, const struct pl *met);
int http_reqconn_set_body(struct http_reqconn *conn, const struct pl *body);
int http_reqconn_set_body(struct http_reqconn *conn, struct mbuf *body);
int http_reqconn_set_ctype(struct http_reqconn *conn, const struct pl *ctype);
int http_reqconn_add_header(struct http_reqconn *conn,
const struct pl *header);
Expand All @@ -238,3 +239,6 @@ int http_reqconn_send(struct http_reqconn *conn, const struct pl *uri);
int http_reqconn_set_tls_hostname(struct http_reqconn *conn,
const struct pl *hostname);
#endif

int http_reqconn_set_req_bodyh(struct http_reqconn *conn,
http_req_bodyh cb, uint64_t total_size);
2 changes: 1 addition & 1 deletion include/re_httpauth.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ int httpauth_digest_response_auth(const struct httpauth_digest_resp *resp,
int httpauth_digest_make_response(struct httpauth_digest_resp **resp,
const struct httpauth_digest_chall *chall,
const char *path, const char *method, const char *user,
const char *pwd, const char *body);
const char *pwd, struct mbuf *body);
int httpauth_digest_response_encode(const struct httpauth_digest_resp *resp,
struct mbuf *mb);

Expand Down
209 changes: 186 additions & 23 deletions src/http/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ struct http_req {
bool chunked;
bool secure;
bool close;
http_req_bodyh *req_bodyh;
};


Expand Down Expand Up @@ -326,27 +327,168 @@ static void timeout_handler(void *arg)
}


static int read_req_data(struct http_req *req)
{
int err = 0;
uint8_t *buf = NULL;
size_t rlen = 0;

if (!req->req_bodyh)
return 0;

if (!req->mbreq) {
req->mbreq = mbuf_alloc(http_client_get_bufsize_max(req->cli));
if (!req->mbreq) {
DEBUG_WARNING("%s:%d out of memory during "
"allocating body: %d", __func__,
__LINE__, err,
http_client_get_bufsize_max(req->cli));
goto out;
}
}

rlen = req->req_bodyh(&buf, req->arg);
if (!rlen) {
goto out;
}

if (!buf) {
DEBUG_WARNING("%s:%d error req_bodyh returned NULL buf\n",
__func__, __LINE__);
goto out;
}

err = mbuf_write_mem(req->mbreq, buf, rlen);
if (err) {
DEBUG_WARNING("%s:%d mbuf write mem failed. (%m), len: %d",
__func__, __LINE__, err, rlen);
goto out;
}

out:
mem_deref(buf);
return err;
}


static int send_buf(struct tcp_conn *tc, struct mbuf *large, size_t max_size)
{
struct mbuf *mb = NULL;
size_t len;
int err = 0;

if (!tc || !large)
return EINVAL;

if (!mbuf_get_left(large)) {
DEBUG_WARNING("%s:%d mbuf_get_left is null\n",
__func__, __LINE__);
return 0;
}

mb = mbuf_alloc_ref(large);
if (!mb) {
err = ENOMEM;
DEBUG_WARNING("%s:%d mbuf_alloc_ref failed (%m)\n",
__func__, __LINE__, err);
goto out;
}

len = min(mbuf_get_left(large), max_size);
mb->end = large->pos + len;

err = tcp_send(tc, mb);
if (err) {
DEBUG_WARNING("%s:%d tcp_send failed (%m)\n",
__func__, __LINE__, err);
goto out;
}

mbuf_advance(large, len);

out:
mem_deref(mb);

return err;
}


static int send_req_buf(struct conn *conn)
{
int err;
struct http_req *req = conn->req;

if (!conn || !req || !req->cli) {
return EINVAL;
}

if (!mbuf_get_left(req->mbreq)) {
return 0;
}

err = send_buf(conn->tc, req->mbreq, req->cli->bufsize_max);
if (err) {
DEBUG_WARNING("%s:%d tcp_send failed: (%m)\n",
__func__, __LINE__, err);
goto out;
}

if (!mbuf_get_left(req->mbreq))
req->mbreq = mem_deref(req->mbreq);

if (!mbuf_get_left(req->mbreq)) {
err = read_req_data(req);
if (err) {
DEBUG_WARNING("%s:%d read_req_data failed: (%m)",
__func__, __LINE__, err);
goto out;
}

if (req->mbreq)
mbuf_set_pos(req->mbreq, 0);

if (mbuf_get_left(req->mbreq) && !tcp_send_queued(conn->tc))
(void) send_req_buf(conn);
}

tmr_start(&conn->tmr, req->cli->conf.recv_timeout, timeout_handler,
conn);

return err;

out:
DEBUG_WARNING("%s:%d error: (%m)", __func__, __LINE__, err);
return err;
}


static void send_req_handler(void *arg)
{
(void) send_req_buf((struct conn *)arg);
}


static void estab_handler(void *arg)
{
struct conn *conn = arg;
struct http_req *req = conn->req;
struct http_cli *cli;
int err;

if (!req)
if (!req || !req->cli)
return;

err = tcp_send(conn->tc, req->mbreq);
err = send_req_buf(conn);
if (err) {
try_next(conn, err);
return;
}

cli = req->cli;
if (!cli)
return;
if (mbuf_get_left(req->mbreq)) {
tcp_set_send(conn->tc, send_req_handler);
tcp_conn_txqsz_set(conn->tc, req->cli->bufsize_max);
}

tmr_start(&conn->tmr, cli->conf.recv_timeout, timeout_handler, conn);
tmr_start(&conn->tmr, req->cli->conf.recv_timeout,
timeout_handler, conn);
}


Expand Down Expand Up @@ -455,26 +597,30 @@ static int conn_connect(struct http_req *req)
const struct sa *addr = &req->srvv[req->srvc];
struct conn *conn;
struct sa *laddr = NULL;
struct http_cli *cli;
int err;
int err = 0;

conn = list_ledata(hash_lookup(req->cli->ht_conn,
sa_hash(addr, SA_ALL), conn_cmp, req));
if (conn) {
err = tcp_send(conn->tc, req->mbreq);
if (!err) {
cli = req->cli;
if (!cli)
return EINVAL;
if (!req->cli)
return EINVAL;

tmr_start(&conn->tmr, cli->conf.recv_timeout,
err = send_req_buf(conn);
if (!err) {
tmr_start(&conn->tmr, req->cli->conf.recv_timeout,
timeout_handler, conn);

req->conn = conn;
conn->req = req;

++conn->usec;

if (mbuf_get_left(req->mbreq)) {
tcp_set_send(conn->tc, send_req_handler);
tcp_conn_txqsz_set(conn->tc,
req->cli->bufsize_max);
}

return 0;
}

Expand Down Expand Up @@ -527,10 +673,12 @@ static int conn_connect(struct http_req *req)
tmr_start(&conn->tmr, req->cli->conf.conn_timeout, timeout_handler,
conn);

req->conn = conn;
conn->req = req;
if (!err) {
req->conn = conn;
conn->req = req;
}

out:
out:
if (err)
mem_deref(conn);

Expand Down Expand Up @@ -701,7 +849,7 @@ int http_uri_decode(struct http_uri *hu, const struct pl *uri)
*/
int http_request(struct http_req **reqp, struct http_cli *cli, const char *met,
const char *uri, http_resp_h *resph, http_data_h *datah,
void *arg, const char *fmt, ...)
http_req_bodyh *req_bodyh, void *arg, const char *fmt, ...)
{
struct http_uri http_uri;
struct pl pl;
Expand Down Expand Up @@ -747,6 +895,7 @@ int http_request(struct http_req **reqp, struct http_cli *cli, const char *met,
defport;
req->resph = resph;
req->datah = datah;
req->req_bodyh = req_bodyh;
req->arg = arg;

err = pl_strdup(&req->host, &http_uri.host);
Expand All @@ -765,18 +914,32 @@ int http_request(struct http_req **reqp, struct http_cli *cli, const char *met,
"Host: %s%r%s\r\n",
met, &http_uri.path,
ipv6 ? "[" : "", &http_uri.host, ipv6 ? "]" : "");

if (fmt) {
va_start(ap, fmt);
err |= mbuf_vprintf(req->mbreq, fmt, ap);
va_end(ap);
}
else {
else
err |= mbuf_write_str(req->mbreq, "\r\n");

if (err) {
DEBUG_WARNING("%s:%d format header failed: (%m)",
__func__, __LINE__, err);
goto out;
}
if (err)

err = read_req_data(req);
if (err) {
DEBUG_WARNING("%s:%d read_req_data failed: (%m)",
__func__, __LINE__, err);
goto out;
}

req->mbreq->pos = 0;
mbuf_set_pos(req->mbreq, 0);

if (err)
goto out;

#ifdef USE_TLS
if (cli->cert && cli->key) {
Expand Down
Loading

0 comments on commit 678f2e7

Please sign in to comment.