📄 http.c
字号:
/*********************************************************************** * http.c: for downloading via http (Hyper Text Transfer Protocol) *********************************************************************** * Copyright (C) 2007 metro <me_t_ro@yahoo.com> * * This file is part of msdl, media stream downloader * * This file is based on http implementation of mplayer. * mplayer's http implementation was very nice. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. * ***********************************************************************/ /* * Copyright notice of MPlayer project * which some part of msdl is based on. * (from MPlayer-1.0rc2/stream/http.c) *//* * HTTP Helper * by Bertrand Baudet <bertrand_baudet@yahoo.com> * (C) 2001, MPlayer team. */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include "msdl.h"#include "msdllib.h"#include "display.h"#include "network.h"#include "http.h"const char http_useragent[] = "User-Agent: MSDL";/* * new_http_header : create new HTTP header */struct http_header_t *new_http_header(void){ struct http_header_t *hdr; hdr = (struct http_header_t *)xmalloc(sizeof(struct http_header_t)); return hdr;}/* * free HTTP header */void free_http_header(struct http_header_t *h){ struct http_field_t *field, *prev; if(h == NULL) return; /* http_hdr is not malloc()ed yet. */ if(h->protocol) free(h->protocol); if(h->method) free(h->method); if(h->uri) free(h->uri); if(h->reason_phrase) free(h->reason_phrase); if(h->field_search) free(h->field_search); if(h->buffer) free(h->buffer); field = h->first_field; for(field = h->first_field; field ; ) { if(field->field_name) free(field->field_name); prev = field; field = field->next; free(prev); } free(h);}/* * returns first filed with 'field name'. * http_get_next_field will get next field with 'filed_name' */char *http_get_field(struct http_header_t *http_hdr, const char *field_name){ if(!http_hdr || !field_name) return NULL; http_hdr->field_search_pos = http_hdr->first_field; http_hdr->field_search = (char *)xrealloc(http_hdr->field_search, strlen(field_name) + 1); /* copy field name first */ strcpy(http_hdr->field_search, field_name); /* get first field value with this field_name. */ return http_get_next_field(http_hdr);}/* * return field string after "http_hdr->field_search". * NULL if not found. */char *http_get_next_field(struct http_header_t *http_hdr){ char *ptr; struct http_field_t *field; if(!http_hdr) return NULL; field = http_hdr->field_search_pos; while(field) { ptr = strstr(field->field_name,":"); if(ptr == NULL) return NULL; /* the header is not valid... */ if(!strncasecmp(field->field_name,http_hdr->field_search, ptr - field->field_name)) { /* found field!!!! */ ptr++; /* skip ':' */ while(*ptr == ' ') ptr++; /* skip %20 */ http_hdr->field_search_pos = field->next; /* points to next field */ return ptr; /* return the string without filed name!! */ } field = field->next; } return NULL; /* NOT FOUND */}/* * http_set_field : make new field and attach it to last_field->next. */void http_set_field(struct http_header_t *http_hdr, const char *field_name){ struct http_field_t *new_field; if(http_hdr == NULL || field_name == NULL) return; new_field = xmalloc(sizeof(struct http_field_t)); new_field->next = NULL; new_field->field_name = xmalloc(strlen(field_name) + 1); strcpy(new_field->field_name, field_name); if(http_hdr->last_field == NULL) { http_hdr->first_field = new_field; /* this was first filed!! */ } else { http_hdr->last_field->next = new_field; /* attach to last */ } http_hdr->last_field = new_field; http_hdr->field_nb++;}/* * send 'http_hdr' to network. it has to be built by build_request funcs * return value: what xsend returned */int http_send_header(struct stream_t *stream, struct http_header_t *http_hdr){ int ret; /* dbg */ display(MSDL_DBG,"SEND http header ------------>\n" "%s\n--(%d bytes)---------------<\n", http_hdr->buffer,(int)http_hdr->buffer_len); ret = xsend(stream->netsock->sock,http_hdr->buffer,http_hdr->buffer_len); return ret;}/* * receive rtsp header and set rtsp_ctrl * return status code : success * -1 : failure */int http_recv_header(struct stream_t *stream,struct http_header_t *http_hdr){ int ret = 0; ret = http_recv_header_get(stream,http_hdr); if(ret < 0) { return -1; } ret = http_parse_response(stream->stream_ctrl->http_ctrl,http_hdr); if(ret < 0) { return -1; } return http_hdr->status_code;}/* * receive http message from stream->sock. * header is guraranteed to be complete after this function, * body should not be complete. * so search Content-length and get all the body later. * return status code : success * -1 : failure */int http_recv_header_get(struct stream_t *stream, struct http_header_t *http_hdr){ int ret = 0,i = 0,total = 0; http_hdr->buffer_len = 0; http_hdr->buffer = NULL; total = 0; do { /* get http reply */ http_hdr->buffer_len += BUFSIZE_1K; http_hdr->buffer = (char *)xrealloc(http_hdr->buffer, http_hdr->buffer_len + 1); i = recv_data(stream,http_hdr->buffer + total,http_hdr->buffer_len - total); if(i <= 0) { display(MSDL_ERR,"http_recv_header error: recv_data() returned %d\n",i); goto failed; } total += i; http_hdr->buffer[total] = '\0'; } while(!http_is_entire_header(http_hdr)); /* http_hdr->buffer_size is length in buffer, not the malloc()ed size. */ http_hdr->buffer_len = total; http_hdr->buffer[total] = '\0'; /* * actually 2 protocols uses http, so * don't mess with stream_ctrl->*_ctrl */ ret = http_response_parse(http_hdr); if(ret < 0) { display(MSDL_ERR,"response HTTP header parse failed\n"); goto failed; } /* push body back !!! */ if(http_hdr->body_len) { stream_data_push_back(stream,http_hdr->body,http_hdr->body_len); } /* http_hdr->buffer *ONLY* contains header, no body follows */ memset(http_hdr->body,0,http_hdr->body_len); /* dbg */ display(MSDL_DBG,"Resopnse header===========\n" "%s\n" "--(%d bytes)-------------------\n", http_hdr->buffer,(int)http_hdr->buffer_len); /* success */ return http_hdr->status_code; failed: if(http_hdr->buffer) free(http_hdr->buffer); http_hdr->buffer = NULL; return -1;}/* table for base 64 */const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";/* * base64_encode : base 64 encode. * * enc: string to base64 encode. * enclen: length of enc * out: output base64 encoded result. * outmax: length of out (buffer length) * * copied from Mplayer/stream/http.c */int base64_encode(const void *enc,int enclen,char *out,int outsize){ unsigned char *encbuf; int outlen; unsigned int bits; unsigned int shift; encbuf = (unsigned char*)enc; outlen = 0; bits = 0; shift = 0; outsize &= ~3; while( outlen < outsize ) { if( enclen>0 ) { /* Shift in byte */ bits <<= 8; bits |= *encbuf; shift += 8; /* Next byte */ encbuf++; enclen--; } else if( shift>0 ) { /* Pad last bits to 6 bits - will end next loop */ bits <<= 6 - shift; shift = 6; } else { /* As per RFC 2045, section 6.8, pad output as necessary: 0 to 2 '=' chars. */ while( outlen & 3 ){ *out++ = '='; outlen++; } return outlen; } /* Encode 6 bit segments */ while( shift>=6 ) { shift -= 6; *out = b64[ (bits >> shift) & 0x3F ]; out++; outlen++; } } /* output overflow */ return -1;}/* * add BASIC authentication string to header. * return value: 0 */int http_add_basic_authentication(struct http_header_t *http_hdr, const char *username, const char *password){ char *auth = NULL, *user_pass = NULL, *b64_user_pass = NULL; int encoded_len ,pass_len = 0, out_len; int res = -1; /* username cannot be NULL. */ if(http_hdr == NULL || username == NULL) return -1; if(password != NULL) { pass_len = strlen(password); } user_pass = (char *)xmalloc(strlen(username) + pass_len + 2); sprintf(user_pass, "%s:%s",username,(password == NULL) ? "" : password); /* base64 encode with at least 33% more data than the original size. */ encoded_len = strlen(user_pass) * 2; b64_user_pass = (char *)xmalloc(encoded_len); out_len = base64_encode(user_pass,strlen(user_pass), b64_user_pass,encoded_len); if(out_len < 0) { fatal_error("Base64 output overflow!!\n"); } b64_user_pass[out_len] = '\0'; auth = xmalloc(encoded_len + 22); sprintf(auth,"Authorization: Basic %s",b64_user_pass); http_set_field(http_hdr,auth); res = 0; free(user_pass); free(b64_user_pass); free(auth); return res;}int http_print_authenticate_required(struct http_header_t *http_hdr){ char *auth = NULL; auth = http_get_field(http_hdr,"WWW-Authenticate"); if(auth) { /* found!!! */ char *auth_space = NULL; auth_space = strstr(auth,"realm="); if(auth_space != NULL) auth_space += 6; display(MSDL_NOR,"authentication required %s!!\n",auth_space); } else { /* not found */ display(MSDL_NOR,"authentication required!!\n"); } return 0;}char *http_redirect_new_url(struct http_header_t *http_hdr){ char *loc = NULL; loc = http_get_field(http_hdr,"Location"); if(loc) { return strdup(loc); } else { display(MSDL_ERR,"Location: field does not exist, maybe invalid redirection\n"); return NULL; }}void http_set_uri(struct http_header_t *http_hdr,const char *uri){ if(http_hdr == NULL || uri == NULL) return; http_hdr->uri = strdup(uri);}void http_set_method(struct http_header_t *http_hdr, const char *method){ if(http_hdr == NULL || method == NULL) return; http_hdr->method = strdup(method);}char *http_request_get(struct http_header_t *http_hdr){ http_set_method(http_hdr,"GET"); return (http_build_request(http_hdr));}char *http_request_head(struct http_header_t *http_hdr){ http_set_method(http_hdr,"HEAD"); return (http_build_request(http_hdr));}char *http_request_post(struct http_header_t *http_hdr){ http_set_method(http_hdr,"POST"); return (http_build_request(http_hdr));}/* * make complete http_header_t. * the request string goes to http_hdr->buffer * return value: http_hdr->buffer ( built request ) */char *http_build_request(struct http_header_t *http_hdr){ char *ptr = NULL; int len; struct http_field_t *field; if(http_hdr->uri == NULL) { http_set_uri(http_hdr,"/"); } /* * culculate the request length. */ /* method line */ len = strlen(http_hdr->method) + strlen(http_hdr->uri) + 12; /* fields */ field = http_hdr->first_field; while(field) { len += strlen(field->field_name) + 2; field = field->next; } /* CRLF */ len += 2; /* request body */ if(http_hdr->body) { len += http_hdr->body_len; } /* * free the buffer which used 4 last request. */ if(http_hdr->buffer) { free(http_hdr->buffer); http_hdr->buffer = NULL; } http_hdr->buffer_len = len; http_hdr->buffer = xmalloc(len + 1); /* 1 for '\0' */ /* * build the request */ ptr = http_hdr->buffer; /* method line */ ptr += sprintf(ptr,"%s %s HTTP/1.%d\r\n", http_hdr->method,http_hdr->uri,http_hdr->http_minor_version); field = http_hdr->first_field; /* fields */ while(field != NULL) { ptr += sprintf(ptr,"%s\r\n",field->field_name); field = field->next; } ptr += sprintf(ptr,"\r\n"); if(http_hdr->body != NULL) { memcpy(ptr,http_hdr->body,http_hdr->body_len); } return http_hdr->buffer;}/* * concatinate http_hdr->buffer and response. * return value is new buffer size. (not counting NULL char) */int http_response_append(struct http_header_t *http_hdr, char *response,int len){ if(http_hdr == NULL || response == NULL || len < 0) return 0; /* *** caution *** */ /* http_hdr->buffer_size does NOT include '\0' at the end. */ /* if(http_hdr->buffer_size + len + 1 > HDR_SIZE_MAX) { // +1 for '\0' display(MSDL_ERR,"%d maybe recv failed\n",http_hdr->buffer_size); return -1; } */ http_hdr->buffer = (char *)xrealloc(http_hdr->buffer, http_hdr->buffer_len + len + 1); /* concat buffer. */ memcpy(http_hdr->buffer + http_hdr->buffer_len, response, len); http_hdr->buffer_len += len; http_hdr->buffer[http_hdr->buffer_len] = '\0'; /* terminate. */ return http_hdr->buffer_len;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -