diff --git a/vfile/vfff/http.c b/vfile/vfff/http.c index 02c4f81..deac884 100644 --- a/vfile/vfff/http.c +++ b/vfile/vfff/http.c @@ -918,7 +918,7 @@ int vhttp_vcn_stat(struct vcn *cn, struct vfff_req *rreq) static int vhttp_vcn_retr(struct vcn *cn, struct vfff_req *rreq) { - int close_cn = 0, rc = 1; + int close_cn = 0, rc = 1, chunked = 0; long from = 0, to = 0, total = 0, amount = 0; char req_line[PATH_MAX]; const char *trenc; @@ -970,15 +970,18 @@ int vhttp_vcn_retr(struct vcn *cn, struct vfff_req *rreq) goto l_err_end; if ((trenc = http_resp_get_hdr(resp, "transfer-encoding"))) { - if (*vfff_verbose > 1) + chunked = strcasecmp(trenc, "chunked") == 0; + + if (*vfff_verbose > 1 && !chunked) { vfff_log("Trasfer-Encoding is an unimplemented tag, give up\n"); - vfff_set_err(ENOENT, "%s: unimplemented HTTP " + vfff_set_err(ENOENT, "%s: unimplemented HTTP " "transfer encoding", trenc); - close_cn = 1; - goto l_err_end; + close_cn = 1; + goto l_err_end; + } } - if ((amount = http_resp_get_content_length(resp)) < 0) + if ( !chunked && (amount = http_resp_get_content_length(resp)) < 0 ) goto l_err_end; if ((trenc = http_resp_get_hdr(resp, "last-modified")) != NULL) @@ -1023,12 +1026,15 @@ int vhttp_vcn_retr(struct vcn *cn, struct vfff_req *rreq) rreq->st_remote_size = total; - if (*vfff_verbose > 1) { + if (*vfff_verbose > 1 && !chunked) { long a = from ? total - from : total; vfff_log("Total file size %ld, %ld to download, mtime %s\n", total, a, ctime(&rreq->st_remote_mtime)); } + if (chunked) + total = -1; + errno = 0; if (!vfff_transfer_file(rreq, cn->sockfd, total)) goto l_err_end; diff --git a/vfile/vfff/vfff.c b/vfile/vfff/vfff.c index 455fafd..25d1102 100644 --- a/vfile/vfff/vfff.c +++ b/vfile/vfff/vfff.c @@ -346,12 +356,12 @@ int vcn_stat(struct vcn *cn, struct vfff_req *req) int vfff_transfer_file(struct vfff_req *vreq, int in_fd, long total_size) { struct timeval tv; - int rc, is_err = 0; + int rc, is_err = 0, chunked = 0, last_chunk = 0; long amount = 0; - + if (chunked = total_size == -1) total_size = 0; amount = vreq->out_fdoff; - + vfff_log("amount, total = %ld, %ld\n", amount, total_size); if (vreq->progress_fn) { vreq->progress_fn(vreq->progress_fn_data, total_size, 0); if (amount) @@ -360,6 +370,7 @@ int vfff_transfer_file(struct vfff_req *vreq, int in_fd, long total_size) while (1) { fd_set fdset; + long size = -1; if (total_size > 0 && amount == total_size) break; @@ -391,15 +402,48 @@ int vfff_transfer_file(struct vfff_req *vreq, int in_fd, long total_size) } else if (rc > 0) { char buf[8192]; - int n; + char *chunkbeg = buf; + char *chunkend = buf; + int n,nw,m; - if ((n = read(in_fd, buf, sizeof(buf))) == 0) + if ((m = n = read(in_fd, buf, sizeof(buf))) == 0) break; - - if (n > 0) { - int nw; - - if ((nw = write(vreq->out_fd, buf, n)) != n) { + + if (chunked && n > 0) { + while (size != 0 && n != 0) { + if ((size = strtol(chunkend, &chunkbeg,16)) == 0) + goto transfer_end; + + total_size += size; + chunkbeg += 2; // CR+LF + n -= chunkbeg - chunkend; + + if (*vfff_verbose > 1) + vfff_log("\nchunk size = %ld, number of bytes rcv= %d\n", size, n); + + if (n >= size) { + if ((nw = write(vreq->out_fd, chunkbeg, size)) != size) { + is_err = 1; + break; + } + } else + if (n < size) { + if ((nw = write(vreq->out_fd, chunkbeg, n)) != n) { + is_err = 1; + break; + } + size -= n; + } + + chunkend += size; + amount += nw; + + if (vreq->progress_fn) + vreq->progress_fn(vreq->progress_fn_data, total_size, amount); + } + } else + if (!chunked && n > 0) { + if ((nw = write(vreq->out_fd, chunkbeg, n)) != n) { is_err = 1; break; } @@ -413,7 +457,9 @@ int vfff_transfer_file(struct vfff_req *vreq, int in_fd, long total_size) } } } - + +transfer_end: + if (is_err) { vfff_errno = errno; if (vfff_errno == 0)