X-Git-Url: http://git.openwrt.org/?a=blobdiff_plain;f=uclient-http.c;h=c2bba6b5b8f2093e3b408d6d35a312673f821583;hb=e209a4ced1d80e8a4ac4290a6ade9d339eab1705;hp=36e2b388cfe707b71fb09b5e23f1c1703326a6d1;hpb=f41ff608831b843719835f3657182a8c00aabbae;p=project%2Fuclient.git diff --git a/uclient-http.c b/uclient-http.c index 36e2b38..c2bba6b 100644 --- a/uclient-http.c +++ b/uclient-http.c @@ -149,7 +149,8 @@ static void uclient_http_disconnect(struct uclient_http *uh) if (uh->ssl) ustream_free(&uh->ussl.stream); ustream_free(&uh->ufd.stream); - close(uh->ufd.fd.fd); + if(uh->ufd.fd.fd) + close(uh->ufd.fd.fd); uh->us = NULL; } @@ -198,7 +199,8 @@ static void uclient_notify_eof(struct uclient_http *uh) return; } - if (uh->content_length < 0 && uh->read_chunked >= 0) + if ((uh->content_length < 0 && uh->read_chunked >= 0) || + uh->content_length == 0) uh->uc.data_eof = true; uclient_backend_set_eof(&uh->uc); @@ -433,7 +435,7 @@ static void add_field(char **buf, int *ofs, int *len, const char *name, const ch *ofs = cur - *buf; } -static void +static int uclient_http_add_auth_digest(struct uclient_http *uh) { struct uclient_url *url = uh->uc.url; @@ -441,6 +443,7 @@ uclient_http_add_auth_digest(struct uclient_http *uh) const char *user, *password; char *buf, *next; int len, ofs; + int err = 0; char cnonce_str[9]; char nc_str[9]; @@ -454,10 +457,17 @@ uclient_http_add_auth_digest(struct uclient_http *uh) }; len = strlen(uh->auth_str) + 1; - if (len > 512) - return; + if (len > 512) { + err = -EINVAL; + goto fail; + } buf = alloca(len); + if (!buf) { + err = -ENOMEM; + goto fail; + } + strcpy(buf, uh->auth_str); /* skip auth type */ @@ -495,8 +505,10 @@ uclient_http_add_auth_digest(struct uclient_http *uh) *dest = digest_unquote_sep(&next); } - if (!realm || !data.qop || !data.nonce) - return; + if (!realm || !data.qop || !data.nonce) { + err = -EINVAL; + goto fail; + } sprintf(nc_str, "%08x", uh->nc++); get_cnonce(cnonce_str); @@ -510,10 +522,17 @@ uclient_http_add_auth_digest(struct uclient_http *uh) char *user_buf; len = password - url->auth; - if (len > 256) - return; + if (len > 256) { + err = -EINVAL; + goto fail; + } user_buf = alloca(len + 1); + if (!user_buf) { + err = -ENOMEM; + goto fail; + } + strncpy(user_buf, url->auth, len); user_buf[len] = 0; user = user_buf; @@ -540,39 +559,46 @@ uclient_http_add_auth_digest(struct uclient_http *uh) add_field(&buf, &ofs, &len, "opaque", opaque); ustream_printf(uh->us, "Authorization: Digest nc=%s, qop=%s%s\r\n", data.nc, data.qop, buf); + free(buf); + + return 0; + +fail: + return err; } -static void +static int uclient_http_add_auth_header(struct uclient_http *uh) { if (!uh->uc.url->auth) - return; + return 0; switch (uh->auth_type) { case AUTH_TYPE_UNKNOWN: case AUTH_TYPE_NONE: break; case AUTH_TYPE_BASIC: - uclient_http_add_auth_basic(uh); - break; + return uclient_http_add_auth_basic(uh); case AUTH_TYPE_DIGEST: - uclient_http_add_auth_digest(uh); - break; + return uclient_http_add_auth_digest(uh); } + + return 0; } -static void +static int uclient_http_send_headers(struct uclient_http *uh) { struct uclient_url *url = uh->uc.url; struct blob_attr *cur; enum request_type req_type = uh->req_type; bool literal_ipv6; - int rem; + int err; + size_t rem; if (uh->state >= HTTP_STATE_HEADERS_SENT) - return; + return 0; if (uh->uc.proxy_url) url = uh->uc.proxy_url; @@ -595,11 +621,15 @@ uclient_http_send_headers(struct uclient_http *uh) if (uclient_request_supports_body(uh->req_type)) ustream_printf(uh->us, "Transfer-Encoding: chunked\r\n"); - uclient_http_add_auth_header(uh); + err = uclient_http_add_auth_header(uh); + if (err) + return err; ustream_printf(uh->us, "\r\n"); uh->state = HTTP_STATE_HEADERS_SENT; + + return 0; } static void uclient_http_headers_complete(struct uclient_http *uh) @@ -625,7 +655,8 @@ static void uclient_http_headers_complete(struct uclient_http *uh) if (uh->eof || seq != uh->uc.seq) return; - if (uh->req_type == REQ_HEAD || uh->uc.status_code == 204) { + if (uh->req_type == REQ_HEAD || uh->uc.status_code == 204 || + uh->content_length == 0) { uh->eof = true; uclient_notify_eof(uh); } @@ -921,6 +952,9 @@ static struct uclient *uclient_http_alloc(void) struct uclient_http *uh; uh = calloc_a(sizeof(*uh)); + if (!uh) + return NULL; + uh->disconnect_t.cb = uclient_http_disconnect_cb; blob_buf_init(&uh->headers, 0); @@ -948,7 +982,7 @@ int uclient_http_set_request_type(struct uclient *cl, const char *type) { struct uclient_http *uh = container_of(cl, struct uclient_http, uc); - int i; + unsigned int i; if (cl->backend != &uclient_backend_http) return -1; @@ -996,11 +1030,14 @@ static int uclient_http_send_data(struct uclient *cl, const char *buf, unsigned int len) { struct uclient_http *uh = container_of(cl, struct uclient_http, uc); + int err; if (uh->state >= HTTP_STATE_REQUEST_DONE) return -1; - uclient_http_send_headers(uh); + err = uclient_http_send_headers(uh); + if (err) + return err; if (len > 0) { ustream_printf(uh->us, "%X\r\n", len); @@ -1015,11 +1052,15 @@ static int uclient_http_request_done(struct uclient *cl) { struct uclient_http *uh = container_of(cl, struct uclient_http, uc); + int err; if (uh->state >= HTTP_STATE_REQUEST_DONE) return -1; - uclient_http_send_headers(uh); + err = uclient_http_send_headers(uh); + if (err) + return err; + if (uclient_request_supports_body(uh->req_type)) ustream_printf(uh->us, "0\r\n\r\n"); uh->state = HTTP_STATE_REQUEST_DONE; @@ -1068,16 +1109,17 @@ uclient_http_read(struct uclient *cl, char *buf, unsigned int len) } } - if (len > data_end - data) - len = data_end - data; + unsigned int diff = data_end - data; + if (len > diff) + len = diff; if (uh->read_chunked >= 0) { - if (len > uh->read_chunked) + if (len > (unsigned long) uh->read_chunked) len = uh->read_chunked; uh->read_chunked -= len; } else if (uh->content_length >= 0) { - if (len > uh->content_length) + if (len > (unsigned long) uh->content_length) len = uh->content_length; uh->content_length -= len; @@ -1134,8 +1176,15 @@ int uclient_http_redirect(struct uclient *cl) if (!url) return false; - free(cl->url); - cl->url = url; + if (cl->proxy_url) { + free(cl->proxy_url); + cl->proxy_url = url; + } + else { + free(cl->url); + cl->url = url; + } + if (uclient_http_connect(cl)) return -1;