C 语言 断点续传2
/* packet handler */
int xhttpd_packet_handler(CONN *conn, CB_DATA *packet)
{
char buf[HTTP_BUF_SIZE], file[HTTP_PATH_MAX], line[HTTP_PATH_MAX], *host = NULL,
*mime = NULL, *home = NULL, *pp = NULL, *p = NULL, *end = NULL, *root = NULL,
*s = NULL, *outfile = NULL, *name = NULL, *encoding = NULL;
int i = 0, n = 0, found = 0, nmime = 0, mimeid = 0, is_need_compress = 0, keepalive = 0;
off_t from = 0, to = 0, len = 0;
struct stat st = {0};
HTTP_REQ http_req = {0};
void *dp = NULL;
if(conn && packet)
{
p = packet->data;
end = packet->data + packet->ndata;
//fprintf(stdout, "%s", p);
if(http_request_parse(p, end, &http_req, http_headers_map) == -1)
{
//fprintf(stdout, "%s::%d REQUEST:%s path:%s\n", __FILE__, __LINE__, packet->data, http_req.path);
goto err;
}
if(http_req.reqid == HTTP_GET)
{
REALLOG(logger, "[%s:%d] GET %s", conn->remote_ip, conn->remote_port, http_req.path);
//get vhost
if((n = http_req.headers[HEAD_REQ_HOST]) > 0)
{
p = http_req.hlines + n;
if(strncasecmp(p, "www.", 4) == 0) p += 4;
host = p;
while(*p != ':' && *p != '\0')++p;
*p = '\0';
n = p - host;
TRIETAB_GET(namemap, host, n, dp);
if((i = ((long)dp - 1)) >= 0) home = httpd_vhosts[i].home;
}
if(home == NULL) home = httpd_home;
if(home == NULL) goto err;
p = file;
p += sprintf(p, "%s", home);
root = p;
if(http_req.path[0] != '/')
p += sprintf(p, "/%s", http_req.path);
else
p += sprintf(p, "%s", http_req.path);
//fprintf(stdout, "outfile:%s\r\n", file);
if((n = (p - file)) > 0 && lstat(file, &st) == 0)
{
if(S_ISDIR(st.st_mode))
{
i = 0;
found = 0;
if(p > file && *(p-1) != '/') *p++ = '/';
while(i < nindexes && http_indexes[i])
{
pp = p;
pp += sprintf(pp, "%s", http_indexes[i]);
if(access(file, F_OK) == 0 && lstat(file, &st) == 0)
{
found = 1;
p = pp;
break;
}
++i;
}
//index view
if(found == 0 && http_indexes_view && (*p = '\0') >= 0)
{
end = --p;
if(xhttpd_index_view(conn, &http_req, file, root, end) == 0) return 0;
else goto err;
}
}
s = mime = line + HTTP_PATH_MAX - 1;
*s = '\0';
pp = --p ;
while(pp > file && *pp != '.')
{
if(*pp >= 'A' && *pp <= 'Z')
{
*--mime = *pp + ('a' - 'A');
}
else *--mime = *pp;
--pp;
}
//while( > file && *mime != '.')--mime;
if(mime > line) nmime = s - mime;
//no content
if(st.st_size == 0)
{
return conn->push_chunk(conn, HTTP_NO_CONTENT,
strlen(HTTP_NO_CONTENT));
}
//if not change
else if((n = http_req.headers[HEAD_REQ_IF_MODIFIED_SINCE]) > 0
&& str2time(http_req.hlines + n) == st.st_mtime)
{
return conn->push_chunk(conn, HTTP_NOT_MODIFIED,
strlen(HTTP_NOT_MODIFIED));
}
else
{
//range
if((n = http_req.headers[HEAD_REQ_RANGE]) > 0)
{
p = http_req.hlines + n;
while(*p == 0x20 || *p == '\t')++p;
if(strncasecmp(p, "bytes=", 6) == 0) p += 6;
while(*p == 0x20)++p;
if(*p == '-')
{
++p;
while(*p == 0x20)++p;
if(*p >= '0' && *p <= '9') to = (off_t)atoll(p) + 1;
}
else if(*p >= '0' && *p <= '9')
{
from = (off_t) atoll(p++);
while(*p != '-')++p;
++p;
while(*p == 0x20)++p;
if(*p >= '0' && *p <= '9') to = (off_t)atoll(p) + 1;
}
}
if(to == 0) to = st.st_size;
len = to - from;
//fprintf(stdout, "%s::%d mime:%s[%d] len:%lld [%lld-%lld]\n", __FILE__, __LINE__, mime, nmime, LL(len), LL(from), LL(to));
//mime
if(mime && nmime > 0)
{
TRIETAB_GET(namemap, mime, nmime, dp);
if((mimeid = ((long)dp - 1)) >= 0
&& (n = http_req.headers[HEAD_REQ_ACCEPT_ENCODING]) > 0
&& strstr(http_mime_types[mimeid].s, "text"))
{
p = http_req.hlines + n;
#ifdef HAVE_ZLIB
if(strstr(p, "deflate"))
is_need_compress |= HTTP_ENCODING_DEFLATE;
if(strstr(p, "gzip"))
is_need_compress |= HTTP_ENCODING_GZIP;
//if(strstr(p, "compress")) is_need_compress |= HTTP_ENCODING_COMPRESS;
#endif
#ifdef HAVE_BZ2LIB
if(strstr(p, "bzip2"))
is_need_compress |= HTTP_ENCODING_BZIP2;
#endif
}
if(mimeid < 0)
{
end = root + 1;
while(*end != '\0')
{
if(*end == '/') name = ++end;
else ++end;
}
}
}
if(is_need_compress > 0 && xhttpd_compress_handler(conn,
&http_req, host, is_need_compress, mimeid, file,
root, from, to, &st) == 0)
{
return 0;
}
else outfile = file;
p = buf;
if(from > 0)
p += sprintf(p, "HTTP/1.1 206 Partial Content\r\nAccept-Ranges: bytes\r\n"
"Content-Range: bytes %lld-%lld/%lld\r\n",
LL(from), LL(to - 1), LL(st.st_size));
else
p += sprintf(p, "HTTP/1.1 200 OK\r\nAccept-Ranges: bytes\r\n");
p += sprintf(p, "Content-Type: %s; charset=%s\r\n",
http_mime_types[mimeid].s, http_default_charset);
//fprintf(stdout, "%s::%d outfile:%s\n", __FILE__, __LINE__, outfile);
if((n = http_req.headers[HEAD_GEN_CONNECTION]) > 0)
{
p += sprintf(p, "Connection: %s\r\n", http_req.hlines + n);
if((strncasecmp(http_req.hlines + n, "close", 5)) !=0 )
keepalive = 1;
}
else
{
p += sprintf(p, "Connection: close\r\n");
}
p += sprintf(p, "Last-Modified:");
p += GMTstrdate(st.st_mtime, p);
p += sprintf(p, "%s", "\r\n");//date end
if(encoding) p += sprintf(p, "Content-Encoding: %s\r\n", encoding);
if(name)
p += sprintf(p, "Content-Disposition: attachment, filename='%s'\r\n", name);
p += sprintf(p, "Date: ");p += GMTstrdate(time(NULL),p);p += sprintf(p,"\r\n");
p += sprintf(p, "Content-Length: %lld\r\n", LL(len));
p += sprintf(p, "Server: xhttpd/%s\r\n\r\n", XHTTPD_VERSION);
conn->push_chunk(conn, buf, (p - buf));
conn->push_file(conn, outfile, from, len);
if(!keepalive) conn->over(conn);
return 0;
}
}
}
else if(http_req.reqid == HTTP_POST)
{
REALLOG(logger, "[%s:%d] POST %s", conn->remote_ip, conn->remote_port, http_req.path);
if((n = http_req.headers[HEAD_ENT_CONTENT_LENGTH]) > 0
&& (p = (http_req.hlines + n)) && (n = atoi(p)) > 0)
{
conn->save_cache(conn, &http_req, sizeof(HTTP_REQ));
return conn->recv_chunk(conn, n);
}
return conn->push_chunk(conn, HTTP_NOT_FOUND, strlen(HTTP_NOT_FOUND));
}
err:
return conn->push_chunk(conn, HTTP_NOT_FOUND, strlen(HTTP_NOT_FOUND));
}
return -1;
}
/* data handler */
int xhttpd_data_handler(CONN *conn, CB_DATA *packet, CB_DATA *cache, CB_DATA *chunk)
{
if(conn)
{
return conn->push_chunk(conn, HTTP_NO_CONTENT, strlen(HTTP_NO_CONTENT));
}
return -1;
}
/* OOB handler */
int xhttpd_oob_handler(CONN *conn, CB_DATA *oob)
{
if(conn && conn->push_chunk)
{
conn->push_chunk((CONN *)conn, ((CB_DATA *)oob)->data, oob->ndata);
return oob->ndata;
}
return -1;
}
/* signal */
static void xhttpd_stop(int sig)
{
switch (sig)
{
case SIGINT:
case SIGTERM:
fprintf(stderr, "xhttpd server is interrupted by user.\n");
if(sbase)sbase->stop(sbase);
break;
default:
break;
}
}