-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathlxhttp.cc
216 lines (183 loc) · 5.86 KB
/
lxhttp.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
#include "xlualib.h"
#define CURL_STATICLIB
#include <curl/curl.h>
#pragma comment(lib, "curl")
#include <map>
#include <vector>
#include <regex>
using std::string;
using std::map;
using std::regex;
using std::smatch;
using std::vector;
//////////////////////////////////////////////////////////////////////////
static size_t xhttp_header_callback(void* ptr, size_t size, size_t nmemb, void* stream)
{
const size_t len = size * nmemb;
map<string, string>& mp = *(map<string, string>*)stream;
string header((const char*)ptr, len);
smatch sm;
regex re("([^:]+?):\\s*(.*?)\\r\\n");
if(regex_match(header, sm, re))
{
mp[sm[1]] = sm[2];
}
return size * nmemb;
}
static size_t xhttp_body_callback(void* ptr, size_t size, size_t nmemb, void* stream)
{
const size_t len = size * nmemb;
string& str = *(string*)stream;
str.append((const char*)ptr, len);
return size * nmemb;
}
static int LUA_C_xhttp(lua_State* ls)
{
//取URL
const char* url = luaL_checkstring(ls, 1);
//初始化CURL
CURL* curl = curl_easy_init();
if(curl == nullptr)
{
return luaL_error(ls, "xhttp - curl_easy_init失败");
}
//初始化header组并预先删除Expect项
struct curl_slist* headers = nullptr;
headers = curl_slist_append(headers, "Expect:");
vector<string> header;
size_t connect_time_out = 20000; //默认连接超时
size_t time_out = 10000; //默认超时
bool post = false; //当配置data项存在时,为post请求
string data; //post数据
bool verbose = false; //细节展示
string proxy;
const int top = lua_gettop(ls);
//如果提供配置则读取之
if(!lua_isnoneornil(ls, 2))
{
lua_settop(ls, top);
//配置必须为表
luaL_checktype(ls, 2, LUA_TTABLE);
//配置可能存在的连接超时
lua_pushstring(ls, "connect_time_out");
lua_gettable(ls, 2);
connect_time_out = luaL_optinteger(ls, -1, connect_time_out);
lua_settop(ls, top);
//配置可能存在的超时
lua_pushstring(ls, "time_out");
lua_gettable(ls, 2);
time_out = luaL_optinteger(ls, -1, time_out);
lua_settop(ls, top);
//配置可能存在的代理
lua_pushstring(ls, "proxy");
lua_gettable(ls, 2);
proxy.assign(luaL_optstring(ls, -1, ""));
lua_settop(ls, top);
//data项存在时,获取之
lua_pushstring(ls, "data");
lua_gettable(ls, 2);
if(!lua_isnil(ls, -1))
{
size_t l = 0;
const char* buf = luaL_checklstring(ls, -1, &l);
post = true;
data.append(buf, l);
}
lua_settop(ls, top);
//配置可能存在的verbose
lua_pushstring(ls, "verbose");
lua_gettable(ls, 2);
verbose = lua_toboolean(ls, -1);
lua_settop(ls, top);
//读取可能存在的header,header必须是表
lua_pushstring(ls, "header");
lua_gettable(ls, 2);
if(!lua_isnil(ls, -1))
{
luaL_checktype(ls, -1, LUA_TTABLE);
lua_pushnil(ls); //第一个键
while(lua_next(ls, -2) != 0)
{
lua_pushvalue(ls, -2); //复制键到栈顶,此时栈:键、值、键
lua_insert(ls, -2); //把键放在值前,此时栈:键、键、值
lua_pushstring(ls, ": "); //此时栈:键、键、值、": "
lua_insert(ls, -2); //位置调整,此时栈:键、键、": "、值
lua_concat(ls, 3); //组织,出栈,此时栈:键、"xxxxx"
const string ss(lua_tostring(ls, -1));
header.push_back(ss);
lua_pop(ls, 1); //保留键,此时栈:键
}
}
lua_settop(ls, top);
}
string repbody;
map<string, string> repheader;
//URL
curl_easy_setopt(curl, CURLOPT_URL, url);
//超时
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, connect_time_out);
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, time_out);
//代理
if(!proxy.empty())
{
curl_easy_setopt(curl, CURLOPT_PROXY, proxy.c_str());
}
//响应头
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, xhttp_header_callback);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, &repheader);
//响应体
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, xhttp_body_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &repbody);
//压入请求头
for(const auto& ss : header)
{
headers = curl_slist_append(headers, ss.c_str());
}
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
//如果是post请求,则设置post
if(post)
{
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, data.size());
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
}
//错误细节展示
curl_easy_setopt(curl, CURLOPT_VERBOSE, verbose ? 1 : 0);
//运行之
CURLcode res = curl_easy_perform(curl);
//立即删除请求头
curl_slist_free_all(headers);
if(res != CURLE_OK)
{
lua_pushfstring(ls, "xhttp访问出错[%d] : %s", res, curl_easy_strerror(res));
curl_easy_cleanup(curl);
return lua_error(ls);
}
long code = 0;
res = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
if(res != CURLE_OK)
{
lua_pushfstring(ls, "xhttp返回出错[%d] : %s", res, curl_easy_strerror(res));
curl_easy_cleanup(curl);
return lua_error(ls);
}
curl_easy_cleanup(curl);
//返回值入栈
lua_pushnumber(ls, code);
lua_newtable(ls);
for(const auto& v : repheader)
{
lua_pushlstring(ls, v.first.c_str(), v.first.size());
lua_pushlstring(ls, v.second.c_str(), v.second.size());
lua_settable(ls, -3);
}
lua_pushlstring(ls, repbody.c_str(), repbody.size());
return 3;
}
//////////////////////////////////////////////////////////////////////////
void register_xhttp(lua_State* ls)
{
lua_pop(ls, lua_gettop(ls));
lua_register(ls, "xhttp", LUA_C_xhttp);
lua_pop(ls, lua_gettop(ls));
}