⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 http.c

📁 linux下流媒体下载程序代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * judges if http_hdr is complete HTTP header, or still needs some parts. *    return value :       0 ... NOT complete *                         1 ... COMPLETE!! */int http_is_entire_header(struct http_header_t *http_hdr){    if(http_hdr == NULL) return 0; /* unlikely, but error */      if(http_hdr->buffer == NULL) return 0;   /* nothing received. */        if(strstr(http_hdr->buffer,"\r\n\r\n") ||        strstr(http_hdr->buffer,"\n\n")) {	return 1;    }    return 0;}/* * http_response_parse :  parse http response header  * make http_hdr from raw data in http_hdr->buffer * *    return value :        -1 ... ERROR *                           0 ... already parsed. *                           1 ... success. */int http_response_parse(struct http_header_t *http_hdr){    char *hdr_ptr, *ptr;    char *field = NULL;      int pos_hdr_sep, hdr_sep_len;    size_t len;      if(http_hdr == NULL) return -1;    if(http_hdr->is_parsed) return 0; /* already parsed. */        /*      1. get protocol.    */    hdr_ptr = strstr(http_hdr->buffer, " ");    if(hdr_ptr == NULL) {	display(MSDL_ERR,"Malformed answer : No %20 separator\n");	return -1;    }      len = hdr_ptr - http_hdr->buffer;    http_hdr->protocol = xmalloc(len + 1);    strncpy(http_hdr->protocol,http_hdr->buffer,len);    http_hdr->protocol[len] = '\0';        /* get (useless) minor version here. */    if(!strncasecmp(http_hdr->protocol,"HTTP",4)) {	if(sscanf(http_hdr->protocol+5,"1.%d",		  &(http_hdr->http_minor_version)) != 1)	    display(MSDL_ERR,"Malformed answer: http minor version unsepcified\n");	/* actually, lack of HTTP version is not fatal AT ALL. */    }    /*      2. get status code    */    if(sscanf(++hdr_ptr,"%d",&(http_hdr->status_code)) != 1) {	display(MSDL_ERR,"Malformed answer : No http status code!!\n");	return -1;    }       hdr_ptr += 4; /* "[0-9][0-9][0-9] " */      /*      3. get reason phrase    */    ptr = strstr(hdr_ptr,"\n");    if(ptr == NULL) {	display(MSDL_ERR,"Malformed answer : unable to get reason_phrase\n");	return -1;    }    len = ptr - hdr_ptr; /* len of reason phrase. */      http_hdr->reason_phrase = xmalloc(len + 1);    strncpy(http_hdr->reason_phrase,hdr_ptr,len);    if(http_hdr->reason_phrase[len - 1] == '\r') { /* M$ style newline! */	len --; /* we don't need \r. */    }    http_hdr->reason_phrase[len] = '\0'; /* terminate string */    hdr_sep_len = 4; /* header separator length */    ptr = strstr(http_hdr->buffer,"\r\n\r\n");    if(!ptr) {	ptr = strstr(http_hdr->buffer,"\n\n");	if(!ptr) {	    display(MSDL_ERR,"Header may be incomplete!\n");	    return -1;	}	hdr_sep_len = 2;    }    pos_hdr_sep = ptr - http_hdr->buffer;    /* points to first line after method line. */    hdr_ptr = strstr(http_hdr->buffer,"\n") + 1;      /* get all fields. they are separated by '\n' */    do {	ptr = hdr_ptr;	while(*ptr != '\r' && *ptr != '\n') ptr++;	len  = ptr - hdr_ptr;	if(len == 0) break; /* met \n\n --> end of header! */    	field = (char *)xrealloc(field,len + 1); /* +1 for '\0' */	strncpy(field,hdr_ptr,len);	field[len] = '\0';    	http_set_field(http_hdr,field);	hdr_ptr = ptr + ((*ptr == '\r') ? 2 : 1); /* points to next line */    } while(hdr_ptr < (http_hdr->buffer + pos_hdr_sep));      if(field) {	free(field);    }    if(pos_hdr_sep + hdr_sep_len < http_hdr->buffer_len) {	/* response has data within. --> store data !! or data will be lost! */	http_hdr->body = http_hdr->buffer + pos_hdr_sep + hdr_sep_len;	/* now its pointing to data in buffer. */	http_hdr->body_len = http_hdr->buffer_len - (pos_hdr_sep + hdr_sep_len);    }      http_hdr->is_parsed = 1;      return 1;}/* * return value:  0: not valid   1: valid * reason_ret ... NULL: no error *                error reason string: some error */int http_byterange_spec_valid(const char *str,char **reason_ret){    const char *p = str;    for(; *p ; p++) {	if(!isdigit(*p)) {	    *reason_ret = "http: byterange must be all digits";	    return 0;	}    }    *reason_ret = NULL;    return 1;}/*  * check if Range: string is valid * return value ... 0: not valid  1: valid * reason_ret ... NULL: no error *                error reason string: some error */int http_byterange_valid(const char *str,char **reason_ret){    char *p = NULL;    char *range_str = NULL;    int valid = 0;    char *reason = NULL;    p = strchr(str,'-');    if(p == NULL) { /* have to have exactly one '-' */	reason = "must use \'-\' to tell range";	if(reason_ret) {	    *reason_ret = reason;	}	return 0;    }    else if(p == str) { /* ( "-" npt-time ) */	valid = http_byterange_spec_valid(p + 1,reason_ret);	return valid;    }    else { /* 00.23- */	int start_str_len = p - str;	if(*(p+1) != '\0') { /* not 00.23- */	    if(!http_byterange_spec_valid(p + 1,reason_ret)) { /* check end string */		return 0;	    }	}	/* end string OK */	/* check start string */	range_str = xmalloc(start_str_len + 1);	strncpy(range_str,str,start_str_len);	range_str[start_str_len] = '\0';	valid = http_byterange_spec_valid(range_str,reason_ret);	free(range_str);		return valid;    }    return 0;}void http_set_byterange_field(struct http_header_t *http_hdr,const char *rangestr){    char *buffer = xmalloc(BUFSIZE_1K);    char *reason = NULL;    if(http_byterange_valid(rangestr,&reason)) { /* valid */	snprintf(buffer,BUFSIZE_1K - 1,"Range: bytes=%s",rangestr);	http_set_field(http_hdr,buffer);    }    else {	display(MSDL_ERR,		"invalid byterange \"%s\"\n"		"%s\n",rangestr,reason);    }        free(buffer);}/* * prepare_resuming for http * set resumeinfo->resume_start_offset & resume_req_success * * return value:     1 ... success *                  -1 ... failed */int http_prepare_resuming(struct stream_t *stream){    int ret = 0;    uint64_t filesize = 0;    /*     * find same file name     */        ret = get_filesize(stream->localfile,&filesize);    if(ret < 0) {	display(MSDL_ERR,		"http resume: no such file \"%s\", not resuming\n",stream->localfile);	goto failed;    }    if(stream->dlopts->byterange) {	free(stream->dlopts->byterange);    }        stream->dlopts->byterange = make_byterange_from_filesize(filesize);    stream->resumeinfo->resume_start_offset = filesize;        display(MSDL_DBG,	    "http resume: start pos: %lld [%llx]\n",	    filesize,filesize);    return 1;  failed:    stream->resumeinfo->resume_start_offset = 0; /* don't check request result */    stream->resumeinfo->resume_req_success = 0;    return -1;}/* * set standard fields for HTTP. * set uri * Accept: * User-Agent: * Host: * */int http_set_standard_fields(struct stream_t *stream,			     struct http_header_t *http_hdr){    struct url_t *url = NULL;    struct download_opts_t *dlopts = NULL;    char str[BUFSIZE_1K];        if(stream == NULL || http_hdr == NULL) {	return -1;    }        url = stream->url;    dlopts = stream->dlopts;    if((url == NULL) || (dlopts == NULL)) {	return -1;    }        http_set_field(http_hdr, "Accept: */*");    http_set_field(http_hdr, http_useragent);    http_add_basic_authentication(http_hdr,				  (url->username) ? url->username : stream->dlopts->username,				  (url->password) ? url->password : stream->dlopts->password);        if(dlopts->http_proxy) {	http_set_uri(http_hdr,url->url);    }    else {	http_set_uri(http_hdr,url->filepath);    }    snprintf(str,BUFSIZE_1K,"Host: %.220s:%d",stream->serverinfo->host,stream->serverinfo->port);    http_set_field(http_hdr,str);        http_set_field(http_hdr,"Connection: Close");        return 1;}int is_http_response_ok(int status_code){    return ((200 <= status_code) && (status_code <= 299)) ? 1 : 0;}/* * parse http response * return value:   1 ... success *                -1 ... parse error */int http_parse_response(struct http_ctrl_t *http_ctrl,			struct http_header_t *http_hdr){    char *content_length = NULL;    content_length = http_get_field(http_hdr, "Content-Length");    if(content_length) {	http_ctrl->content_length = atoi(content_length);    }    else {	http_ctrl->content_length = 0;    }        return 1;}/* * send GET request and perse response * return value:    1 ... success *                 -1 ... comp */int http_get(struct stream_t *stream){    struct http_header_t *http_hdr = NULL;    struct download_opts_t *dlopts = stream->dlopts;    int ret = 0;    http_hdr = new_http_header();    http_set_standard_fields(stream,http_hdr);    if(dlopts->resume_download) {	http_prepare_resuming(stream);    }        /* byte range specified */    if(dlopts->byterange) {	http_set_byterange_field(http_hdr,dlopts->byterange);    }    http_request_get(http_hdr);    http_send_header(stream,http_hdr);    free_http_header(http_hdr);        http_hdr = new_http_header();    http_recv_header(stream,http_hdr);    ret = http_process_reply(stream,http_hdr); // interpret http_hdr which just received    if(ret < 0) {	goto failed; // including complete    }    free_http_header(http_hdr);    return 1;  failed:    free_http_header(http_hdr);    return -1;}int http_process_reply(struct stream_t *stream,struct http_header_t *http_hdr){    int status_code = http_hdr->status_code;        if(status_code < 0) {	display(MSDL_ERR,"response HTTP header parse failed\n");	goto failed;    }    if(stream->dlopts->resume_download) {  /* resume case */	if(status_code == 206) { /* byterange req success */	    stream->resumeinfo->resume_req_success = 1;	}	else if (status_code == 416){	    stream->resumeinfo->resume_req_success = 0;	    stream->stream_ctrl->status = STREAMING_NO_NEED_TO_DOWNLOAD;	    goto complete;	}	else {	    stream->resumeinfo->resume_req_success = 0;	}    }    if(!is_http_response_ok(status_code)) { /* other error case */	if(status_code == 301 || status_code == 302 || status_code == 303 || status_code == 307) {	    char *newurlstr = NULL;  // HERE	    newurlstr = http_redirect_new_url(http_hdr);	    display(MSDL_NOR,"redirect to %s\n",newurlstr);	    if(newurlstr) {		stream->stream_ctrl->retry_urlstr = newurlstr;		stream->stream_ctrl->status = STREAMING_REDIRECTED;	    }	    goto failed;	}	else if(status_code == 401) {	    http_print_authenticate_required(http_hdr);	    goto failed;	}	else {	    display(MSDL_ERR,"%d %s\n",http_hdr->status_code,http_hdr->reason_phrase);	    goto failed;	}    }    return 1;  complete:  failed:    return -1;}/* * starts mmst streaming(actually this is downlaoding). *  *    return value :   negative or 0  ... error *                                 1  ... success */int http_streaming_start(struct stream_t *stream){    struct stream_ctrl_t *stream_ctrl = stream->stream_ctrl;    struct http_ctrl_t *http_ctrl = stream_ctrl->http_ctrl;    struct url_t *url = stream->url;    int sock = 0;    int ret = 0;      stream_ctrl->status = STREAMING_HANDSHAKING;        set_serverinfo_by_proxy_string(stream->serverinfo,url->hostname,url->port,				   stream->dlopts->http_proxy,				   HTTP_PORT,HTTP_PROXY_PORT);    sock = server_connect(stream->serverinfo->connect_host,stream->serverinfo->connect_port);    if(sock < 0) {	goto failed;    }    stream->netsock->sock = sock;    ret = http_get(stream);    if(ret < 0) {	if(stream_ctrl->status == STREAMING_NO_NEED_TO_DOWNLOAD) {	    goto complete;	}	else {	    goto failed;	}    }        /* set file size to download */    stream_ctrl->file_size = http_ctrl->content_length;    stream_ctrl->status = STREAMING_DOWNLOADING;    stream_ctrl->protocol = HTTP;    return 1;    failed:  complete:    return 0;}/* * read http (stream). filles buffer, and buffer size is 'size'  * *        read cached data from stream->netsock->buffer *        check for to see if network access is necessary *        get chunk(media packet) from network. * *  return value: bytes written to buffer. -1 if error. */int http_streaming_read(struct stream_t *stream,			uint8_t *buffer, size_t buffer_size){    struct http_ctrl_t *http_ctrl = stream->stream_ctrl->http_ctrl;    int ret;      if(http_ctrl->content_length) {	int rest = http_ctrl->content_length - http_ctrl->down_length;    	if(rest == 0) { /* finished */	    ret = 0;	}	else { /* needs to get from network or buffer */	    int recv_length = (rest > buffer_size) ? buffer_size : rest; /* smaller */	    ret = recv_data(stream,buffer,recv_length);	    http_ctrl->down_length += ret;	}    }    else {	/*	  recv() returns 0 if we call recv on	  already shutdown()ed socket	*/	ret = recv_data(stream,buffer,buffer_size);    }        if(ret == 0) {	stream->stream_ctrl->status = STREAMING_FINISHED;    }    return ret;}struct http_ctrl_t *new_http_ctrl_t(void){    struct http_ctrl_t *ctrl = xmalloc(sizeof(struct http_ctrl_t));    return ctrl;}void free_http_ctrl_t(struct http_ctrl_t *ctrl){    free(ctrl);}struct stream_t *http_streaming_init(){    struct stream_t *stream = streaming_init_common();    stream->stream_ctrl->http_ctrl = new_http_ctrl_t();      stream->start = http_streaming_start;    stream->read  = http_streaming_read;    stream->close = http_streaming_close;      return stream;}void http_streaming_close(struct stream_t *stream){    if(stream->netsock->sock > 0) {	close(stream->netsock->sock);    }        free_http_ctrl_t(stream->stream_ctrl->http_ctrl);    streaming_close_common(stream);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -