简单HTTP下载实现

3 views
Skip to first unread message

裴国兴

unread,
Nov 8, 2009, 7:00:20 AM11/8/09
to btload
----------------------urifetch.h----------------
struct uristat{
size_t st_size;
time_t st_mtime;
};

int uriopen(const char *url, struct uristat *sb);
int urifetch(int fd, size_t size, const char *path);

----------------------urifetch.c----------------
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <winsock.h>
#include "urifetch.h"

#define close(a) closesocket(a)

static int leapMonth(size_t year, size_t month)
{
return (year%100)&&!(year&0x3)&&(month==2);
}

static int urlsplit(const char **inp, char *outp, int splitch)
{
char *output = outp;
const char *url = *inp;
while (*url && *url!=splitch)
*output++ = *url++;
*output = 0;
*inp = url;
return output - outp;
}

static int urlskip(const char **inp, const char *skips)
{
const char *url = *inp;
const char *oldinp = *inp;
while (*url == *skips++)
url++;
*inp = url;
return url-oldinp;
}

static size_t Month2Date(size_t year, int month)
{
int i;
size_t date = 0;
const int MONTHS[]={31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30,
31, 29};
for (i=0; i<month; i++)
date += MONTHS[i]+leapMonth(year, i);
return date;
}

static time_t uritime(const char *uritime)
{
char format[1024];
const char *month_names[] = {
"Jan", "Feb", "Mar", "Apr",
"May", "Jun", "Jul", "Aug",
"Sep", "Oct", "Nov", "Dec"
};

size_t month = 0;
size_t date, year, hour, minus, second;
for (month=0; month<12; month++) {
snprintf(format, sizeof(format), "%s %s %s",
"%*s %d", month_names[month], "%d %d:%d:%d GMT");
if (sscanf(uritime, format, &date, &year,
&hour, &minus, &second) == 5)
break;
}

size_t total = 0;
assert(month < 12);

size_t y = 1970;
for (y=1970; y<year; y++) {
size_t day = Month2Date(y, 12);
total += day;
}
total += Month2Date(year, month)+date;
total = total*24+hour;
total = total*60+minus;
total = total*60+second;
return (time_t)(total);
}

static int statparse(const char *header, size_t count, struct uristat
*sb)
{
size_t length = 0;
const char *optname = NULL;

assert(sb != NULL);
optname="Content-Length: ";
if (!strncmp(optname, header, strlen(optname))) {
sscanf(header+strlen(optname), "%d", &length);
sb->st_size = length;
return 0;
}
optname="Last-Modified: ";
if (!strncmp(optname, header, strlen(optname))) {
/* Sat, 15 Aug 2009 05:46:42 GMT */
sb->st_mtime = uritime(header+strlen(optname));
return 0;
}
printf("%s", header);
return 0;
}

static int urigets(int fd, char *header, size_t count)
{
int hdrsz = 0;
int error = 0;

while (hdrsz < count) {
error = recv(fd, &header[hdrsz], 1, 0);
if (error != 1)
break;
hdrsz++;
if (hdrsz < 2)
continue;
if (!strncmp(&header[hdrsz-2], "\r\n", 2))
break;
}
if (hdrsz < count)
header[hdrsz] = 0;
return hdrsz;
}

int uriopen(const char *url, struct uristat *sb)
{
char schema[32];
char domain[256];
char location[512];
char urlrequest[4096];
char header[8192];

const char *oldurl = url;

urlsplit(&url, schema, ':');
urlskip(&url, "://");
urlsplit(&url, domain, '/');
strcpy(location, url);

int fd = -1;
int hdrsz = 0;
int error = 0;
struct hostent *phost;
phost = gethostbyname(domain);
if (phost == NULL)
return -1;
struct sockaddr_in srvaddr;
srvaddr.sin_family = AF_INET;
srvaddr.sin_port = htons(80);
srvaddr.sin_addr = *(struct in_addr*)phost->h_addr;
struct sockaddr *caddr = (struct sockaddr*)&srvaddr;
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1)
return -1;
error = connect(fd, caddr, sizeof(srvaddr));
if (error != 0)
goto fail;
snprintf(urlrequest, sizeof urlrequest,
"GET %s HTTP/1.0\r\n"
"Accept: */*\r\n"
"Host: %s\r\n"
"Referer: %s\r\n"
"Connection: Close\r\n"
/*"User-Agent: MiniDownload\r\n"*/
"\r\n", location, domain, oldurl);
error = send(fd, urlrequest, strlen(urlrequest), 0);
if (error < strlen(urlrequest))
goto fail;

hdrsz = urigets(fd, header, sizeof(header));
assert(hdrsz < sizeof(header));
printf("%s\n", header);
hdrsz = urigets(fd, header, sizeof(header));
assert(hdrsz < sizeof(header));
while (hdrsz > 2) {
statparse(header, hdrsz, sb);
hdrsz = urigets(fd, header, sizeof(header));
}
assert(!strcmp("\r\n", header));
return fd;
fail:
close(fd);
return -1;
}

int urifetch(int fd, size_t size, const char *path)
{
int iocnt;
int error = -1;
char buffer[8192];

FILE *fpo = fopen(path, "wb");

size_t total = 0;
assert(fpo != NULL);
while (total < size){
iocnt = recv(fd, buffer, sizeof(buffer), 0);
if (iocnt == -1)
goto fail;
if (iocnt == 0)
goto fail;
fwrite(buffer, iocnt, 1, fpo);
total += iocnt;
}
#if 1
assert (total == size);
iocnt = recv(fd, buffer, sizeof(buffer), 0);
assert (iocnt == 0);
#endif
error = 0;
fail:
fclose(fpo);
return error;
}

-----------------简单HTTP下载实现
Reply all
Reply to author
Forward
0 new messages