📄 http_fetcher.cpp
字号:
}
else
/* Found 'Location:' but contains no URL! We'll handle it as
* 'found', hopefully the resulting document will give the user
* a hint as to what happened. */
found = 1;
}
else
found = 1;
} while(!found && redirectsFollowed <= DEFAULT_REDIRECTS);
if(url) /* Redirection code may malloc this, then exceed DEFAULT_REDIRECTS */
{
free(url);
url = NULL;
}
if(redirectsFollowed >= DEFAULT_REDIRECTS && !found)
{
closesocket(sock); // added by jarjar
//close(sock); // removed by jarjar
errorInt = DEFAULT_REDIRECTS; /* To be inserted in error string */
errorSource = FETCHER_ERROR;
http_errno = HF_MAXREDIRECTS;
return -1;
}
/*
* Parse out about how big the data segment is.
* Note that under current HTTP standards (1.1 and prior), the
* Content-Length field is not guaranteed to be accurate or even present.
* I just use it here so I can allocate a ballpark amount of memory.
*
* Note that some servers use different capitalization
*/
charIndex = strstr(headerBuf, "Content-Length:");
if(charIndex == NULL)
charIndex = strstr(headerBuf, "Content-length:");
if(charIndex != NULL)
{
ret = sscanf(charIndex + strlen("content-length: "), "%d",
&fileSize);
if(ret < 1)
{
closesocket(sock); // added by jarjar
//close(sock); // removed by jarjar
errorSource = FETCHER_ERROR;
http_errno = HF_CONTENTLEN;
return -1;
}
}
char tmpReadBuf[BLOCK_SIZE];
DWORD tmpWriteBytes = 0;
tv.tv_sec = DEFAULT_READ_TIMEOUT;
tv.tv_usec = 0;
DWORD dwStartTicks = GetTickCount();
/* Begin reading the body of the file */
while(ret > 0 && (fileSize == -1 || downloadedSize < fileSize) && localFile != INVALID_HANDLE_VALUE)
{
FD_ZERO(&rfds);
FD_SET((SOCKET)sock, &rfds);
selectRet = select(sock+1, &rfds, NULL, NULL, &tv);
if(selectRet == 0)
{
// timeout means nothing
continue;
/*
errorSource = FETCHER_ERROR;
http_errno = HF_DATATIMEOUT;
errorInt = DEFAULT_READ_TIMEOUT;
closesocket(sock); // added by jarjar
//close(sock); // removed by jarjar
return -1;
*/
}
else if(selectRet == -1)
{
closesocket(sock); // added by jarjar
//close(sock); // removed by jarjar
errorSource = ERRNO;
return -1;
}
ret = recv(sock, tmpReadBuf, BLOCK_SIZE, 0); // added by jarjar
if(ret == -1)
{
closesocket(sock); // added by jarjar
//close(sock); // removed by jarjar
errorSource = ERRNO;
return -1;
}
if(INVALID_SET_FILE_POINTER == SetFilePointer(localFile, downloadedSize, 0, FILE_BEGIN))
{
int xxx = GetLastError();
closesocket(sock); // added by jarjar
//close(sock); // removed by jarjar
errorSource = ERRNO;
return -1;
}
downloadedSize += ret;
if(!WriteFile(localFile, tmpReadBuf, ret, &tmpWriteBytes, NULL) || tmpWriteBytes != ret)
{
int xxx = GetLastError();
closesocket(sock); // added by jarjar
//close(sock); // removed by jarjar
errorSource = ERRNO;
return -1;
}
// For bandwidth throttling
if (limitSpeed > 0.0f)
{
double t = (double)(GetTickCount() - dwStartTicks);
double q = (double)((double)downloadedSize / t);
if (q > limitSpeed)
Sleep((DWORD)((((q*t)/limitSpeed)-t)));
}
}
::FlushFileBuffers(localFile);
closesocket(sock); // added by jarjar
//close(sock); // removed by jarjar
return downloadedSize;
}
/*
* Returns a pointer to the current error description message. The
* message pointed to is only good until the next call to http_strerror(),
* so if you need to hold on to the message for a while you should make
* a copy of it
*/
const char* HttpFetcher::http_strerror()
{
int errno;
if(errorSource == ERRNO)
return strerror(errno);
else if(errorSource == FETCHER_ERROR)
{
if(strstr(http_errlist[http_errno], "%d") == NULL)
return http_errlist[http_errno];
else
{
/* The error string has a %d in it, we need to insert errorInt.
* convertedError[128] has been declared for that purpose */
char *stringIndex, *originalError;
originalError = (char *)http_errlist[http_errno];
convertedError[0] = 0; /* Start off with NULL */
stringIndex = strstr(originalError, "%d");
strncat(convertedError, originalError, /* Copy up to %d */
abs(stringIndex - originalError));
sprintf(&convertedError[strlen(convertedError)],"%d",errorInt);
stringIndex += 2; /* Skip past the %d */
strcat(convertedError, stringIndex);
return convertedError;
}
}
return http_errlist[HF_METAERROR]; /* Should NEVER happen */
}
/*
* Reads the metadata of an HTTP response.
* Perhaps a little inefficient, as it reads 1 byte at a time, but
* I don't think it's that much of a loss (most headers aren't HUGE).
* Returns:
* # of bytes read on success, or
* -1 on error
*/
int HttpFetcher::_http_read_header(int sock, char *headerPtr)
{
fd_set rfds;
struct timeval tv;
int bytesRead = 0, newlines = 0, ret, selectRet;
while(newlines != 2 && bytesRead != HEADER_BUF_SIZE)
{
FD_ZERO(&rfds);
FD_SET((SOCKET)sock, &rfds);
tv.tv_sec = DEFAULT_READ_TIMEOUT;
tv.tv_usec = 0;
selectRet = select(sock+1, &rfds, NULL, NULL, &tv);
if(selectRet == 0)
{
errorSource = FETCHER_ERROR;
http_errno = HF_HEADTIMEOUT;
errorInt = DEFAULT_READ_TIMEOUT;
return -1;
}
else if(selectRet == -1) { errorSource = ERRNO; return -1; }
ret = recv(sock, headerPtr, 1, 0);
//ret = read(sock, headerPtr, 1); //removed by jarjar
if(ret == -1) { errorSource = ERRNO; return -1; }
bytesRead++;
if(*headerPtr == '\r') /* Ignore CR */
{
/* Basically do nothing special, just don't set newlines
* to 0 */
headerPtr++;
continue;
}
else if(*headerPtr == '\n') /* LF is the separator */
newlines++;
else
newlines = 0;
headerPtr++;
}
headerPtr -= 3; /* Snip the trailing LF's */
*headerPtr = '\0';
return bytesRead;
}
/*
* Opens a TCP socket and returns the descriptor
* Returns:
* socket descriptor, or
* -1 on error
*/
int HttpFetcher::makeSocket(const char *host)
{
int sock; /* Socket descriptor */
struct sockaddr_in sa; /* Socket address */
struct hostent *hp; /* Host entity */
int ret;
u_short port; // added by jarjar
//int port; // removed by jarjar
char *p;
/* Check for port number specified in URL */
p = strchr(host, ':');
if(p)
{
port = atoi(p + 1);
*p = '\0';
}
else
port = PORT_NUMBER;
hp = gethostbyname(host);
if(hp == NULL) { errorSource = ERRNO; return -1; }
/* Copy host address from hostent to (server) socket address */
memcpy((char *)&sa.sin_addr, (char *)hp->h_addr, hp->h_length);
sa.sin_family = hp->h_addrtype; /* Set service sin_family to PF_INET */
sa.sin_port = htons(port); /* Put portnum into sockaddr */
sock = socket(hp->h_addrtype, SOCK_STREAM, 0);
if(sock == -1) { errorSource = ERRNO; return -1; }
ret = connect(sock, (struct sockaddr *)&sa, sizeof(sa));
if(ret == -1) { errorSource = ERRNO; return -1; }
return sock;
}
/*
* Determines if the given NULL-terminated buffer is large enough to
* concatenate the given number of characters. If not, it attempts to
* grow the buffer to fit.
* Returns:
* 0 on success, or
* -1 on error (original buffer is unchanged).
*/
int HttpFetcher::_checkBufSize(char **buf, int *bufsize, int more)
{
char *tmp;
int roomLeft = *bufsize - (strlen(*buf) + 1);
if(roomLeft > more)
return 0;
tmp = (char*)realloc(*buf, *bufsize + more + 1);
if(tmp == NULL)
return -1;
*buf = tmp;
*bufsize += more + 1;
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -