├── .project ├── CMakeLists.txt ├── README.md ├── include └── chttp │ ├── chttp.h │ ├── chttp_error.h │ ├── chttp_socket.h │ ├── chttp_string.h │ ├── cookie.h │ ├── setopt.h │ └── slist.h ├── src ├── chttp.c ├── chttp_socket.c ├── chttp_string.c ├── cookie.c └── slist.c └── test ├── CMakeLists.txt └── src ├── test_chttp.c ├── test_cookie.c ├── test_slist.c └── test_string.c /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | nx_http 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 10 | clean,full,incremental, 11 | 12 | 13 | 14 | 15 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 16 | full,incremental, 17 | 18 | 19 | 20 | 21 | 22 | org.eclipse.cdt.core.cnature 23 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 24 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 25 | 26 | 27 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.8) 2 | project(chttp) 3 | 4 | set(HTTPS 1) 5 | 6 | #定义编译选项 7 | add_definitions("-Wall -ansi -g -std=c99 -DBUILD") 8 | 9 | 10 | #头文件查找目录 11 | include_directories(./include/chttp/) 12 | 13 | #添加源代码 14 | aux_source_directory(./src/ CHTTP_SRC) 15 | 16 | #输出库的路径 17 | set(LIBRARY_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/lib) 18 | 19 | #生成静态库名称 20 | add_library(chttp STATIC ${CHTTP_SRC}) 21 | 22 | if(WIN32) 23 | find_library(WS2_32_LIBRARY ws2_32) 24 | if(WS2_32_LIBRARY) 25 | target_link_libraries(chttp ${WS2_32_LIBRARY}) 26 | endif(WS2_32_LIBRARY) 27 | 28 | message(STATUS "win32 平台") 29 | elseif(LINUX) 30 | message(STATUS "LINUX 平台") 31 | target_link_libraries(chttp -lsocket) 32 | endif(WIN32) 33 | 34 | 35 | if(HTTPS) 36 | add_definitions("-D_HTTPS") 37 | target_link_libraries(chttp ssl crypto) 38 | endif(HTTPS) 39 | add_subdirectory(test) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # chttp 2 | 一个简单的http/https库,c语言实现,用到了 openssl库,支持 get和post cookie管理 3 | 使用cmake工具来编译,在编译库之前,可以选择是否支持https 具体看 CMakeLists.txt 4 | 5 | 如果要支持https 请先安装openssl库 6 | 7 | windows下 mingw编译通过 8 | 9 | windows下 mingw编译命令为: 10 | 11 | mkdir build 12 | 13 | cd build 14 | 15 | cmake -G"MinGW Makefiles" .. 16 | 17 | mingw32-make 18 | 19 | 20 | 21 | 创建build目的是 让一些文件生成在build目录下,不污染项目文件。 22 | 23 | chttp/lib 目录下生成 chttp库文件 24 | chttp/bin 目录下生成 测试程序 25 | 26 | 27 | 28 | linux下测试通过。 29 | 30 | 31 | 程序肯定存在很多问题,若发现问题,欢迎联系我。qq 30670835 32 | -------------------------------------------------------------------------------- /include/chttp/chttp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * chttp.h 3 | * 4 | * Created on: 2015年6月8日 5 | * Author: Administrator 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #ifndef INCLUDE_CHTTP_CHTTP_H_ 13 | #define INCLUDE_CHTTP_CHTTP_H_ 14 | 15 | /* 16 | * 定义win32平台的宏 17 | */ 18 | #if (defined(_WIN32) || defined(__WIN32__)) && \ 19 | !defined(WIN32) && !defined(__SYMBIAN32__) 20 | #define WIN32 21 | #endif 22 | 23 | #ifdef __cplusplus 24 | extern "C" 25 | { 26 | #endif 27 | 28 | 29 | 30 | typedef struct chttp_s chttp_t; 31 | 32 | /* 编译库的时候,导出函数,使用库的时候导入*/ 33 | #if defined(WIN32) 34 | # if defined(BUILD) 35 | # define CHTTP_API __declspec(dllexport) 36 | # else 37 | # define CHTTP_API __declspec(dllimport) 38 | # endif 39 | #else 40 | # define CHTTP_API 41 | #endif 42 | 43 | 44 | 45 | 46 | 47 | /* 48 | * 定义协议类型,http或者https类型 49 | */ 50 | typedef enum 51 | { 52 | CHTTP = 0, CHTTPS 53 | } chttp_protocol_type_t; 54 | 55 | /* 56 | * 定义提交方式,get或者post方式 57 | */ 58 | typedef enum 59 | { 60 | CHTTP_METHOD_GET = 0, CHTTP_METHOD_POST 61 | } chttp_method_type_t; 62 | 63 | 64 | 65 | 66 | /* 67 | * 可以设置的一些请求头选项 68 | */ 69 | typedef enum 70 | { 71 | 72 | 73 | /*网站url*/ 74 | CHTTP_OPT_URL = 0, 75 | 76 | /*是否调试*/ 77 | CHTTP_OPT_DEBUG, 78 | 79 | /*是否是post请求,0为get 1为post, 默认为get请求*/ 80 | CHTTP_OPT_POST, 81 | 82 | /*设置请求来路地址*/ 83 | CHTTP_OPT_REFER, 84 | 85 | /*设置客户端信息*/ 86 | CHTTP_OPT_AGENT, 87 | 88 | /*post提交的内容,char*类型 */ 89 | CHTTP_OPT_POSTDATA, 90 | 91 | /*以cookie列表头指针的方式传递cookie信息*/ 92 | CHTTP_OPT_COOKIE_LIST, 93 | 94 | /*以cookie字符串的方式传递cookie信息, char* 类型*/ 95 | CHTTP_OPT_COOKIE_STR, 96 | 97 | /*传递用户自定义的头信息,chttp_slist_t * 类型 */ 98 | CHTTP_OPT_CUSTOM, 99 | 100 | } chttp_opt_t; 101 | 102 | 103 | #include 104 | #include 105 | #include 106 | #include 107 | 108 | 109 | struct chttp_s 110 | { 111 | /* 是否显示调试信息 */ 112 | int debug; 113 | 114 | /*句柄*/ 115 | chttp_socket_t sock; 116 | 117 | /* 协议类型 */ 118 | chttp_protocol_type_t protocol_type; 119 | 120 | /* 请求方式*/ 121 | chttp_method_type_t method_type; 122 | 123 | /*网站地址*/ 124 | char *url; 125 | 126 | /*主机地址*/ 127 | chttp_str_t *host; 128 | 129 | /*来路地址*/ 130 | char *refer; 131 | 132 | /*端口*/ 133 | int port; 134 | 135 | /*cookie,请求的时候设置要提交的cookie,返回请求的时候存储返回的cookie*/ 136 | chttp_cookie_t *cookies; 137 | 138 | /*cookie字符串 请求的时候设置要提交的cookie,返回请求的时候存储返回的cookie*/ 139 | char *cookie_str; 140 | 141 | /*post的时候要提交的数据*/ 142 | char *postdata; 143 | 144 | /*客户端信息*/ 145 | char *agent; 146 | 147 | /*用户自定义请求头信息*/ 148 | chttp_slist_t *custom_header_list; 149 | 150 | /*请求头指针*/ 151 | chttp_str_t *req_header; 152 | 153 | /*返回的头部*/ 154 | chttp_str_t *res_header; 155 | 156 | /*返回的内容部分*/ 157 | chttp_str_t *res_content; 158 | 159 | /*存储错误信息*/ 160 | chttp_str_t *err_str; 161 | }; 162 | 163 | CHTTP_API chttp_t* chttp_init(); 164 | CHTTP_API char* chttp_exec(chttp_t *chttp); 165 | CHTTP_API char* chttp_lasterr(chttp_t *chttp); 166 | CHTTP_API void chttp_free(chttp_t *chttp); 167 | 168 | 169 | /*这个头文件中放了 _chttp_setopt(chttp,opt,param) 宏 用来处理不同的 param*/ 170 | #include 171 | 172 | 173 | 174 | #ifdef __cplusplus 175 | } 176 | #endif 177 | 178 | #endif /* INCLUDE_CHTTP_CHTTP_H_ */ 179 | 180 | -------------------------------------------------------------------------------- /include/chttp/chttp_error.h: -------------------------------------------------------------------------------- 1 | /* 2 | * chttp_error.h 3 | * 4 | * Created on: 2015年6月13日 5 | * Author: Administrator 6 | */ 7 | 8 | #include 9 | 10 | #ifndef INCLUDE_CHTTP_CHTTP_ERROR_H_ 11 | #define INCLUDE_CHTTP_CHTTP_ERROR_H_ 12 | 13 | typedef struct chttp_error_s chttp_error_t; 14 | 15 | typedef enum 16 | { 17 | CHTTP_ERR_NOCONNECT 18 | }chttp_error_type_t; 19 | 20 | struct chttp_error_s 21 | { 22 | chttp_error_type_t type; 23 | chttp_str_t *err_str; 24 | }; 25 | 26 | #endif /* INCLUDE_CHTTP_CHTTP_ERROR_H_ */ 27 | -------------------------------------------------------------------------------- /include/chttp/chttp_socket.h: -------------------------------------------------------------------------------- 1 | /* 2 | * chttp_socket.h 3 | * 4 | * Created on: 2015年6月10日 5 | * Author: Administrator 6 | */ 7 | 8 | #include 9 | 10 | 11 | /* 12 | * 包含不同平台的头文件 13 | */ 14 | #if defined(WIN32) 15 | #include 16 | #include 17 | #else 18 | #include 19 | #include 20 | #include 21 | #include 22 | #endif 23 | 24 | #if defined(_HTTPS) 25 | #include 26 | #include 27 | #include 28 | #endif 29 | 30 | #ifndef INCLUDE_CHTTP_CHTTP_SOCKET_H_ 31 | #define INCLUDE_CHTTP_CHTTP_SOCKET_H_ 32 | 33 | #if defined(WIN32) 34 | typedef SOCKET chttp_socket_t; 35 | #else 36 | typedef int chttp_socket_t; 37 | #endif 38 | 39 | /* 40 | * 初始化socket 返回socket句柄 41 | */ 42 | chttp_socket_t chttp_socket(); 43 | chttp_socket_t chttp_socket_connect(chttp_socket_t sock, char *host, int port); 44 | int chttp_socket_send(chttp_socket_t socket, void *buffer, size_t size, int flags); 45 | int chttp_socket_recv(chttp_socket_t socket, void *buffer, size_t size, int flags); 46 | 47 | chttp_str_t* chttp_ssl_request(chttp_socket_t socket, void *buffer, size_t size); 48 | 49 | void chttp_socket_close(chttp_socket_t sock); 50 | 51 | #endif /* INCLUDE_CHTTP_CHTTP_SOCKET_H_ */ 52 | -------------------------------------------------------------------------------- /include/chttp/chttp_string.h: -------------------------------------------------------------------------------- 1 | /* 2 | * chttp_string.h 3 | * 4 | * Created on: 2015年6月12日 5 | * Author: Administrator 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | #ifndef INCLUDE_CHTTP_CHTTP_STRING_H_ 12 | #define INCLUDE_CHTTP_CHTTP_STRING_H_ 13 | 14 | typedef struct chttp_str_s chttp_str_t; 15 | 16 | struct chttp_str_s 17 | { 18 | char *data; 19 | size_t buf_size; 20 | size_t data_len; 21 | }; 22 | 23 | chttp_str_t *chttp_str_append(chttp_str_t *str, const char *cstr); 24 | void chttp_str_reset(chttp_str_t *str); 25 | chttp_str_t *chttp_str_size_append(chttp_str_t *str, const char *cstr, size_t len); 26 | void chttp_str_free(chttp_str_t *str); 27 | 28 | #endif /* INCLUDE_CHTTP_CHTTP_STRING_H_ */ 29 | -------------------------------------------------------------------------------- /include/chttp/cookie.h: -------------------------------------------------------------------------------- 1 | /* 2 | * cookie.h 3 | * 4 | * Created on: 2015年6月9日 5 | * Author: Administrator 6 | */ 7 | #include 8 | #include 9 | 10 | #ifndef INCLUDE_CHTTP_COOKIE_H_ 11 | #define INCLUDE_CHTTP_COOKIE_H_ 12 | 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | 19 | typedef struct chttp_cookie_s chttp_cookie_t; 20 | 21 | struct chttp_cookie_s 22 | { 23 | char *key; 24 | char *value; 25 | chttp_cookie_t *next; 26 | }; 27 | 28 | CHTTP_API int chttp_cookie_parse(chttp_cookie_t** head, const char* header); 29 | CHTTP_API int chttp_cookie_add(chttp_cookie_t *head, chttp_cookie_t *cookies); 30 | CHTTP_API const char* chttp_cookie_get_value(chttp_cookie_t* head, const char* key); 31 | CHTTP_API char* chttp_cookie_tostring(chttp_cookie_t* head); 32 | CHTTP_API void chttp_cookie_free(chttp_cookie_t* head); 33 | 34 | 35 | #ifdef __cplusplus 36 | } 37 | #endif 38 | 39 | #endif /* INCLUDE_CHTTP_COOKIE_H_ */ 40 | -------------------------------------------------------------------------------- /include/chttp/setopt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * setopt.h 3 | * 4 | * Created on: 2015年6月10日 5 | * Author: Administrator 6 | */ 7 | 8 | #include 9 | 10 | #ifndef INCLUDE_CHTTP_SETOPT_H_ 11 | #define INCLUDE_CHTTP_SETOPT_H_ 12 | 13 | /* 14 | * 设置请求头的选项 15 | */ 16 | #define chttp_setopt(chttp,opt,param) do{ \ 17 | switch(opt) \ 18 | { \ 19 | case CHTTP_OPT_POST: chttp->method_type = (chttp_method_type_t)param; break; \ 20 | case CHTTP_OPT_DEBUG: chttp->debug = (int)param; break; \ 21 | case CHTTP_OPT_URL: chttp->url = (char*)param; break; \ 22 | case CHTTP_OPT_REFER: chttp->refer = (char*)param; break; \ 23 | case CHTTP_OPT_AGENT: chttp->agent = (char*)param; break; \ 24 | case CHTTP_OPT_POSTDATA: chttp->postdata = (char*)param; break; \ 25 | case CHTTP_OPT_COOKIE_STR: chttp->cookie_str = (char*)param; break; \ 26 | case CHTTP_OPT_CUSTOM: chttp->custom_header_list = (chttp_slist_t*)param; break; \ 27 | case CHTTP_OPT_COOKIE_LIST: chttp->cookies = (chttp_cookie_t*)param; break; \ 28 | default: break; \ 29 | } \ 30 | }while(0) 31 | 32 | 33 | 34 | 35 | 36 | #endif /* INCLUDE_CHTTP_SETOPT_H_ */ 37 | -------------------------------------------------------------------------------- /include/chttp/slist.h: -------------------------------------------------------------------------------- 1 | /* 2 | * clist.h 3 | * 4 | * Created on: 2015年6月9日 5 | * Author: Administrator 6 | */ 7 | #include 8 | 9 | #ifndef INCLUDE_CHTTP_SLIST_H_ 10 | #define INCLUDE_CHTTP_SLIST_H_ 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | 17 | typedef struct chttp_slist_s chttp_slist_t; 18 | 19 | struct chttp_slist_s 20 | { 21 | char *data; 22 | chttp_slist_t *next; 23 | }; 24 | 25 | CHTTP_API chttp_slist_t* chttp_slist_append(chttp_slist_t *list, const char *data); 26 | CHTTP_API void chttp_slist_free_all(chttp_slist_t *list); 27 | 28 | #ifdef __cplusplus 29 | } 30 | #endif 31 | 32 | #endif /* INCLUDE_CHTTP_SLIST_H_ */ 33 | -------------------------------------------------------------------------------- /src/chttp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * nx_http.c 3 | * 4 | * Created on: 2015年6月8日 5 | * Author: Administrator 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | static int _parse_url(char *, int *, char *, int *, char *); 12 | static int _http_pack(chttp_t *chttp); 13 | static int _chttp_request(chttp_t *chttp); 14 | 15 | /* 16 | * 初始化chttp 17 | * 返回初始化后的chttp_t 指针 18 | */ 19 | chttp_t* chttp_init() 20 | { 21 | chttp_t *chttp = NULL; 22 | 23 | chttp = (chttp_t*) malloc(sizeof(chttp_t)); 24 | memset(chttp, 0, sizeof(chttp_t)); 25 | 26 | /*初始化 socket句柄*/ 27 | chttp->sock = chttp_socket(); 28 | 29 | return chttp; 30 | } 31 | 32 | /*执行http请求*/ 33 | char* chttp_exec(chttp_t *chttp) 34 | { 35 | _http_pack(chttp); 36 | 37 | if (chttp->debug) 38 | { 39 | printf("\n\n%s\n", chttp->req_header->data); 40 | } 41 | 42 | /* 如果返回值不是0 就表示出错了。 */ 43 | if (0 != _chttp_request(chttp)) 44 | { 45 | return NULL; 46 | } 47 | 48 | if (chttp->debug) 49 | { 50 | printf("\n\n%s\n", chttp->res_header->data); 51 | } 52 | 53 | return chttp->res_content->data; 54 | } 55 | 56 | /* 57 | * 根据 chttp发送请求 58 | * 返回0表示成功,返回1 表示连接失败 59 | */ 60 | static int _chttp_request(chttp_t *chttp) 61 | { 62 | chttp_str_t *html = NULL; 63 | char text[512], *temp = NULL; 64 | size_t len = 0; 65 | if (0 == chttp_socket_connect(chttp->sock, chttp->host->data, chttp->port)) 66 | { 67 | return 1; 68 | } 69 | 70 | if (chttp->protocol_type == CHTTP) 71 | { 72 | 73 | chttp_socket_send(chttp->sock, chttp->req_header->data, 74 | chttp->req_header->data_len, 0); 75 | 76 | while ((len = chttp_socket_recv(chttp->sock, text, 512, 0)) > 0) 77 | { 78 | text[len] = 0; 79 | html = chttp_str_size_append(html, text, len); 80 | } 81 | } 82 | else 83 | { 84 | html = chttp_ssl_request(chttp->sock, chttp->req_header->data, 85 | chttp->req_header->data_len); 86 | } 87 | 88 | for (temp = html->data; 89 | *temp != 0 90 | && !(*temp == '\r' && *(temp + 1) == '\n' 91 | && *(temp + 2) == '\r' && *(temp + 3) == '\n'); 92 | temp++) 93 | ; 94 | 95 | /*保存头部*/ 96 | chttp->res_header = chttp_str_size_append(chttp->res_header, html->data, 97 | (size_t) (temp - html->data)); 98 | 99 | /*保存内容*/ 100 | chttp->res_content = chttp_str_size_append(chttp->res_content, temp + 4, 101 | html->data_len - (temp - html->data) - 4); 102 | 103 | chttp_str_free(html); 104 | html = NULL; 105 | 106 | /*如果下面两个中的其中一个值不为空,表示要获取cookie,就解析cookie保存到 chttp->cookies中*/ 107 | if (chttp->cookie_str != NULL || chttp->cookies != NULL) 108 | { 109 | chttp_cookie_parse(&chttp->cookies, chttp->res_header->data); 110 | } 111 | 112 | return 0; 113 | } 114 | 115 | /** 116 | * 释放chttp 117 | */ 118 | void chttp_free(chttp_t *chttp) 119 | { 120 | if (!chttp) 121 | return; 122 | 123 | if (chttp->sock) 124 | { 125 | chttp_socket_close(chttp->sock); 126 | chttp->sock = 0; 127 | } 128 | 129 | /*如果存在cookie 释放他*/ 130 | if (chttp->cookies) 131 | { 132 | chttp_cookie_free(chttp->cookies); 133 | chttp->cookies = NULL; 134 | } 135 | 136 | /*如果主机名需要释放*/ 137 | if (chttp->host) 138 | { 139 | chttp_str_free(chttp->host); 140 | chttp->host = NULL; 141 | } 142 | 143 | if (chttp->req_header) 144 | { 145 | chttp_str_free(chttp->req_header); 146 | chttp->req_header = NULL; 147 | } 148 | 149 | if (chttp->res_content) 150 | { 151 | chttp_str_free(chttp->res_content); 152 | chttp->res_content = NULL; 153 | } 154 | 155 | } 156 | 157 | /* 158 | * 根据chttp组装请求包 159 | */ 160 | static int _http_pack(chttp_t *chttp) 161 | { 162 | char host[512], get[512]; 163 | int proto = 0, port = 0; 164 | 165 | _parse_url(chttp->url, &proto, host, &port, get); 166 | 167 | chttp->port = port; 168 | chttp->host = chttp_str_append(chttp->host, host); 169 | 170 | /*协议类型 HTTP / HTTPS*/ 171 | chttp->protocol_type = proto; 172 | 173 | if (CHTTP_METHOD_GET == chttp->method_type) 174 | { 175 | /* GET http://www.zixue7.com/forum.php HTTP/1.1 */ 176 | chttp->req_header = chttp_str_append(chttp->req_header, "GET "); 177 | chttp->req_header = chttp_str_append(chttp->req_header, get); 178 | chttp->req_header = chttp_str_append(chttp->req_header, " HTTP/1.1"); 179 | chttp->req_header = chttp_str_append(chttp->req_header, "\r\n"); 180 | 181 | /* Host: www.zixue7.com */ 182 | chttp->req_header = chttp_str_append(chttp->req_header, "Host: "); 183 | chttp->req_header = chttp_str_append(chttp->req_header, host); 184 | chttp->req_header = chttp_str_append(chttp->req_header, "\r\n"); 185 | 186 | /* User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0 */ 187 | if (NULL == chttp->agent) 188 | { 189 | chttp->req_header = 190 | chttp_str_append(chttp->req_header, 191 | "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0"); 192 | chttp->req_header = chttp_str_append(chttp->req_header, "\r\n"); 193 | } 194 | else 195 | { 196 | chttp->req_header = chttp_str_append(chttp->req_header, 197 | "User-Agent: "); 198 | chttp->req_header = chttp_str_append(chttp->req_header, 199 | chttp->agent); 200 | chttp->req_header = chttp_str_append(chttp->req_header, "\r\n"); 201 | } 202 | 203 | /* Referer: http://www.zixue7.com/thread-190-1-1.html 204 | * 如果没有设置 refer 就默认当前url为来路域名 205 | * */ 206 | if (NULL != chttp->refer) 207 | { 208 | chttp->req_header = chttp_str_append(chttp->req_header, 209 | "Referer: "); 210 | chttp->req_header = chttp_str_append(chttp->req_header, 211 | chttp->refer); 212 | chttp->req_header = chttp_str_append(chttp->req_header, "\r\n"); 213 | } 214 | else 215 | { 216 | chttp->req_header = chttp_str_append(chttp->req_header, 217 | "Referer: "); 218 | chttp->req_header = chttp_str_append(chttp->req_header, chttp->url); 219 | chttp->req_header = chttp_str_append(chttp->req_header, "\r\n"); 220 | } 221 | 222 | /* Cookie: */ 223 | if (NULL != chttp->cookie_str) 224 | { 225 | chttp->req_header = chttp_str_append(chttp->req_header, "Cookie: "); 226 | chttp->req_header = chttp_str_append(chttp->req_header, 227 | chttp->cookie_str); 228 | chttp->req_header = chttp_str_append(chttp->req_header, "\r\n"); 229 | } 230 | else if (NULL != chttp->cookies) 231 | { 232 | char *pcookie = chttp_cookie_tostring(chttp->cookies); 233 | chttp->req_header = chttp_str_append(chttp->req_header, "Cookie: "); 234 | chttp->req_header = chttp_str_append(chttp->req_header, pcookie); 235 | chttp->req_header = chttp_str_append(chttp->req_header, "\r\n"); 236 | free(pcookie); 237 | } 238 | 239 | /* Connection: Close */ 240 | chttp->req_header = chttp_str_append(chttp->req_header, 241 | "Connection: Close"); 242 | chttp->req_header = chttp_str_append(chttp->req_header, "\r\n"); 243 | 244 | }else /*处理普通的post请求*/ 245 | { 246 | /* 247 | * POST http://www.baidu.com/login.php HTTP/1.1 248 | Host: www.baidu.com 249 | User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0 250 | Accept: text/html,application/xhtml+xml,application/xml;q=0.9,* / *;q=0.8 251 | Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3 252 | Accept-Encoding: gzip, deflate 253 | Cookie: BAIDUID=997EB76C2725522C8EBE30B4127E263B:FG=1; BD_UPN=13314352; BIDUPSID=4007768C25D14E4883B1A37FF77956F7; PSTM=1433399829; BDUSS=WtqUnh0ZUxWTGtlTzRmN3R1UE9lTFg3MldkdDNwYm9sNWdDcWUyb2R2Q2c3NWhWQVFBQUFBJCQAAAAAAAAAAAEAAAA-p74KMTczMTI2MDE5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKBicVWgYnFVQ; ispeed_lsm=2; H_PS_645EC=6486zzMln6d2lC8Qm7giGBWd%2F%2BmuOLT%2BiRFKT3r7Bt4dKyss0zo03gO3lgd4o4UMgAb1; H_PS_PSSID=14591_1425_14860_12658_14511_14444_14734_12825_14429_12867_14622_14669_12723_14549_14625_14484_14903_11807_13937; BDSFRCVID=q-usJeC62mE0-a3lqpqSKd_zjCh-TrTTH6aIS1uXeqpgMuCZms2OEG0PJOlQpYD-LEWhogKK3gOTH4jP; H_BDCLCKID_SF=JJ4q_ItaJDvbfP0k247qe5OQqxby26nDH6TeaJ5nJDoVsDtz-jbSKJ8L0PRbybTB0K-L-PomQpP-HqTbDJoibJ_QbPct3hTL-br9Kl0MLpccDMjxWf8VXMLiMMnMBMPe52OnaIb_LIcjqR8ZD6LKj55P; BD_CK_SAM=1; BDSVRTM=0 254 | Connection: keep-alive 255 | Content-Type: application/x-www-form-urlencoded 256 | Content-Length: 46 257 | 258 | username=admin&submit=%CC%E1%BD%BB%B2%E9%D1%AF 259 | */ 260 | chttp->req_header = chttp_str_append(chttp->req_header, "POST "); 261 | chttp->req_header = chttp_str_append(chttp->req_header, get); 262 | chttp->req_header = chttp_str_append(chttp->req_header, " HTTP/1.1"); 263 | chttp->req_header = chttp_str_append(chttp->req_header, "\r\n"); 264 | 265 | /* Host: www.zixue7.com */ 266 | chttp->req_header = chttp_str_append(chttp->req_header, "Host: "); 267 | chttp->req_header = chttp_str_append(chttp->req_header, host); 268 | chttp->req_header = chttp_str_append(chttp->req_header, "\r\n"); 269 | 270 | /* User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0 */ 271 | if (NULL == chttp->agent) 272 | { 273 | chttp->req_header = 274 | chttp_str_append(chttp->req_header, 275 | "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0"); 276 | chttp->req_header = chttp_str_append(chttp->req_header, "\r\n"); 277 | } 278 | else 279 | { 280 | chttp->req_header = chttp_str_append(chttp->req_header, 281 | "User-Agent: "); 282 | chttp->req_header = chttp_str_append(chttp->req_header, 283 | chttp->agent); 284 | chttp->req_header = chttp_str_append(chttp->req_header, "\r\n"); 285 | } 286 | 287 | /* Referer: http://www.zixue7.com/thread-190-1-1.html 288 | * 如果没有设置 refer 就默认当前url为来路域名 289 | * */ 290 | if (NULL != chttp->refer) 291 | { 292 | chttp->req_header = chttp_str_append(chttp->req_header, 293 | "Referer: "); 294 | chttp->req_header = chttp_str_append(chttp->req_header, 295 | chttp->refer); 296 | chttp->req_header = chttp_str_append(chttp->req_header, "\r\n"); 297 | } 298 | else 299 | { 300 | chttp->req_header = chttp_str_append(chttp->req_header, 301 | "Referer: "); 302 | chttp->req_header = chttp_str_append(chttp->req_header, chttp->url); 303 | chttp->req_header = chttp_str_append(chttp->req_header, "\r\n"); 304 | } 305 | 306 | /* Cookie: */ 307 | if (NULL != chttp->cookie_str) 308 | { 309 | chttp->req_header = chttp_str_append(chttp->req_header, "Cookie: "); 310 | chttp->req_header = chttp_str_append(chttp->req_header, 311 | chttp->cookie_str); 312 | chttp->req_header = chttp_str_append(chttp->req_header, "\r\n"); 313 | } 314 | else if (NULL != chttp->cookies) 315 | { 316 | char *pcookie = chttp_cookie_tostring(chttp->cookies); 317 | chttp->req_header = chttp_str_append(chttp->req_header, "Cookie: "); 318 | chttp->req_header = chttp_str_append(chttp->req_header, pcookie); 319 | chttp->req_header = chttp_str_append(chttp->req_header, "\r\n"); 320 | free(pcookie); 321 | } 322 | 323 | /* Connection: Close */ 324 | chttp->req_header = chttp_str_append(chttp->req_header, 325 | "Connection: Close"); 326 | chttp->req_header = chttp_str_append(chttp->req_header, "\r\n"); 327 | 328 | /*Content-Type: application/x-www-form-urlencoded*/ 329 | chttp->req_header = chttp_str_append(chttp->req_header, 330 | "Content-Type: application/x-www-form-urlencoded"); 331 | chttp->req_header = chttp_str_append(chttp->req_header, "\r\n"); 332 | 333 | /*Content-Length: 46*/ 334 | if (NULL != chttp->postdata && 0 != chttp->postdata[0]) 335 | { 336 | char buf[100]; 337 | sprintf(buf, "Content-Length: %d\0", strlen(chttp->postdata)); 338 | chttp->req_header = chttp_str_append(chttp->req_header, buf); 339 | chttp->req_header = chttp_str_append(chttp->req_header, "\r\n"); 340 | chttp->req_header = chttp_str_append(chttp->req_header, "\r\n"); 341 | chttp->req_header = chttp_str_append(chttp->req_header, 342 | chttp->postdata); 343 | chttp->req_header = chttp_str_append(chttp->req_header, "\r\n"); 344 | } 345 | else 346 | { 347 | chttp->req_header = chttp_str_append(chttp->req_header, 348 | "Content-Length: 0\r\n"); 349 | } 350 | 351 | } 352 | 353 | chttp->req_header = chttp_str_append(chttp->req_header, "\r\n"); 354 | return 0; 355 | } 356 | 357 | /** 358 | * 解析url 359 | * 传入参数 例如 http://www.zixue7.com:80/index.php 360 | * host 返回url的主机地址 例如 www.zixue7.com 361 | * proto 返回请求类型,CHTTP 或者 CHTTPS 362 | * port 返回url的端口 363 | * get 返回url相对路径,比如 /index.php 364 | * 返回值为0 表示成功 365 | */ 366 | static int _parse_url(char *url, int *proto, char *host, int *port, char *get) 367 | { 368 | 369 | char site_url[512]; 370 | int i; 371 | 372 | //url is null 373 | if (url == NULL || url[0] == 0) 374 | return 1; 375 | 376 | memset(site_url, 0, 512); 377 | if (strncmp("http://", url, 7) == 0 || strncmp("HTTP://", url, 7) == 0) 378 | { //is http? 379 | //is http 380 | *proto = CHTTP; 381 | 382 | //copy url to site_url without http:// 383 | strcpy(site_url, url + 7); 384 | 385 | } 386 | else if (strncmp("https://", url, 7) == 0 387 | || strncmp("HTTPS://", url, 7) == 0) 388 | { //is https? 389 | //is https 390 | *proto = CHTTPS; 391 | 392 | //copy url to site_url without https:// 393 | strcpy(site_url, url + 8); 394 | } 395 | else 396 | { 397 | //is http 398 | *proto = CHTTP; 399 | //copy url to site_url 400 | strcpy(site_url, url); 401 | } 402 | 403 | //find first / 404 | for (i = 0; site_url[i] != '/' && site_url[i] != 0; i++) 405 | ; 406 | 407 | //don't find '/' 408 | if (i == strlen(site_url)) 409 | { 410 | get[0] = '/'; 411 | get[1] = 0; 412 | } 413 | else 414 | { 415 | strcpy(get, site_url + i); 416 | site_url[i] = 0; 417 | } 418 | 419 | //find the first ':' from site_url 420 | for (i = 0; site_url[i] != ':' && site_url[i] != 0; i++) 421 | ; 422 | 423 | //don't find ':' 424 | if (i == strlen(site_url)) 425 | { 426 | 427 | if (*proto == CHTTP) 428 | { 429 | //default http port 80 430 | *port = 80; 431 | } 432 | else if (*proto == CHTTPS) 433 | { 434 | //default https port 443 435 | *port = 443; 436 | } 437 | } 438 | else 439 | { //find ':' 440 | char p[6]; 441 | strcpy(p, site_url + i + 1); 442 | site_url[i] = 0; 443 | *port = strtol(p, NULL, 10); 444 | } 445 | 446 | //return host 447 | strcpy(host, site_url); 448 | 449 | return 0; 450 | } 451 | 452 | -------------------------------------------------------------------------------- /src/chttp_socket.c: -------------------------------------------------------------------------------- 1 | /* 2 | * chttp_socket.c 3 | * 4 | * Created on: 2015年6月10日 5 | * Author: Administrator 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | /* 12 | * 初始化socket 返回socket句柄 13 | */ 14 | chttp_socket_t chttp_socket() 15 | { 16 | chttp_socket_t sock = 0; 17 | 18 | #if defined(WIN32) 19 | WORD wVersionRequested; 20 | WSADATA wsaData; 21 | int err; 22 | wVersionRequested = MAKEWORD(1, 1); 23 | err = WSAStartup(wVersionRequested, &wsaData); 24 | if (err != 0) 25 | { 26 | return 0; 27 | } 28 | if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) 29 | { 30 | WSACleanup(); 31 | return 0; 32 | } 33 | #endif 34 | sock = socket(AF_INET, SOCK_STREAM, 0); 35 | 36 | if (-1 == sock) 37 | return 0; 38 | 39 | return sock; 40 | } 41 | 42 | /* 43 | * 通过域名连接服务器 44 | *失败 返回0 45 | */ 46 | chttp_socket_t chttp_socket_connect(chttp_socket_t sock, char *host, int port) 47 | { 48 | struct hostent *phost; 49 | struct sockaddr_in addr; 50 | int rc = 0; 51 | 52 | phost = gethostbyname(host); 53 | 54 | addr.sin_family = AF_INET; 55 | addr.sin_port = htons(port); 56 | addr.sin_addr.s_addr = *((unsigned long*) phost->h_addr_list[0]); 57 | 58 | rc = connect(sock, (struct sockaddr*) &addr, sizeof(addr)); 59 | 60 | if (0 != rc) 61 | return 0; 62 | 63 | return sock; 64 | } 65 | 66 | /* 67 | * 发送数据 68 | * socket socket句柄 69 | * buffer 要发送的数据的缓冲区 70 | * flags send函数的标志 71 | * ssl 是否sll加密传输 0为不加密,1为加密 72 | */ 73 | int chttp_socket_send(chttp_socket_t socket, void *buffer, size_t size, 74 | int flags) 75 | { 76 | return send(socket, buffer, size, flags); 77 | } 78 | 79 | /* 80 | * 接收数据 81 | * socket socket句柄 82 | * buffer 接收数据的缓冲区 83 | * flags recv函数的标志 84 | * ssl 是否sll加密传输 0为不加密,1为加密 85 | */ 86 | int chttp_socket_recv(chttp_socket_t socket, void *buffer, size_t size, 87 | int flags) 88 | { 89 | return recv(socket, buffer, size, flags); 90 | } 91 | 92 | /* 93 | * 执行ssl请求,返回chttp_str_t * 需要释放内存 94 | */ 95 | chttp_str_t* chttp_ssl_request(chttp_socket_t socket, void *buffer, size_t size) 96 | { 97 | #if defined(_HTTPS) 98 | SSL_CTX *ctx = NULL; 99 | SSL *ssl = NULL; 100 | int ret = 0; 101 | char text[1024]; 102 | chttp_str_t *html = NULL; 103 | 104 | SSL_library_init(); 105 | SSL_load_error_strings(); 106 | 107 | ctx = SSL_CTX_new(SSLv23_client_method()); 108 | if (ctx == NULL) 109 | return NULL; 110 | 111 | ssl = SSL_new(ctx); 112 | if (ssl == NULL) 113 | return NULL; 114 | 115 | ret = SSL_set_fd(ssl, socket); 116 | if (0 == ret) 117 | return NULL; 118 | 119 | RAND_poll(); 120 | while (RAND_status() == 0) 121 | { 122 | unsigned short rand_ret = rand() % 65536; 123 | RAND_seed(&rand_ret, sizeof(rand_ret)); 124 | } 125 | 126 | ret = SSL_connect(ssl); 127 | if (ret != 1) 128 | return NULL; 129 | 130 | if (!(SSL_write(ssl, buffer, size))) 131 | { 132 | return NULL; 133 | } 134 | 135 | while ((ret = SSL_read(ssl, text, 1024)) > 0) 136 | { 137 | html = chttp_str_size_append(html, text, ret); 138 | } 139 | 140 | //free resource 141 | if (ssl) 142 | { 143 | SSL_free(ssl); 144 | SSL_CTX_free(ctx); 145 | ERR_free_strings(); 146 | } 147 | 148 | return html; 149 | #else 150 | printf("不支持https方式请求,请在编译的时候加入开启 _HTTPS \n"); 151 | exit(1); 152 | #endif 153 | } 154 | 155 | /* 156 | *关闭socket连接 157 | */ 158 | void chttp_socket_close(chttp_socket_t sock) 159 | { 160 | #if defined(WIN32) 161 | closesocket(sock); 162 | WSACleanup(); 163 | #else 164 | close(sock); 165 | #endif 166 | } 167 | -------------------------------------------------------------------------------- /src/chttp_string.c: -------------------------------------------------------------------------------- 1 | /* 2 | * chttp_string.c 3 | * 4 | * Created on: 2015年6月12日 5 | * Author: Administrator 6 | */ 7 | 8 | #include 9 | 10 | chttp_str_t *chttp_str_append(chttp_str_t *str, const char *cstr) 11 | { 12 | if ((cstr != NULL && cstr[0] != 0)) 13 | return chttp_str_size_append(str, cstr, strlen(cstr)); 14 | else 15 | return str; 16 | } 17 | 18 | chttp_str_t *chttp_str_size_append(chttp_str_t *str, const char *cstr, 19 | size_t len) 20 | { 21 | /*如果是第一次,则初始化并分配内存*/ 22 | if (NULL == str) 23 | { 24 | str = (chttp_str_t*) malloc(sizeof(chttp_str_t)); 25 | memset(str, 0, sizeof(chttp_str_t)); 26 | str->data_len = len; 27 | str->buf_size = str->data_len * 2; 28 | 29 | str->data = malloc(str->buf_size); 30 | memset(str->data, 0, str->buf_size); 31 | 32 | memcpy(str->data, cstr, str->data_len); 33 | 34 | return str; 35 | } 36 | 37 | /*如果不是第一次,就检测当前空间是否够大,不够大就增加空间*/ 38 | if (str->buf_size - str->data_len < len) 39 | { 40 | char *temp = NULL; 41 | 42 | do 43 | { 44 | temp = realloc(str->data, str->buf_size + len * 2); 45 | } while (!temp); 46 | 47 | str->data = temp; 48 | str->buf_size += len * 2; 49 | } 50 | 51 | /*把内容增加到缓冲区后面*/ 52 | memcpy(str->data+str->data_len, cstr, len); 53 | str->data_len += len; 54 | 55 | return str; 56 | } 57 | 58 | /*重置字符串,缓冲区清零,内存空间大小不变*/ 59 | void chttp_str_reset(chttp_str_t *str) 60 | { 61 | str->data_len = 0; 62 | memset(str->data, 0, str->buf_size); 63 | } 64 | 65 | /*释放字符串内存*/ 66 | void chttp_str_free(chttp_str_t *str) 67 | { 68 | if (str) 69 | { 70 | if (str->data) 71 | { 72 | free(str->data); 73 | } 74 | free(str); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/cookie.c: -------------------------------------------------------------------------------- 1 | /* 2 | * cookie.c 3 | * 4 | * Created on: 2015年6月9日 5 | * Author: Administrator 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | static chttp_cookie_t* _chttp_cookie_new(const char* key, const char* value); 14 | static int _chttp_cookie_add(chttp_cookie_t** head, chttp_cookie_t* cookie); 15 | 16 | /** 17 | * 用于解析服务端放来的头信息中的cookie 18 | * head: cookie列表的头指针 19 | * header: http响应头信息 20 | * return 0 success 21 | */ 22 | int chttp_cookie_parse(chttp_cookie_t** head, const char* header) 23 | { 24 | int i, j, k; 25 | chttp_cookie_t *cookie = NULL; 26 | 27 | /*如果返回头为空,则不处理,header[0] == 0 这个判断是防止后面 strlen 处理 空字符串的时候导致错误 */ 28 | if (header == NULL || header[0] == 0) 29 | return 1; 30 | 31 | /* 处理类似这种格式的cookie Set-Cookie: q3vF_2132_sid=HtwU4l; expires=Tue, 02-Jun-2015 12:56:53 GMT; path=/ 32 | 查找 Set-Cookie: , 找到每一个cookie*/ 33 | for (i = 0; header[i] != '\0'; i++) 34 | { 35 | if (strncmp("Set-Cookie: ", header + i, 12) == 0) 36 | { 37 | char *key = NULL, *value = NULL; 38 | 39 | /* 40 | * 查找 Set-Cookie: 后面的 = , 这样就可以确定 cookie名称的长度, 41 | */ 42 | for (j = i + 12; 43 | header[j] != '=' && header[j] != '\r' && header[j] != 0; 44 | j++) 45 | ; 46 | 47 | /** 48 | * 查找 = 后面的 ; , 从而确定 cookie值的长度 49 | * 此处要注意处理 这样的cookie:Set-Cookie: noxue=www.zixue7.com 没有分号结尾 是以 \r 结尾 50 | */ 51 | for (k = j + 1; 52 | header[k] != ';' && header[k] != '\r' && header[k] != 0; 53 | k++) 54 | ; 55 | 56 | /*如果key或者value的长度为0 表示cookie为空,那就进行下一次循环。*/ 57 | if (0 == j || 0 == k) 58 | continue; 59 | 60 | key = (char*) calloc(1, j - i - 12 + 1); 61 | value = (char*) calloc(1, k - j - 1 + 1); 62 | 63 | memcpy(key, header + i + 12, j - i - 12); 64 | memcpy(value, header + j + 1, k - j - 1); 65 | 66 | cookie = _chttp_cookie_new(key, value); 67 | _chttp_cookie_add(head, cookie); 68 | 69 | if (key) 70 | free(key); 71 | 72 | if (value) 73 | free(value); 74 | 75 | } 76 | } 77 | 78 | return 0; 79 | } 80 | 81 | /* 82 | * 把两个cookie链表合并,后面的合并到前面。 83 | *cookies 不会被此函数释放掉,需要自己释放 84 | */ 85 | int chttp_cookie_add(chttp_cookie_t *head, chttp_cookie_t *cookies) 86 | { 87 | while (NULL != cookies) 88 | { 89 | _chttp_cookie_add(&head, cookies); 90 | } 91 | return 0; 92 | } 93 | 94 | /** 95 | * 根据cookie名称返回对应的cookie值 96 | * head: cookie列表头指针 97 | * key: cookie的名称 98 | * if 成功就返回cookie内容,否则返回NULL 99 | * 返回的指针不能释放,因为返回的就是cookie节点中的内容 100 | */ 101 | const char* chttp_cookie_get_value(chttp_cookie_t* head, const char* key) 102 | { 103 | chttp_cookie_t *temp = head; 104 | 105 | while (temp != NULL) 106 | { 107 | if (strcmp(temp->key, key) == 0) 108 | { 109 | return temp->value; 110 | } 111 | temp = temp->next; 112 | } 113 | 114 | return NULL; 115 | } 116 | 117 | /** 118 | * 返回这种格式的字符串cookie信息:aaa=bbb; ccc=ddd; eee=fff; 119 | * head: cookie列表的头指针 120 | * 返回cookie字符串的指针【需要释放】 121 | */ 122 | char* chttp_cookie_tostring(chttp_cookie_t* head) 123 | { 124 | char *cookie = NULL; 125 | chttp_cookie_t *temp = head; 126 | size_t len = 0; 127 | 128 | /*计算cookie中内容的长度,为下面分配内存的长度*/ 129 | while (temp != NULL) 130 | { 131 | /*添加 ; = 和空格 这3个字符的长度*/ 132 | len += strlen(temp->key) + strlen(temp->value) + 3; 133 | temp = temp->next; 134 | } 135 | 136 | cookie = (char *) calloc(1, len + 5); 137 | 138 | temp = head; 139 | while (temp != NULL) 140 | { 141 | strcat(cookie, temp->key); 142 | strcat(cookie, "="); 143 | strcat(cookie, temp->value); 144 | strcat(cookie, "; "); 145 | temp = temp->next; 146 | } 147 | 148 | return cookie; 149 | } 150 | 151 | /** 152 | * 销毁cookie列表 153 | * head: cookie列表的头指针 154 | */ 155 | void chttp_cookie_free(chttp_cookie_t* head) 156 | { 157 | chttp_cookie_t *temp = head, *t1 = NULL; 158 | while (temp != NULL) 159 | { 160 | t1 = temp->next; 161 | 162 | free(temp->key); 163 | free(temp->value); 164 | free(temp); 165 | 166 | temp = t1; 167 | } 168 | } 169 | 170 | /** 171 | * 创建一个cookie节点,返回该节点的指针 172 | * key: cookie的名称 173 | * value: cookie的值 174 | * return: 返回cookie节点的指针,需要用户释放(一般是直接加入到列表中,最后一起由cookie_free释放) 175 | */ 176 | static chttp_cookie_t* _chttp_cookie_new(const char* key, const char* value) 177 | { 178 | chttp_cookie_t *cookie = NULL; 179 | if (key == NULL || value == NULL || key[0] == 0 || value[0] == 0) 180 | return NULL; 181 | 182 | cookie = (chttp_cookie_t*) malloc(sizeof(chttp_cookie_t)); 183 | cookie->key = (char *) calloc(1, strlen(key) + 1); 184 | cookie->value = (char *) calloc(1, strlen(value) + 1); 185 | strcpy(cookie->key, key); 186 | strcpy(cookie->value, value); 187 | cookie->next = NULL; 188 | 189 | return cookie; 190 | } 191 | 192 | /** 193 | * 把cookie节点添加到 cookie列表中 194 | * head: cookie列表的头指针【必须初始化为NULL,否则会出错】 195 | * cookie: cookie节点指针 196 | * 成功返回0 197 | */ 198 | static int _chttp_cookie_add(chttp_cookie_t** head, chttp_cookie_t* cookie) 199 | { 200 | chttp_cookie_t *temp = *head; 201 | chttp_cookie_t *prev = NULL; 202 | if (cookie == NULL) 203 | return 1; 204 | 205 | /*如果头指针为NULL 表示是头结点,这也是前面为何必须要初始化为NULL的原因*/ 206 | if (temp == NULL) 207 | { 208 | *head = cookie; 209 | } 210 | else 211 | { 212 | 213 | for (; temp != NULL; temp = temp->next) 214 | { 215 | /*如果存在相同名称的cookie节点,就覆盖他*/ 216 | if (strcmp(temp->key, cookie->key) == 0) 217 | { 218 | 219 | /*保存这个同名的cookie节点指针,方便后面释放*/ 220 | chttp_cookie_t *t = temp; 221 | 222 | /*把同名的节点的next指针赋值给新的节点的next指针*/ 223 | cookie->next = t->next; 224 | /*让同名节点的前面一个节点的next指针指向新的节点*/ 225 | prev->next = cookie; 226 | 227 | /*释放以前的同名节点*/ 228 | free(t->key); 229 | free(t->value); 230 | free(t); 231 | return 0; 232 | } 233 | 234 | /*保存当前循环的节点的前面一个节点,这样后面才能添加*/ 235 | prev = temp; 236 | } 237 | 238 | /*如果没有重名的,就添加到cookie列表的最后面*/ 239 | prev->next = cookie; 240 | } 241 | 242 | return 0; 243 | } 244 | -------------------------------------------------------------------------------- /src/slist.c: -------------------------------------------------------------------------------- 1 | /* 2 | * clist.c 3 | * 4 | * Created on: 2015年6月9日 5 | * Author: Administrator 6 | */ 7 | 8 | #include 9 | 10 | /* 11 | * 向字符串链表中追加字符串 12 | * list 链表头指针,必须初始化为NULL 13 | * 返回字符串链表头指针 14 | */ 15 | chttp_slist_t * chttp_slist_append(chttp_slist_t *list, const char *data) 16 | { 17 | chttp_slist_t *node = NULL, *temp = list; 18 | 19 | node = (chttp_slist_t*) calloc(1, sizeof(chttp_slist_t)); 20 | node->data = (char *) calloc(1, strlen(data) + 1); 21 | node->next = NULL; 22 | strcpy(node->data, data); 23 | 24 | if (NULL == temp) 25 | { 26 | list = node; 27 | } 28 | else 29 | { 30 | /*找到最后一个节点,把新节点追加到最后*/ 31 | for (temp = list; temp->next != NULL; temp = temp->next) 32 | ; 33 | temp->next = node; 34 | } 35 | 36 | return list; 37 | } 38 | 39 | /* 40 | * 释放字符串链表 41 | */ 42 | void chttp_slist_free_all(chttp_slist_t *list) 43 | { 44 | chttp_slist_t *temp = NULL; 45 | while (list) 46 | { 47 | /*保存要释放的节点*/ 48 | temp = list; 49 | list = list->next; 50 | 51 | /*先释放节点中的变量data*/ 52 | free(temp->data); 53 | /*再释放节点*/ 54 | free(temp); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories(./include/ ${CMAKE_SOURCE_DIR}/include/chttp) 2 | 3 | set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin) 4 | 5 | add_executable(slist src/test_slist.c) 6 | add_executable(cookie src/test_cookie.c) 7 | add_executable(http src/test_chttp.c) 8 | add_executable(string src/test_string.c) 9 | 10 | target_link_libraries(slist chttp) 11 | target_link_libraries(cookie chttp) 12 | 13 | 14 | target_link_libraries(http chttp) 15 | target_link_libraries(string chttp) 16 | 17 | 18 | -------------------------------------------------------------------------------- /test/src/test_chttp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * test_chttp.c 3 | * 4 | * Created on: 2015年6月11日 5 | * Author: Administrator 6 | */ 7 | 8 | #include 9 | 10 | /*如果定义了 DEBUG 就会显示出 请求头和返回头*/ 11 | #define DEBUG 1 12 | 13 | int main(int argc, char **argv) 14 | { 15 | 16 | chttp_t *chttp = NULL; 17 | char *temp = NULL; 18 | 19 | chttp = chttp_init(); 20 | 21 | chttp_setopt(chttp, CHTTP_OPT_URL, "http://www.zixue7.com/forum.php"); 22 | chttp_setopt(chttp, CHTTP_OPT_POST, 1); 23 | chttp_setopt(chttp, CHTTP_OPT_DEBUG, 0); 24 | chttp_setopt(chttp, CHTTP_OPT_COOKIE_STR, ""); 25 | chttp_setopt(chttp, CHTTP_OPT_POSTDATA, "content=adminadmin"); 26 | if(NULL==chttp_exec(chttp)) 27 | { 28 | printf("请求失败了\n"); 29 | chttp_free(chttp); 30 | } 31 | 32 | temp = chttp_cookie_tostring(chttp->cookies); 33 | printf("response header:\n%s\n\ncookie:\n%s\n\nhtml:\n%s\n", 34 | chttp->res_header->data, temp, chttp->res_content->data); 35 | 36 | free(temp); 37 | chttp_free(chttp); 38 | 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /test/src/test_cookie.c: -------------------------------------------------------------------------------- 1 | /* 2 | * test_cookie.c 3 | * 4 | * Created on: 2015年6月10日 5 | * Author: Administrator 6 | */ 7 | 8 | #include 9 | 10 | int main(void) 11 | { 12 | chttp_cookie_t *cookie = NULL; 13 | const char *header_str = NULL; 14 | char *cookie_str = NULL; 15 | 16 | header_str = 17 | "HTTP/1.1 200 OK\r\n\ 18 | Date: Wed, 10 Jun 2015 03:32:04 GMT\r\n\ 19 | Server: Apache\r\n\ 20 | Set-Cookie: MANYOU_SESSIONID=366af6d035189ad10749c06dc6a6a587; expires=Wed, 10-Jun-2015 04:32:04 GMT; Path=/; domain=discuz.qq.com\r\n\ 21 | Set-Cookie: MANYOU_AUTH=b4241baf64e1e42ff674ed95d3f7bcbf; expires=Wed, 10-Jun-2015 04:32:04 GMT; Path=/; domain=discuz.qq.com\r\n\ 22 | Set-Cookie: MANYOU_DATA=fultUO73AtTbaa%2B4kghyZ2agYN%2B7a7HRMVtsbZfEdOKQ8foUD8usNVyiLMSTHo9mtCLOWI7Dsp%2BUmPed2kvE2Q%3D%3D; expires=Wed, 10-Jun-2015 04:32:04 GMT; Path=/; domain=discuz.qq.com\r\n\ 23 | Cache-Control: max-age=0\r\n\ 24 | Expires: Wed, 10 Jun 2015 03:32:04 GMT\r\n\ 25 | Content-Length: 197\r\n\ 26 | Connection: close\r\n\ 27 | Content-Type: text/javascript; charset=utf-8"; 28 | 29 | chttp_cookie_parse(&cookie, header_str); 30 | 31 | cookie_str = chttp_cookie_tostring(cookie); 32 | 33 | printf("cookie:\n%s\n\nMANYOU_SESSIONID:%s\n\n", cookie_str, chttp_cookie_get_value(cookie, "MANYOU_SESSIONID")); 34 | 35 | free(cookie_str); 36 | 37 | chttp_cookie_free(cookie); 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /test/src/test_slist.c: -------------------------------------------------------------------------------- 1 | /* 2 | * test.c 3 | * 4 | * Created on: 2015年6月10日 5 | * Author: Administrator 6 | */ 7 | 8 | 9 | #include 10 | 11 | int main(void) 12 | { 13 | chttp_slist_t *strs=NULL, *pstrs=NULL; 14 | 15 | strs = chttp_slist_append(strs, "admin"); 16 | strs = chttp_slist_append(strs, "root"); 17 | strs = chttp_slist_append(strs, "admin"); 18 | 19 | for(pstrs=strs; pstrs!=NULL; pstrs=pstrs->next) 20 | { 21 | printf("%s\n", pstrs->data); 22 | } 23 | 24 | chttp_slist_free_all(strs); 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /test/src/test_string.c: -------------------------------------------------------------------------------- 1 | /* 2 | * test_string.c 3 | * 4 | * Created on: 2015年6月12日 5 | * Author: Administrator 6 | */ 7 | 8 | 9 | #include 10 | 11 | int main(void) 12 | { 13 | chttp_str_t *str =NULL; 14 | 15 | str = chttp_str_append(str, "www.zixue7.com"); 16 | str = chttp_str_append(str, "www.zixue7.com"); 17 | 18 | printf("%s", str->data); 19 | 20 | chttp_str_free(str); 21 | 22 | return 0; 23 | } 24 | --------------------------------------------------------------------------------