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;
    }
}

posted on 2010-05-31 16:32  风乔  阅读(389)  评论(0编辑  收藏  举报

导航