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

📄 c_http.c

📁 C编写的用来实现search engine的推荐功能
💻 C
📖 第 1 页 / 共 2 页
字号:
/**
 * 以各种方式调用HTTP请求
 * Xu Lubing
 * May 23, 2003
 */

#include "c_http.h"
#include "urlbreaker.h"
#include "NonbSocket2.h"
#include "base64.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifdef WIN32
#define strncasecmp _strnicmp
#endif

#define DEFAULT_PORT 80

#define DEFAULT_TIMEOUT 60

#define BLANK_LINE   ""
#define CONTENT_TYPE "Content-Type: application/x-www-form-urlencoded"
#define USER_AGENT   "User-Agent: lubing c_HTTP agent"
#define BASIC_AUTH   "Authorization: Basic"

#define NO_HEADER "[None]"

/* 错误代码定义 */
typedef enum {
	NO_ERROR = 0,
	UNSUPPORTED_METHOD,
	NO_URL,
	NO_BUFFER,
	BADURL,
	CONNECTION_ERROR,
	COMM_ERROR,
	UNKNOWN_RESPONSE,
	BAD_REQUEST,
	NO_BODY,
	OTHER_ERROR
} ERROR_CODE;

/* 错误原因定义 */
static const char* ERROR_MESSAGE[] = {
	NULL,
	"目前还不支持该请求方法",
	"给定的URL为NULL",
	"请给定内存空间存放响应结果",
	"给定的URL为非法URL",
	"连接服务器失败!",
	"和服务器间通讯失败!",
	"未知的响应头",
	"请求失败",
	"没有响应内容",
	NULL /* other error */
};

#ifndef min
#define min(x,y) ((x)<(y)?(x):(y))
#endif

#if defined(PROCESS_BODY) || defined(PROCESS_EXTRA)
/**
 * 初始化响应头,所有的数据都被清空。在调用任何函数前务必
 * 调用。
 */
void initResponseHeader(HTTP_RESPONSE_HEADER_T* headers)
{
	if (headers != NULL)
	{
		memset(headers, 0, sizeof(HTTP_RESPONSE_HEADER_T));
	}
}
#endif

/**
 * HTTP请求
 * IN:
 *  url:        HTTP的URL,可以带query_string('?'后面的部分),例:http://user:passwd@host:port/file?query
 *  method:     请求方式,M_GET、M_POST或者M_HEAD,分别代表"GET"、"POST"或者"HEAD"方式
 *  inHeaders:  请求头信息,如设置cookie的头信息,可以传NULL,格式是:"Header1: value1\nHeader2: value2",最后一个不加'\n'
 *  outHeaders: 响应的头信息,见HTTP_RESPONSE_HEADER_T定义,可以传NULL
 *  timeout:    访问超时秒数,传0使用缺省值
 *  response:   存放响应结果的内存区,如果是M_HEAD,可以传NULL
 *  size:       response的空间大小,如果是M_HEAD,可以传0
 * OUT:
 *  0: 发生错误,错误原因可看headers中的errMsg
 *  >0: response中的有效字符数,这时headers中的errMsg为NULL
 * 【注意】:response中不会添加字符串结束标志'\0',因为结果也可以是二进制内容
 */
int HTTPRequest(const char* url, REQUEST_METHOD_T method, const char* inHeaders, HTTP_RESPONSE_HEADER_T* outHeaders, int timeout, char* response, int size)
{
	switch (method)
	{
	case M_GET:
		return HTTPRequestGet(url, inHeaders, outHeaders, timeout, response, size);
		
	case M_POST:
		return HTTPRequestPost(url, NULL, 0, inHeaders, outHeaders, timeout, response, size);
		
	case M_HEAD:
		return HTTPRequestHead(url, inHeaders, outHeaders, timeout);
		
	default:
		if (outHeaders != NULL)
		{
			outHeaders->errMsg = ERROR_MESSAGE[UNSUPPORTED_METHOD];
		}
		return 0;
	}
}

/* 超时时间,内部函数 */
static int getResponseTimeOut(int timeout)
{
	if (timeout <= 0)
	{
		return DEFAULT_TIMEOUT;
	}
	return timeout;
}

/* 内部用函数,检查各参数,分析URL */
static int validHTTPParams(const char* url, HTTP_RESPONSE_HEADER_T* headers, char* response, int size, URLINFO* urlInfo)
{
	int errno = NO_ERROR;
	const char* err = NULL;
	
#if !defined(PROCESS_EXTRA) && !defined(PROCESS_BODY)
	if (headers != NULL)
	{
		memset(headers, 0, sizeof(HTTP_RESPONSE_HEADER_T));
	}
#endif
	
	if (url == NULL)
	{
		errno = NO_URL;
		goto ERROR;
	}
	if (response == NULL || size <= 0)
	{
		errno = NO_BUFFER;
		goto ERROR;
	}
	
	err = parseURL(url, urlInfo);
	if (err)
	{
		errno = OTHER_ERROR;
		goto ERROR;
	}
	
	return 1;
	
ERROR:
	if (headers != NULL)
	{
		headers->errMsg = (errno != OTHER_ERROR ? ERROR_MESSAGE[errno] : err);
	}
	return 0;
}

/* 内部函数,读响应头信息 */
static int readHeaders(int hSocket, HTTP_RESPONSE_HEADER_T* headers, char* line, int timeout)
{
	int ret;
	char* p;
	
	headers->contentLength   = -1;
	
	/* get response status line */
	if ((ret = ReadLine(hSocket, line, 1024, timeout)) <= 0)
	{
		return SOCKET_ERROR;
	}
	
	if (strncmp(line, "HTTP/", 5) != 0)
	{
		return UNKNOWN_RESPONSE;
	}
	
	p = line + 5;
	while (*p && *p != ' ')p++;
	while (*p && *p == ' ')p++;
	
	strncpy(headers->statusCode, p, 3);
	
	//read other headers
	while (1)
	{
		if ((ret = ReadLine(hSocket, line, 1024, timeout)) < 0)
		{
			return SOCKET_ERROR;
		}
		if (ret == 0)
		{
			break;
		}
		if (strncasecmp(line, "Content-Type:", 13) == 0)
		{
			p = line + 13;
			while (*p && *p == ' ')p++;
			
			strncpy(headers->contentType, p, 80);
		}
		else if (strncasecmp(line, "Content-Length:", 15) == 0)
		{
			p = line + 15;
			while (*p && *p == ' ')p++;
			
			headers->contentLength = atoi(p);
		}
		else if (strncasecmp(line, "Date:", 5) == 0)
		{
			p = line + 5;
			while (*p && *p == ' ')p++;
			
			strncpy(headers->date, p, 32);
		}
		else if (strncasecmp(line, "Server:", 7) == 0)
		{
			p = line + 7;
			while (*p && *p == ' ')p++;
			
			strncpy(headers->server, p, 80);
		}
		else if (strncasecmp(line, "Last-Modified:", 14) == 0)
		{
			p = line + 14;
			while (*p && *p == ' ')p++;
			
			strncpy(headers->lastModified, p, 32);
		}
		else if (strncasecmp(line, "Location:", 9) == 0)
		{
			p = line + 9;
			while (*p && *p == ' ')p++;
			
			strncpy(headers->location, p, 1024);
		}
	}
	
	return NO_ERROR;
}

/* 内部函数,读响应内容 */
static int readResponse(int hSocket, HTTP_RESPONSE_HEADER_T* pHeaders, char* line, char* response, int size, int* errno, int timeout)
{
	int ret;
	HTTP_RESPONSE_HEADER_T headers = {0};
	
	int readByte = 0;
	
	if (pHeaders == NULL)
	{
		pHeaders = &headers;
	}
	ret = readHeaders(hSocket, pHeaders, line, timeout);
	switch (ret)
	{
	case SOCKET_ERROR:
		*errno = COMM_ERROR;
		return 0;
		
	case NO_ERROR:
		break;
		
	default:
		*errno = ret;
		return 0;
	}

#if 0	
	if (pHeaders->statusCode[0] == '4')
	{
		/* not OK */
		*errno = BAD_REQUEST;
		return 0;
	}
#endif
	
	if(pHeaders->contentLength == 0)
	{
		/* nothing */
		*errno = NO_BODY;
		return 0;
	}

#ifdef PROCESS_BODY
	if (pHeaders->processResponseBody != NULL) {
		return (*pHeaders->processResponseBody)(hSocket, response, size);
	}
#endif
	if (pHeaders->contentLength > 0)
	{
		int len = min(size, pHeaders->contentLength);
		while (readByte < len) {
			ret = Receive(hSocket, response+readByte, len-readByte, timeout);
			switch (ret) {
			case SOCKET_ERROR:
				return SOCKET_ERROR;
			case SOCKET_TIMEOUT:
				break;
			case SOCKET_CLOSED:
				return readByte;
			default:
				readByte += ret;
				break;
			}
		}
	}
	else
	{
		while (readByte < size)
		{
			ret = Receive(hSocket, response+readByte, size-readByte, timeout);
			switch (ret) {
			case SOCKET_ERROR:
			case SOCKET_CLOSED:
				return readByte;
			case SOCKET_TIMEOUT:
				break;
			default:
				readByte += ret;
				break;
			}
		}
	}
	
	/* discard the remaing response */
	while (1) {
#ifndef PROCESS_EXTRA
		char buf[1024];
		ret = Receive(hSocket, buf, 1024, 1);
#else
		ret = Receive(hSocket, pHeaders->extraResp, 1024, 1);
#endif

⌨️ 快捷键说明

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