├── .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 |
--------------------------------------------------------------------------------