cl->state = CLIENT_STATE_HEADER;
}
-static bool client_data_cb(struct client *cl, char *buf, int len)
+void client_poll_post_data(struct client *cl)
{
struct dispatch *d = &cl->dispatch;
struct http_request *r = &cl->request;
- int consumed = 0;
- int cur_len = 0;
+ char *buf;
+ int len;
- if (!d->data_send)
- return false;
+ if (cl->state == CLIENT_STATE_DONE)
+ return;
- while (len) {
- int offset = 0;
+ while (1) {
char *sep;
+ int offset = 0;
+ int cur_len;
- consumed += cur_len;
- buf += cur_len;
- len -= cur_len;
- cur_len = min(r->content_length, len);
+ buf = ustream_get_read_buf(cl->us, &len);
+ if (!buf || !len)
+ break;
+
+ if (!d->data_send)
+ return;
+ cur_len = min(r->content_length, len);
if (cur_len) {
- r->content_length -= cur_len;
+ if (d->data_blocked)
+ break;
+
if (d->data_send)
d->data_send(cl, buf, cur_len);
+ r->content_length -= cur_len;
+ ustream_consume(cl->us, cur_len);
continue;
}
break;
*sep = 0;
- cur_len = sep + 2 - buf;
r->content_length = strtoul(buf + offset, &sep, 16);
r->transfer_chunked++;
+ ustream_consume(cl->us, sep + 2 - buf);
/* invalid chunk length */
- if (sep && *sep)
- goto abort;
+ if (sep && *sep) {
+ r->content_length = 0;
+ r->transfer_chunked = 0;
+ break;
+ }
/* empty chunk == eof */
- if (!r->content_length)
+ if (!r->content_length) {
r->transfer_chunked = false;
-
- continue;
-
-abort:
- consumed = len;
- r->content_length = 0;
- r->transfer_chunked = 0;
- break;
+ break;
+ }
}
- ustream_consume(cl->us, consumed);
- if (!r->content_length && !r->transfer_chunked) {
+ buf = ustream_get_read_buf(cl->us, &len);
+ if (!r->content_length && !r->transfer_chunked &&
+ cl->state != CLIENT_STATE_DONE) {
if (cl->dispatch.data_done)
cl->dispatch.data_done(cl);
cl->state = CLIENT_STATE_DONE;
}
+}
+
+static bool client_data_cb(struct client *cl, char *buf, int len)
+{
+ client_poll_post_data(cl);
return false;
}
{
struct client *cl = container_of(us, struct client, dispatch.proc.r.sfd.stream);
+ if (ustream_pending_data(us, true))
+ return;
+
+ cl->dispatch.data_blocked = false;
+ us->notify_write = NULL;
+ client_poll_post_data(cl);
+}
+
+static void proc_relay_write_close_cb(struct ustream *us, int bytes)
+{
+ struct client *cl = container_of(us, struct client, dispatch.proc.r.sfd.stream);
+
if (ustream_pending_data(us, true))
return;
struct ustream *us = &cl->dispatch.proc.r.sfd.stream;
ustream_write(us, data, len, false);
+ if (ustream_pending_data(us, true)) {
+ cl->dispatch.data_blocked = true;
+ us->notify_write = proc_relay_write_cb;
+ }
}
static void proc_data_done(struct client *cl)
struct ustream *us = &cl->dispatch.proc.r.sfd.stream;
if (ustream_pending_data(us, true)) {
- us->notify_write = proc_relay_write_cb;
+ us->notify_write = proc_relay_write_close_cb;
return;
}
void (*write_cb)(struct client *cl);
void (*close_fds)(struct client *cl);
void (*free)(struct client *cl);
+ bool data_blocked;
+
union {
struct {
struct blob_attr **hdr;
uh_client_error(struct client *cl, int code, const char *summary, const char *fmt, ...);
void uh_handle_request(struct client *cl);
+void client_poll_post_data(struct client *cl);
void uh_auth_add(const char *path, const char *user, const char *pass);
bool uh_auth_check(struct client *cl, struct path_info *pi);