📄 http_fetcher.cpp
字号:
/* http_fetcher.c - HTTP handling functions
HTTP Fetcher
Copyright (C) 2001, 2003, 2004 Lyle Hanson (lhanson@users.sourceforge.net)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
See LICENSE file for details
*/
#include "stdafx.h"
#include "http_fetcher.h"
HttpFetcher::HttpFetcher() : DEFAULT_VERSION("1.1"), HTTP_VERSION("HTTP/1.0"), DEFAULT_USER_AGENT("Chaos Client")
{
errorSource = 0;
http_errno = 0;
errorInt = 0; /* When the error message has a %d in it,
* this variable is inserted */
/* Note that '%d' cannot be escaped at this time */
http_errlist[HF_SUCCESS] ="成功";
http_errlist[HF_METAERROR] ="内部错误.";
http_errlist[HF_NULLURL] ="无内容的URL";
http_errlist[HF_HEADTIMEOUT] ="超时; %d秒钟内没有收到HTTP头";
http_errlist[HF_DATATIMEOUT] ="超时; %d秒钟内没有收到数据";
http_errlist[HF_FRETURNCODE] ="无返回代码";
http_errlist[HF_CRETURNCODE] ="无效的返回代码";
http_errlist[HF_STATUSCODE] ="状态代码是: %d. \r\n401:需要认证, 403:无法访问, 404:没有找到, 500:服务器出错";
http_errlist[HF_CONTENTLEN] ="无效的内容长度(Content-Length)";
http_errlist[HF_HERROR] ="网络错误 (description unavailable)";
http_errlist[HF_CANTREDIRECT] ="状态代码是: %d,但是没有\"Location\"项";
http_errlist[HF_MAXREDIRECTS] ="已经达到最大重定向次数(%d)";
}
/*
* Actually downloads the url to localFile.
* Returns size of download on success, -1 on error is set,
*/
int HttpFetcher::http_fetch(const char *url_tmp, HANDLE localFile, UINT& fileSize, UINT& downloadedSize, double limitSpeed)
{
fd_set rfds;
struct timeval tv;
char headerBuf[HEADER_BUF_SIZE];
char *tmp, *url, *requestBuf = NULL, *host, *charIndex;
int sock, bufsize = REQUEST_BUF_SIZE;
int i,
ret = -1,
tempSize,
selectRet,
found = 0, /* For redirects */
redirectsFollowed = 0;
downloadedSize = 0;
fileSize = -1;
if(url_tmp == NULL)
{
errorSource = FETCHER_ERROR;
http_errno = HF_NULLURL;
return -1;
}
/* Copy the url passed in into a buffer we can work with, change, etc. */
url = (char*)malloc(strlen(url_tmp)+1);
if(url == NULL)
{
errorSource = ERRNO;
return -1;
}
strncpy(url, url_tmp, strlen(url_tmp) + 1);
/* This loop allows us to follow redirects if need be. An afterthought,
* added to provide this basic functionality. Will hopefully be designed
* better in 2.x.x ;) */
do {
/* Seek to the file path portion of the url */
charIndex = strstr(url, "://");
if(charIndex != NULL)
{
/* url contains a protocol field */
charIndex += strlen("://");
host = charIndex;
charIndex = strchr(charIndex, '/');
}
else
{
host = (char *)url;
charIndex = strchr(url, '/');
}
/* Compose a request string */
requestBuf = (char*)malloc(bufsize);
if(requestBuf == NULL)
{
free(url);
errorSource = ERRNO;
return -1;
}
requestBuf[0] = 0;
if(charIndex == NULL)
{
/* The url has no '/' in it, assume the user is making a root-level
* request */
tempSize = strlen("GET /") + strlen(HTTP_VERSION) + 2;
if(_checkBufSize(&requestBuf, &bufsize, tempSize) ||
_snprintf(requestBuf, bufsize, "GET / %s\r\n", HTTP_VERSION) < 0)
{
free(url);
free(requestBuf);
errorSource = ERRNO;
return -1;
}
}
else
{
tempSize = strlen("GET ") + strlen(charIndex) +
strlen(HTTP_VERSION) + 4;
/* + 4 is for ' ', '\r', '\n', and NULL */
if(_checkBufSize(&requestBuf, &bufsize, tempSize) ||
_snprintf(requestBuf, bufsize, "GET %s %s\r\n",
charIndex, HTTP_VERSION) < 0)
{
free(url);
free(requestBuf);
errorSource = ERRNO;
return -1;
}
}
/* Null out the end of the hostname if need be */
if(charIndex != NULL)
*charIndex = 0;
/* Use Host: even though 1.0 doesn't specify it. Some servers
* won't play nice if we don't send Host, and it shouldn't
* hurt anything */
ret = bufsize - strlen(requestBuf); /* Space left in buffer */
tempSize = (int)strlen("Host: ") + (int)strlen(host) + 3;
/* +3 for "\r\n\0" */
if(_checkBufSize(&requestBuf, &bufsize, tempSize + 128))
{
free(url);
free(requestBuf);
errorSource = ERRNO;
return -1;
}
strcat(requestBuf, "Host: ");
strcat(requestBuf, host);
strcat(requestBuf, "\r\n");
tempSize = (int)strlen("User-Agent: ") +
(int)strlen(DEFAULT_USER_AGENT) + (int)strlen(DEFAULT_VERSION) + 4;
/* + 4 is for '\', '\r', '\n', and NULL */
if(_checkBufSize(&requestBuf, &bufsize, tempSize))
{
free(url);
free(requestBuf);
errorSource = ERRNO;
return -1;
}
strcat(requestBuf, "User-Agent: ");
strcat(requestBuf, DEFAULT_USER_AGENT);
strcat(requestBuf, "/");
strcat(requestBuf, DEFAULT_VERSION);
strcat(requestBuf, "\r\n");
tempSize = (int)strlen("Connection: Close\r\n\r\n");
if(_checkBufSize(&requestBuf, &bufsize, tempSize))
{
free(url);
free(requestBuf);
errorSource = ERRNO;
return -1;
}
strcat(requestBuf, "Connection: Close\r\n\r\n");
/* Now free any excess memory allocated to the buffer */
tmp = (char*)realloc(requestBuf, strlen(requestBuf) + 1);
if(tmp == NULL)
{
free(url);
free(requestBuf);
errorSource = ERRNO;
return -1;
}
requestBuf = tmp;
sock = makeSocket(host); /* errorSource set within makeSocket */
if(sock == -1) { free(url); free(requestBuf); return -1;}
free(url);
url = NULL;
if(send(sock, requestBuf, strlen(requestBuf), 0) == -1) // added by jarjar
//if(write(sock, requestBuf, strlen(requestBuf)) == -1) // removed by jarjar
{
closesocket(sock); // added by jarjar
//close(sock); // removed by jarjar
free(requestBuf);
errorSource = ERRNO;
return -1;
}
free(requestBuf);
requestBuf = NULL;
/* Grab enough of the response to get the metadata */
ret = _http_read_header(sock, headerBuf); /* errorSource set within */
if(ret < 0)
{
closesocket(sock); // added by jarjar
//close(sock); // removed by jarjar
return -1;
}
/* Get the return code */
charIndex = strstr(headerBuf, "HTTP/");
if(charIndex == NULL)
{
closesocket(sock); // added by jarjar
//close(sock); // removed by jarjar
errorSource = FETCHER_ERROR;
http_errno = HF_FRETURNCODE;
return -1;
}
while(*charIndex != ' ')
charIndex++;
charIndex++;
ret = sscanf(charIndex, "%d", &i);
if(ret != 1)
{
closesocket(sock); // added by jarjar
//close(sock); // removed by jarjar
errorSource = FETCHER_ERROR;
http_errno = HF_CRETURNCODE;
return -1;
}
if(i<200 || i>307)
{
closesocket(sock); // added by jarjar
//close(sock); // removed by jarjar
errorInt = i; /* Status code, to be inserted in error string */
errorSource = FETCHER_ERROR;
http_errno = HF_STATUSCODE;
return -1;
}
/* If a redirect, repeat operation until final URL is found or we
* redirect DEFAULT_REDIRECTS times. Note the case sensitive "Location",
* should probably be made more robust in the future (without relying
* on the non-standard strcasecmp()).
* This bit mostly by Dean Wilder, tweaked by me */
if(i >= 300)
{
redirectsFollowed++;
/* Pick up redirect URL, allocate new url, and repeat process */
charIndex = strstr(headerBuf, "Location:");
if(!charIndex)
{
closesocket(sock); // added by jarjar
//close(sock); // removed by jarjar
errorInt = i; /* Status code, to be inserted in error string */
errorSource = FETCHER_ERROR;
http_errno = HF_CANTREDIRECT;
return -1;
}
charIndex += strlen("Location:");
/* Skip any whitespace... */
while(*charIndex != '\0' && isspace(*charIndex))
charIndex++;
if(*charIndex == '\0')
{
closesocket(sock); // added by jarjar
//close(sock); // removed by jarjar
errorInt = i; /* Status code, to be inserted in error string */
errorSource = FETCHER_ERROR;
http_errno = HF_CANTREDIRECT;
return -1;
}
i = strcspn(charIndex, " \r\n");
if(i > 0)
{
url = (char *)malloc(i + 1);
strncpy(url, charIndex, i);
url[i] = '\0';
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -