+ if (!uh->eof) {
+ if (!us->eof && !us->write_error)
+ return;
+
+ if (ustream_pending_data(us, false))
+ return;
+ }
+
+ uclient_backend_set_eof(&uh->uc);
+
+ if (uh->connection_close)
+ uclient_http_disconnect(uh);
+}
+
+static void uclient_http_reset_state(struct uclient_http *uh)
+{
+ uclient_backend_reset_state(&uh->uc);
+ uh->read_chunked = -1;
+ uh->content_length = -1;
+ uh->eof = false;
+ uh->connection_close = false;
+ uh->state = HTTP_STATE_INIT;
+
+ if (uh->auth_type == AUTH_TYPE_UNKNOWN && !uh->uc.url->auth)
+ uh->auth_type = AUTH_TYPE_NONE;
+}
+
+static void uclient_http_init_request(struct uclient_http *uh)
+{
+ uclient_http_reset_state(uh);
+ blob_buf_init(&uh->meta, 0);
+}
+
+static enum auth_type
+uclient_http_update_auth_type(struct uclient_http *uh)
+{
+ if (!uh->auth_str)
+ return AUTH_TYPE_NONE;
+
+ if (!strncasecmp(uh->auth_str, "basic", 5))
+ return AUTH_TYPE_BASIC;
+
+ return AUTH_TYPE_NONE;
+}
+
+static void uclient_http_process_headers(struct uclient_http *uh)
+{
+ enum {
+ HTTP_HDR_TRANSFER_ENCODING,
+ HTTP_HDR_CONNECTION,
+ HTTP_HDR_CONTENT_LENGTH,
+ HTTP_HDR_AUTH,
+ __HTTP_HDR_MAX,
+ };
+ static const struct blobmsg_policy hdr_policy[__HTTP_HDR_MAX] = {
+#define hdr(_name) { .name = _name, .type = BLOBMSG_TYPE_STRING }
+ [HTTP_HDR_TRANSFER_ENCODING] = hdr("transfer-encoding"),
+ [HTTP_HDR_CONNECTION] = hdr("connection"),
+ [HTTP_HDR_CONTENT_LENGTH] = hdr("content-length"),
+ [HTTP_HDR_AUTH] = hdr("www-authenticate"),
+#undef hdr
+ };
+ struct blob_attr *tb[__HTTP_HDR_MAX];
+ struct blob_attr *cur;
+
+ blobmsg_parse(hdr_policy, __HTTP_HDR_MAX, tb, blob_data(uh->meta.head), blob_len(uh->meta.head));
+
+ cur = tb[HTTP_HDR_TRANSFER_ENCODING];
+ if (cur && strstr(blobmsg_data(cur), "chunked"))
+ uh->read_chunked = 0;
+
+ cur = tb[HTTP_HDR_CONNECTION];
+ if (cur && strstr(blobmsg_data(cur), "close"))
+ uh->connection_close = true;
+
+ cur = tb[HTTP_HDR_CONTENT_LENGTH];
+ if (cur)
+ uh->content_length = strtoul(blobmsg_data(cur), NULL, 10);
+
+ cur = tb[HTTP_HDR_AUTH];
+ if (cur) {
+ free(uh->auth_str);
+ uh->auth_str = strdup(blobmsg_data(cur));
+ }
+
+ uh->auth_type = uclient_http_update_auth_type(uh);
+}
+
+static void
+uclient_http_add_auth_header(struct uclient_http *uh)
+{
+ struct uclient_url *url = uh->uc.url;
+ char *auth_buf;
+ int auth_len;
+
+ if (!url->auth)