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

📄 http_resp.c

📁 完整实现http协议源代码(WINDOWS或LINUX平台均可移植使用),我在VC++上(不调用WINDOWS的HTTP的API)可实现XML文件下载等.
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * http_resp.c -- routines for reading http_responses * Created: Christopher Blizzard <blizzard@appliedtheory.com> 9-Aug-1998 * * Copyright (C) 1998 Free Software Foundation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include <stdlib.h>#include <string.h>#include <ctype.h>#include <unistd.h>#include "http_resp.h"#include "http_global.h"typedef enum header_state_tag{  reading_header = 0,  reading_value,  reading_sep,  reading_eol} header_state;static intstring_is_number(char *a_string);static intread_chunk(http_trans_conn *a_conn);static intread_body_chunked(http_resp *a_resp,		  http_req *a_req,		  http_trans_conn *a_conn);static intread_body_content_length(http_resp *a_resp,			 http_req *a_req,			 http_trans_conn *a_conn);static intread_body_standard(http_resp *a_resp,		   http_req *a_req,		   http_trans_conn *a_conn);http_resp *http_resp_new(void){  http_resp *l_return = NULL;  l_return = (http_resp *)malloc(sizeof(http_resp));  memset(l_return, 0, sizeof(http_resp));  l_return->headers = http_hdr_list_new();  return l_return;}voidhttp_resp_destroy(http_resp *a_resp){  if (!a_resp)    return;  if (a_resp->reason_phrase)    free(a_resp->reason_phrase);  if (a_resp->headers)    http_hdr_list_destroy(a_resp->headers);  if (a_resp->body)    free(a_resp->body);  free(a_resp);  return;}inthttp_resp_read_headers(http_resp *a_resp, http_trans_conn *a_conn){  char          *l_start_body = NULL;  int            l_rv = 0;  int            l_done = 0;  int            l_return = HTTP_TRANS_DONE;  char          *l_start_header = NULL;  int            l_header_len = 0;  char          *l_last_header = NULL;  int            l_last_header_len = 0;  char          *l_start_value = NULL;  int            l_value_len = 0;  char          *l_cur_ptr = NULL;  char          *l_ptr = NULL;  header_state   l_state = reading_header;  /* check to see if we need to jump in somewhere */  if (a_conn->sync == HTTP_TRANS_ASYNC)    {      if (a_resp->header_state == http_resp_reading_header)	goto http_resp_reading_header_jump;    }  /* start reading headers */  do    {      a_resp->header_state = http_resp_reading_header;    http_resp_reading_header_jump:      /* read in the buffer */      l_rv = http_trans_read_into_buf(a_conn);      /* check for an error */      if (l_rv == HTTP_TRANS_ERR)	{	  a_conn->errstr = "Failed to read http response line";	  l_return = HTTP_TRANS_ERR;	  goto ec;	}      /* check to see if the end of headers string is in the buffer */      l_start_body = http_trans_buf_has_patt(a_conn->io_buf,					     a_conn->io_buf_alloc,					     "\r\n\r\n", 4);      if (l_start_body != NULL)	l_done = 1;      if ((l_done == 0) && (a_conn->sync == HTTP_TRANS_ASYNC) && (l_rv == HTTP_TRANS_NOT_DONE))	return HTTP_TRANS_NOT_DONE;      /* yes, that !l_done is ther because in the case of a 100         continue we well get back up to this loop without doing a         successful read. */      if ((!l_done) && (l_rv == HTTP_TRANS_DONE) && (a_conn->last_read == 0))	{	  a_conn->errstr = "Short read while reading http response headers";	  return HTTP_TRANS_ERR;	}    } while (l_done == 0);  /* parse out the response header */  /* check to make sure that there's enough that came back */  if ((a_conn->io_buf_alloc) < 14)    {      a_conn->errstr = "The http response line was too short.";      l_return = HTTP_TRANS_ERR;      goto ec;    }  l_ptr = a_conn->io_buf;  /* can you say PARANOID?  I thought you could. */  if (strncmp(l_ptr, "HTTP", 4) != 0)    {      a_conn->errstr = "The http response line did not begin with \"HTTP\"";      l_return = HTTP_TRANS_ERR;      goto ec;    }  if ((isdigit(l_ptr[5]) == 0) || /* http ver */      (l_ptr[6] != '.') ||      (isdigit(l_ptr[7]) == 0) ||      (l_ptr[8] != ' ') ||        /* space */      (isdigit(l_ptr[9]) == 0) || /* code */      (isdigit(l_ptr[10]) == 0) ||      (isdigit(l_ptr[11]) == 0) ||      (l_ptr[12] != ' '))          /* space */    {      a_conn->errstr = "Error parsing http response line";      l_return = HTTP_TRANS_ERR;      goto ec;    }  /* convert char into int */  a_resp->http_ver = (l_ptr[5] - 0x30);  a_resp->http_ver += ((l_ptr[7] - 0x30) / 10.0);  /* convert the response into an int */  a_resp->status_code = ((l_ptr[9] - 0x30)*100);  a_resp->status_code += ((l_ptr[10] - 0x30)*10);  a_resp->status_code += (l_ptr[11] - 0x30);  /* get the length of the reason_phrase */  l_cur_ptr = &l_ptr[13];  /* you can't overrun this because you already know that     there has to be a '\r' above from searching from the     end of the headers */  while (*l_cur_ptr != '\r')    l_cur_ptr++;  /* make sure to free the buffer if it's already allocated */  if (a_resp->reason_phrase) {    free(a_resp->reason_phrase);    a_resp->reason_phrase = NULL;  }  /* allocate space for the reason phrase */  a_resp->reason_phrase =    malloc((l_cur_ptr - (&l_ptr[13])) + 1);  memset(a_resp->reason_phrase, 0,	 ((l_cur_ptr - (&l_ptr[13])) + 1));  memcpy(a_resp->reason_phrase,	 &l_ptr[13], (l_cur_ptr - (&l_ptr[13])));  /* see if there are any headers.  If there aren't any headers     then the end of the reason phrase is the same as the start body     as above.  If that's the case then skip reading any headers. */  if (l_cur_ptr == l_start_body)    l_done = 1;  else    l_done = 0;  /* make sure that it's not a continue. */  if (a_resp->status_code == 100)    {      /* look for the next \r\n\r\n and cut it off */      char *l_end_continue = http_trans_buf_has_patt(a_conn->io_buf,						     a_conn->io_buf_alloc,						     "\r\n\r\n", 4);      if (!l_end_continue)	return HTTP_TRANS_ERR;      http_trans_buf_clip(a_conn, l_end_continue + 4);      l_start_body = NULL;      a_resp->status_code = 0;      l_done = 0;      if (a_conn->sync == HTTP_TRANS_ASYNC)	return HTTP_TRANS_NOT_DONE;      else	goto http_resp_reading_header_jump;    }  /* set the start past the end of the reason phrase,     checking if there's a CRLF after it. */  while ((*l_cur_ptr == '\r') ||	 (*l_cur_ptr == '\n'))    l_cur_ptr++;  /* start parsing out the headers */  /* start at the beginning */  l_start_header = l_cur_ptr;  while (l_done == 0)    {      /* check to see if we're at the end of the	 headers as determined above by the _patt() call */      if (l_cur_ptr == (l_start_body + 1))	break;      /* reading the header name */      if (l_state == reading_header)	{	  /* check to see if there's leading whitespace.	     If that's the case then it needs to be combined	     from the previous header */	  if (l_header_len == 0)	    {	      if ((*l_cur_ptr == ' ') || (*l_cur_ptr == '\t'))		{		  /* bomb if it's the first header.  That's not valid */		  if ((l_last_header == NULL) || (l_last_header_len == 0))		    {		      a_conn->errstr = "The first http response header began with whitespace";		      l_return = HTTP_TRANS_ERR;		      goto ec;		    }		  l_cur_ptr++;		  /* set it reading sep.  sep will eat all of the write space */		  l_state = reading_sep;		  continue;		}	    }	  if (*l_cur_ptr == ':')	    {	      /* make sure that there's some header there */	      if (l_header_len == 0)		{		  a_conn->errstr = "An http response header was zero length";		  l_return = HTTP_TRANS_ERR;		  goto ec;		}	      /* start reading the seperator */	      l_state = reading_sep;	      l_cur_ptr++;	    }	  /* make sure there's a seperator in	     there somewhere */	  else if (*l_cur_ptr == '\r')	    {	      a_conn->errstr = "Failed to find seperator in http response headers";	      l_return = HTTP_TRANS_ERR;	      goto ec;	    }	  else	    {	      l_cur_ptr++;	      l_header_len++;	    }	}      /* read the seperator */      else if(l_state == reading_sep)	{	  /* walk until you get a non-whitespace character */	  if ((*l_cur_ptr == ' ') || (*l_cur_ptr == '\t'))	    l_cur_ptr++;	  else	    {	      l_state = reading_value;	      l_start_value = l_cur_ptr;	      l_value_len = 0;	    }	}      /* read the value */      else if(l_state == reading_value)	{	  /* check to see if we've reached the end of the	     value */	  if ((*l_cur_ptr == '\r') || (*l_cur_ptr == '\n'))	    {	      /* check to see if this is a continuation of the last		 header. If the header len is 0 and we've gotten to		 this point then that's the case */	      if (l_header_len == 0)		{		  http_hdr_set_value_no_nts(a_resp->headers,					    l_last_header,					    l_last_header_len,					    l_start_value,					    l_value_len);		}	      else		{		  http_hdr_set_value_no_nts(a_resp->headers,					    l_start_header,					    l_header_len,					    l_start_value,					    l_value_len);		  		  /* set the last header and the length so that a new line		     that starts with spaces can figure out what header it		     applies to */		  l_last_header = l_start_header;		  l_last_header_len = l_header_len;		}	      /* start eating the end of line */	      l_state = reading_eol;	    }	  else	    {	      l_cur_ptr++;	      l_value_len++;	    }	}      /* read the eof */      else if(l_state == reading_eol)	{	  /* eat the eol */	  if ((*l_cur_ptr == '\r') || (*l_cur_ptr == '\n'))	    l_cur_ptr++; 	  else	    {	      /* start reading a new header again. */	      l_state = reading_header;	      l_start_header = l_cur_ptr;	      l_header_len = 0;	    }	}      /* what state is this? */      else	{	  a_conn->errstr = "Unknown state while reading http response headers";	  l_return = HTTP_TRANS_ERR;	  goto ec;

⌨️ 快捷键说明

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