📄 c_http.c
字号:
/**
* 以各种方式调用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 + -