fix partial-transfer problem

svn path=/trunk/boinc/; revision=9491
This commit is contained in:
David Anderson 2006-02-16 21:35:34 +00:00
parent 8e0d3dde71
commit 0cbe340ed8
6 changed files with 61 additions and 37 deletions

View File

@ -1955,3 +1955,17 @@ Rom 16 Feb 2006
clientlib/win/
BOINCSENSSink.cpp
NetworkTracker.cpp
David 16 Feb 2006
- core client: bug fix (hopefully) for situation where
a server or proxy doesn't understand Range: in HTTP header,
and sends us the entire file when we just want the tail.
Solution: if we asked for a partial transfer,
and we got a 200 HTTP return,
and the file is bigger than it's supposed to be,
trim off the part that was there initially.
- remove NET_XFER::strCurlResult, file_read_buf* fields
client/
file_xfer.C,h
net_xfer_curl.C,h

View File

@ -197,6 +197,8 @@ bool FILE_XFER_SET::poll() {
FILE_XFER* fxp;
bool action = false;
static double last_time=0;
char pathname[256];
double size;
if (gstate.now - last_time < 1.0) return false;
last_time = gstate.now;
@ -266,9 +268,6 @@ bool FILE_XFER_SET::poll() {
// since it may be a proxy error message
//
if (!fxp->is_upload && fxp->fip->nbytes) {
char pathname[256];
double size;
get_pathname(fxp->fip, pathname);
if (file_size(pathname, size)) continue;
if (size == fxp->fip->nbytes) continue;
@ -281,6 +280,35 @@ bool FILE_XFER_SET::poll() {
boinc_truncate(pathname, fxp->starting_size);
}
}
// for downloads: if we requested a partial transfer,
// and the HTTP response is 200,
// and the file is larger than it should be,
// the server or proxy must have sent us the entire file
// (i.e. it doesn't understand Range: requests).
// In this case, trim off the initial part of the file
//
if (!fxp->is_upload && fxp->starting_size
&& fxp->response==HTTP_STATUS_OK
) {
get_pathname(fxp->fip, pathname);
if (file_size(pathname, size)) continue;
if (size > fxp->fip->nbytes) {
FILE* f1 = boinc_fopen(pathname, "rb");
FILE* f2 = boinc_fopen(TEMP_FILE_NAME, "wb");
if (f1 && f2) {
fseek(f1, (long)fxp->starting_size, SEEK_SET);
copy_stream(f1, f2);
fclose(f1);
fclose(f2);
f1 = boinc_fopen(TEMP_FILE_NAME, "rb");
f2 = boinc_fopen(pathname, "wb");
copy_stream(f1, f2);
fclose(f1);
fclose(f2);
}
}
}
}
return action;
}

View File

@ -38,10 +38,12 @@ public:
bool file_size_query;
bool is_upload;
double starting_size;
// File size at start of transfer.
// This is used to to implement a "minimum download increment"
// File size at start of transfer, used for:
// 1) a "minimum download increment"
// that rejects partial downloads of less than 5K,
// since these may be error messages from proxies.
// 2) lets us recover when server ignored Range request
// and sent us whole file
FILE_XFER();
~FILE_XFER();

View File

@ -92,7 +92,6 @@ void NET_XFER::reset() {
strcpy(infile, "");
strcpy(outfile, "");
CurlResult = CURLE_OK;
strcpy(strCurlResult, "");
bTempOutfile = true;
is_connected = false;
want_download = false;
@ -103,8 +102,6 @@ void NET_XFER::reset() {
fileOut = NULL;
io_ready = true;
error = 0;
file_read_buf_offset = 0;
file_read_buf_len = 0;
bytes_xferred = 0;
xfer_speed = 0;
bSentHeader = false;
@ -285,7 +282,8 @@ void NET_XFER_SET::got_select(FDSET_GROUP&, double timeout) {
// included with Mac OS X 10.3.9
//
curlErr = curl_easy_getinfo(nxf->curlEasy,
(CURLINFO)(CURLINFO_LONG+25) /*CURLINFO_OS_ERRNO*/, &nxf->error);
(CURLINFO)(CURLINFO_LONG+25) /*CURLINFO_OS_ERRNO*/, &nxf->error
);
nxf->io_done = true;
nxf->io_ready = false;
@ -309,27 +307,8 @@ void NET_XFER_SET::got_select(FDSET_GROUP&, double timeout) {
//
nxf->http_op_state = HTTP_STATE_DONE;
// added a more useful error string
// (just pass the curl string up for now)
//
nxf->CurlResult = pcurlMsg->data.result;
safe_strcpy(nxf->strCurlResult, curl_easy_strerror(nxf->CurlResult));
// optional, example use, non-zero CurlResult has a useful error string:
//if (nxf->CurlResult) fprintf(stdout, "Error: %s\n", nxf->strCurlResult);
// 200 is a good HTTP response code
// It may not mean the data received is "good"
// (the calling program will have to check/parse that)
// but it at least means that the server operation
// went through fine
//
// NOTE: http_op_retval is multipurposed,
// it can also contain any error code that BOINC would return
// for IO errors and DNS errors.
// We need to translate between the curl error codes and the equiv.
// BOINC error codes here.
//
if (nxf->CurlResult == CURLE_OK) {
if ((nxf->response/100)*100 == HTTP_STATUS_OK) {
nxf->http_op_retval = 0;
@ -349,7 +328,9 @@ void NET_XFER_SET::got_select(FDSET_GROUP&, double timeout) {
std::string url = "http://www.google.com";
gstate.lookup_website_op.do_rpc(url);
}
msg_printf(0, MSG_ERROR, "HTTP error: %s", nxf->strCurlResult);
msg_printf(0, MSG_ERROR,
"HTTP error: %s", curl_easy_strerror(nxf->CurlResult)
);
nxf->http_op_retval = ERR_HTTP_ERROR;
}

View File

@ -55,7 +55,6 @@ net_xfer object status codes (using libcurl):
nxf->response maps to HTTP_STATUS_* (from http_curl.h)
nxf->http_op_state maps to HTTP_STATE_* (from http_curl.h)
nxf->CurlError is a curl specific code (maps to the CURLE_* enums in curl/curl.h)
nxf->strCurlError is a human-readable msg (i.e. "couldn't connect to server")
*/
class NET_XFER {
@ -74,7 +73,6 @@ public:
char* req1;
bool bSentHeader; // CMC -- a flag that I already sent the header
CURLcode CurlResult; // CMC -- send up curl result code
char strCurlResult[_MAX_PATH]; // CMC -- 'human-readable' string with result info
// int socket; // CMC -- deprecated, net_xfer's via curlEasy handle above
char hostname[256]; // The host we're connecting to (possibly a proxy)
@ -105,8 +103,6 @@ public:
double xfer_speed;
double bytes_xferred; // bytes transferred in this session
double content_length;
char file_read_buf[MAX_BLOCKSIZE];
int file_read_buf_offset, file_read_buf_len;
int seconds_until_timeout;
// CMC - moved from http_op

View File

@ -3,12 +3,15 @@
$light_blue="#d8e8ff";
$med_blue="#c0d0f0";
function last_mod() {
return gmdate("g:i A \U\T\C, F d Y", filemtime($_SERVER["SCRIPT_FILENAME"]));
function last_mod($datefile) {
return gmdate("g:i A \U\T\C, F d Y", filemtime($datefile));
}
function page_head($title) {
$d = last_mod();
function page_head($title, $datefile=null) {
if (!$datefile) {
$datefile = $_SERVER["SCRIPT_FILENAME"];
}
$d = last_mod($datefile);
echo "<html>
<head>
<link rel=\"stylesheet\" type=\"text/css\" href=\"white.css\"/>