📄 http_client.c
字号:
{ begin_path+=begin_hostport; } else return begin_path; } else { out->hostport.IPv4address.sin_port=0; out->hostport.IPv4address.sin_addr.s_addr=0; out->hostport.text.size=0; out->hostport.text.buff=0; begin_path=begin_hostport; } begin_fragment=parse_uric(&in[begin_path],max-begin_path,&out->pathquery); if ( (out->pathquery.size) && (out->pathquery.buff[0]=='/')) { out->path_type=ABS_PATH; } begin_fragment+=begin_path; if ( (begin_fragment<max) && ( in[begin_fragment]=='#')) { begin_fragment++; parse_uric(&in[begin_fragment],max-begin_fragment,&out->fragment); } else{ out->fragment.buff=NULL; out->fragment.size=0; } return HTTP_SUCCESS;}//*************************************************************************//* Name: concat_socket_buffers//*//* Description: concats a list of socket buffers (used to read data of //* unknown size) into one buffer (out)//* size of out is assumed to be large enough to hold the data//* the caller is responsible for maintaining this//*//* In: socket_buffer * head (head of the list of buffers)//*//* Out: the concatenated socket_buffers are copied into out//*//* Return Codes: None//* Error Codes: None //*************************************************************************void concat_socket_buffers(socket_buffer * head, char * out){ socket_buffer *finger=head; finger=head; while (finger) { memcpy(out,finger->buff,finger->size); out+=finger->size; finger=finger->next; } }//*************************************************************************//* Name: free_socket_buffers//*//* Description: frees the space allocated in a list of socket_buffers//* //* In: socket_buffer * head (head of list of buffers to free)//*//* Out: None//* //* Return Codes: None//* Error Codes: None //*************************************************************************void free_socket_buffers(socket_buffer * head){ socket_buffer * temp=NULL; socket_buffer * finger=NULL; if (head) { finger=head->next; while (finger) { temp=finger->next; free(finger); finger=temp; } }}//*************************************************************************//* Name: getHeaders//*//* Description: Reads the header section of a http message (used in //* transfer http) //* returns a list of socket buffers and the content length//* if a "CONTENT-LENGTH:" header is found. //* reads until a line : "\r\n"//* //* In: socket_buffer * head (head of list of buffers)//* int fd (socket)//* int * ContentLength (space to place content length)//* socket_buffer **tail (space to place end of socket buffer //* list)//* int * timeout (timeout for operation) (returns time //* remaining after operation)//* //* Out: total size of headers (memory contained in list of socket //* buffers) memory in socket buffer list must be freed by//* caller//* //* Return Codes: >=0 SUCCESS , time of operation is subtracted//* from timeout//* Error Codes: UPNP_E_OUTOF_MEMORY (memory failure)//* UPNP_E_SOCKET_READ (error reading from socket , including //* timeout) //*************************************************************************int getHeaders(int fd, int *ContentLength, socket_buffer* head, socket_buffer **tail, int *timeout){ socket_buffer *current=head; socket_buffer *prev=NULL; int total_size=0; char * invalidchar; char * pat="CONTENT-LENGTH:"; char * pat2="TRANSFER-ENCODING: CHUNKED"; char * pat3="CONTENT"; int pat_len=strlen(pat); int pat2_len=strlen(pat2); int pat3_len=strlen(pat3); head->next=NULL; (*ContentLength)=-3; (*tail)=NULL; current->size=0; while ( (current->size=readLine(fd,current->buff,SOCKET_BUFFER_SIZE,timeout)) >0) { total_size+=current->size; //check for continuation of header over multiple lines //this is a continuation if and only if the previous line was //properly ended AND this line begins with a space or tab //in this case the CRLF is removed from the previous line if ( (current->buff[0]==' ') || (current->buff[0]==TAB)) { if (prev) { if ( (prev->size>=2) && (prev->buff[prev->size-1]=='\n') && (prev->buff[prev->size-2]=='\r')) prev->size-=2; DBGONLY(UpnpPrintf(UPNP_INFO,API,__FILE__,__LINE__,"REMOVED CRLF FROM MULTILINE HEADER")); total_size-=2; } } //make sure we only check these values after new lines //just in case the previous value was so large that the CRLF was //not detected before the SOCKET_BUFFER was filled if ( (!prev) || ( (prev) && (prev->size>=2) && (prev->buff[prev->size-1]=='\n') && (prev->buff[prev->size-2]=='\r'))) { if (!strncasecmp(pat3,current->buff,pat3_len)) { DBGONLY(UpnpPrintf(UPNP_INFO,API,__FILE__,__LINE__,"EXPECTING CONTENT")); if ((*ContentLength)==-3) (*ContentLength)=-2; } if (!strncasecmp(pat2,current->buff,pat2_len)) { DBGONLY(UpnpPrintf(UPNP_INFO,API,__FILE__,__LINE__,"CONTENT IS CHUNKED")); //transfer-encoding:chunked (*ContentLength)=-1; } //if it is "Content-Length:" then get the length if (!strncasecmp(pat,current->buff,pat_len)) { //if transfer-encoding chunked is already found then //ignore content length header if ((*ContentLength)!=-1) { DBGONLY(UpnpPrintf(UPNP_INFO,API,__FILE__,__LINE__,"CONTENT LENGTH FOUND")); (*ContentLength)=strtol(current->buff+pat_len ,&invalidchar,10); if (invalidchar==current->buff+pat_len) { (*ContentLength)=0; DBGONLY(UpnpPrintf(UPNP_CRITICAL,API,__FILE__,__LINE__,"Trouble getting Content Length")); } } } //last \r\n if ( ( current->size==2) && (current->buff[0]=='\r')) break; } current->next= (socket_buffer *) malloc(sizeof(socket_buffer)); if (!current->next) { free_socket_buffers(head); return UPNP_E_OUTOF_MEMORY; } prev=current; current=current->next; current->next=NULL; current->size=0; } if (current->size<0) { (*ContentLength)=0; free_socket_buffers(head); DBGONLY(UpnpPrintf(UPNP_CRITICAL,API,__FILE__,__LINE__,"ERROR READING SOCKET")); return UPNP_E_SOCKET_READ; } if ((*ContentLength)==-3) (*ContentLength)=0; (*tail)=current; return total_size;}//*************************************************************************//* Name: write_timeout//*//* Description: writes bytes to a socket with a timeout//* //* In: int fd (socket)//* void *buf (buffer to be sent)//* size_t count (number of bytes to be sent)//* int *timeout (timeout for operation)//*//* Out: # of bytes sent. timeout is updated, time of operation//* is subtracted from it.//* //* Return Codes: >=0 success//* Error Codes: -1 Timeout, <=0 Error return code of write()//*************************************************************************ssize_t write_timeout(int fd, void *buf, size_t count, int *timeout){ fd_set wset; struct timeval tv; time_t current_time; int writeable; time_t new_time; if ((*timeout)<=0) { return -1; //TIMEOUT } FD_ZERO(&wset); FD_SET(fd,&wset); tv.tv_sec=(*timeout); tv.tv_usec = 0 ; time(¤t_time); //get current time writeable=select(fd+1,NULL, &wset,NULL,&tv); if (writeable>0) { time(&new_time); (*timeout)-=(new_time-current_time); return send(fd,buf,count,MSG_NOSIGNAL); } else { (*timeout)=0; return -1; //TIMEOUT }}//*************************************************************************//* Name: read_timeout//*//* Description: read bytes to a socket with a timeout//* //* In: int fd (socket)//* void *buf (buffer to store data)//* size_t count (number of bytes to be read t)//* int *timeout (timeout for operation)//*//* Out: # of bytes read. timeout is updated, time of operation//* is subtracted from it.//* //* Return Codes: >=0 success//* Error Codes: -1 Timeout, <=0 Error return code of read()//*************************************************************************ssize_t read_timeout(int fd,void *buf, size_t count, int * timeout){ fd_set rset; struct timeval tv; time_t current_time; int readable; time_t new_time; if ((*timeout)<=0) { DBGONLY(UpnpPrintf(UPNP_CRITICAL,API,__FILE__,__LINE__,"TIMEOUT ON READ")); return -1; //TIMEOUT } FD_ZERO(&rset); FD_SET(fd, &rset); tv.tv_sec=(*timeout); tv.tv_usec = 0 ; time(¤t_time); //get current time readable=select(fd+1,&rset, NULL,NULL,&tv); if (readable>0) { time(&new_time); (*timeout)-=(new_time-current_time); return recv(fd,buf,count,0); } else { (*timeout)=0; DBGONLY(UpnpPrintf(UPNP_CRITICAL,API,__FILE__,__LINE__,"TIMEOUT ON READ")); return -1; //TIMEOUT } }//*************************************************************************//* Name: readLine//*//* Description: reads characters from a socket until a newline is seen//* appends a null to the output//* In: int fd (socket)//* char *out(buffer to store data)//* int max (bytes in buffer)//* int *timeout (timeout for operation)//*//* Out: # of bytes read. timeout is updated, time of operation//* is subtracted from it.//* //* Return Codes: >=0 success//* Error Codes: -1 Error reading from socket//*************************************************************************ssize_t readLine(int fd, char *out, int max, int *timeout){ char c; ssize_t count=0,rc=0; while ( (count<(max-1)) && ( (rc=read_timeout(fd,&c,1,timeout))==1) ) { *out++=c; count++; if (c=='\n') break; } if (rc<0)//error { return -1; } *out=0; return count;}//*************************************************************************//* Name: read_http_response//*//* Description: reads the http response from a socket, with a timeout//* returns a dynamically allocated string (null terminated)//* must be freed by caller. //* //* In: int fd (socket)//* char **out (memory allocated by function and pointer //* stored here)//* int timeout (timeout for operation)//*//* Out: http response is read and returned in null terminated //* string, (*out). http headers and content are read//* ONLY WORKS if "CONTENT LENGTH:" header is present.//* otherwise content is NOT returned.//* //* Return Codes: HTTP_SUCCESS on success//* Error Codes: UPNP_E_OUTOF_MEMORY, memory error//* UPNP_E_SOCKET_READ, socket read error, including//* timeout//*************************************************************************int read_http_response(int fd, char **out, int timeout){ socket_buffer head; socket_buffer *current=&head; socket_buffer * header_tail=NULL; int total_size=0; int contentLength=0; int Timeout=timeout; int done =0; int chunk_size=-1; socket_buffer chunkSizebuff; char *invalidchar; int nextToRead=0; head.next=NULL; if ( ( (total_size=getHeaders(fd,&contentLength,&head,&header_tail,&Timeout)) >0)) { current=header_tail; if (contentLength==0) { DBGONLY(UpnpPrintf(UPNP_INFO,API,__FILE__,__LINE__,"NO CONTENT EXPECTED")); done=1; } while (!done) { if ( (contentLength==-1) && ( chunk_size<=0)) { DBGONLY(UpnpPrintf(UPNP_INFO,API,__FILE__,__LINE__,"GETTING NEXT CHUNK SIZE")); //gobble up crlf if (chunk_size==0) chunkSizebuff.size= readLine(fd,chunkSizebuff.buff,SOCKET_BUFFER_SIZE,&Timeout); if ((chunkSizebuff.size=readLine(fd,chunkSizebuff.buff,SOCKET_BUFFER_SIZE,&Timeout)) >0) { chunk_size=strtol(chunkSizebuff.buff ,&invalidchar,16); DBGONLY(UpnpPrintf(UPNP_INFO,API,__FILE__,__LINE__,"chunk size: %d\n",chunk_size);) if (invalidchar==chunkSizebuff.buff) chunk_size=0; } else chunk_size=0; if (chunk_size==0) { done=1; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -