REQ_GET,
REQ_HEAD,
REQ_POST,
+ REQ_PUT,
__REQ_MAX
};
[REQ_GET] = "GET",
[REQ_HEAD] = "HEAD",
[REQ_POST] = "POST",
+ [REQ_PUT] = "PUT",
};
struct uclient_http {
struct ustream_fd ufd;
struct ustream_ssl ussl;
+ struct uloop_timeout disconnect_t;
+
bool ssl_require_validation;
bool ssl;
bool eof;
bool connection_close;
+ bool disconnect;
enum request_type req_type;
enum http_state state;
static void uclient_http_disconnect(struct uclient_http *uh)
{
+ uloop_timeout_cancel(&uh->disconnect_t);
if (!uh->us)
return;
{
struct ustream *us = uh->us;
+ if (uh->disconnect)
+ return;
+
if (!uh->eof) {
if (!us->eof && !us->write_error)
return;
uh->read_chunked = -1;
uh->content_length = -1;
uh->eof = false;
+ uh->disconnect = false;
uh->connection_close = false;
uh->state = HTTP_STATE_INIT;
blobmsg_for_each_attr(cur, uh->headers.head, rem)
ustream_printf(uh->us, "%s: %s\n", blobmsg_name(cur), (char *) blobmsg_data(cur));
- if (uh->req_type == REQ_POST)
+ if (uh->req_type == REQ_POST || uh->req_type == REQ_PUT)
ustream_printf(uh->us, "Transfer-Encoding: chunked\r\n");
uclient_http_add_auth_header(uh);
if (uh->uc.cb->header_done)
uh->uc.cb->header_done(&uh->uc);
+ if (uh->eof)
+ return;
+
if (uh->req_type == REQ_HEAD || uh->uc.status_code == 204) {
uh->eof = true;
uclient_notify_eof(uh);
ustream_consume(uh->us, cur_len);
len -= cur_len;
+ if (uh->eof)
+ return;
+
data = ustream_get_read_buf(uh->us, &len);
} while (data && uh->state < HTTP_STATE_RECV_DATA);
return;
}
+ if (uh->eof)
+ return;
+
if (uh->state == HTTP_STATE_RECV_DATA && uc->cb->data_read)
uc->cb->data_read(uc);
}
return ret;
}
+static void uclient_http_disconnect_cb(struct uloop_timeout *timeout)
+{
+ struct uclient_http *uh = container_of(timeout, struct uclient_http, disconnect_t);
+
+ uclient_http_disconnect(uh);
+}
+
static struct uclient *uclient_http_alloc(void)
{
struct uclient_http *uh;
uh = calloc_a(sizeof(*uh));
+ uh->disconnect_t.cb = uclient_http_disconnect_cb;
blob_buf_init(&uh->headers, 0);
return &uh->uc;
return -1;
uclient_http_send_headers(uh);
- if (uh->req_type == REQ_POST)
+ if (uh->req_type == REQ_POST || uh->req_type == REQ_PUT)
ustream_printf(uh->us, "0\r\n\r\n");
uh->state = HTTP_STATE_REQUEST_DONE;
read_len += sep + 2 - data;
data = sep + 2;
- if (!uh->read_chunked)
+ if (!uh->read_chunked) {
uh->eof = true;
+ uh->uc.data_eof = true;
+ }
}
if (len > data_end - data)
len = uh->content_length;
uh->content_length -= len;
- if (!uh->content_length)
+ if (!uh->content_length) {
uh->eof = true;
+ uh->uc.data_eof = true;
+ }
}
if (len > 0) {
return 0;
}
+static void uclient_http_request_disconnect(struct uclient *cl)
+{
+ struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
+
+ if (!uh->us)
+ return;
+
+ uh->eof = true;
+ uh->disconnect = true;
+ uloop_timeout_set(&uh->disconnect_t, 1);
+}
+
const struct uclient_backend uclient_backend_http = {
.prefix = uclient_http_prefix,
.alloc = uclient_http_alloc,
.free = uclient_http_free,
.connect = uclient_http_connect,
+ .disconnect = uclient_http_request_disconnect,
.update_url = uclient_http_free_url_state,
.read = uclient_http_read,