1 /**
2 * \file curl_utils.c
3 * \brief curl utilities for the http library.
4 * \author Copyright (c) 2017 Tom van Dijck, Jo�o Matos and the Premake project
5 */
6 #ifdef PREMAKE_CURL
7
8 #include "curl_utils.h"
9 #include "premake.h"
10 #include <string.h>
11
curlProgressCallback(curl_state * state,double dltotal,double dlnow,double ultotal,double ulnow)12 int curlProgressCallback(curl_state* state, double dltotal, double dlnow, double ultotal, double ulnow)
13 {
14 lua_State* L = state->L;
15
16 (void)ultotal;
17 (void)ulnow;
18
19 if (dltotal == 0) return 0;
20
21 /* retrieve the lua progress callback we saved before */
22 lua_rawgeti(L, LUA_REGISTRYINDEX, state->RefIndex);
23 lua_pushnumber(L, (lua_Number)dltotal);
24 lua_pushnumber(L, (lua_Number)dlnow);
25 lua_pcall(L, 2, LUA_MULTRET, 0);
26
27 return 0;
28 }
29
30
curlWriteCallback(char * ptr,size_t size,size_t nmemb,curl_state * state)31 size_t curlWriteCallback(char *ptr, size_t size, size_t nmemb, curl_state* state)
32 {
33 size_t length = size * nmemb;
34 buffer_puts(&state->S, ptr, length);
35 return length;
36 }
37
38
curl_init()39 static void curl_init()
40 {
41 static int initializedHTTP = 0;
42
43 if (initializedHTTP)
44 return;
45
46 curl_global_init(CURL_GLOBAL_ALL);
47 atexit(curl_global_cleanup);
48 initializedHTTP = 1;
49 }
50
51
get_headers(lua_State * L,int headersIndex,struct curl_slist ** headers)52 static void get_headers(lua_State* L, int headersIndex, struct curl_slist** headers)
53 {
54 lua_pushnil(L);
55 while (lua_next(L, headersIndex) != 0)
56 {
57 const char *item = luaL_checkstring(L, -1);
58 lua_pop(L, 1);
59 *headers = curl_slist_append(*headers, item);
60 }
61 }
62
63
curlRequest(lua_State * L,curl_state * state,int optionsIndex,int progressFnIndex,int headersIndex)64 CURL* curlRequest(lua_State* L, curl_state* state, int optionsIndex, int progressFnIndex, int headersIndex)
65 {
66 char agent[1024];
67 CURL* curl;
68
69 state->L = 0;
70 state->RefIndex = 0;
71 state->errorBuffer[0] = '\0';
72 state->headers = NULL;
73 buffer_init(&state->S);
74
75 curl_init();
76 curl = curl_easy_init();
77
78 if (!curl)
79 return NULL;
80
81 strcpy(agent, "Premake/");
82 strcat(agent, PREMAKE_VERSION);
83
84 curl_easy_setopt(curl, CURLOPT_URL, luaL_checkstring(L, 1));
85 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
86 curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
87 curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
88 curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, state->errorBuffer);
89 curl_easy_setopt(curl, CURLOPT_USERAGENT, agent);
90
91 // check if the --insecure option was specified on the commandline.
92 lua_getglobal(L, "_OPTIONS");
93 lua_pushstring(L, "insecure");
94 lua_gettable(L, -2);
95 if (!lua_isnil(L, -1))
96 {
97 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
98 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
99 }
100 lua_pop(L, 2);
101
102 // apply all other options.
103 if (optionsIndex && lua_istable(L, optionsIndex))
104 {
105 lua_pushnil(L);
106 while (lua_next(L, optionsIndex) != 0)
107 {
108 const char* key = luaL_checkstring(L, -2);
109
110 if (!strcmp(key, "headers") && lua_istable(L, -1))
111 {
112 get_headers(L, lua_gettop(L), &state->headers);
113 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, state->headers);
114 }
115 else if (!strcmp(key, "progress") && lua_isfunction(L, -1))
116 {
117 state->L = L;
118 lua_pushvalue(L, -1);
119 state->RefIndex = luaL_ref(L, LUA_REGISTRYINDEX);
120 }
121 else if (!strcmp(key, "userpwd") && lua_isstring(L, -1))
122 {
123 curl_easy_setopt(curl, CURLOPT_USERPWD, luaL_checkstring(L, -1));
124 }
125 else if (!strcmp(key, "username") && lua_isstring(L, -1))
126 {
127 curl_easy_setopt(curl, CURLOPT_USERNAME, luaL_checkstring(L, -1));
128 }
129 else if (!strcmp(key, "password") && lua_isstring(L, -1))
130 {
131 curl_easy_setopt(curl, CURLOPT_PASSWORD, luaL_checkstring(L, -1));
132 }
133 else if (!strcmp(key, "timeout") && lua_isnumber(L, -1))
134 {
135 curl_easy_setopt(curl, CURLOPT_TIMEOUT, (long)luaL_checknumber(L, -1));
136 }
137 else if (!strcmp(key, "timeoutms") && lua_isnumber(L, -1))
138 {
139 curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, (long)luaL_checknumber(L, -1));
140 }
141 else if (!strcmp(key, "sslverifyhost") && lua_isnumber(L, -1))
142 {
143 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, (long)luaL_checknumber(L, -1));
144 }
145 else if (!strcmp(key, "sslverifypeer") && lua_isnumber(L, -1))
146 {
147 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, (long)luaL_checknumber(L, -1));
148 }
149 else if (!strcmp(key, "proxyurl") && lua_isstring(L, -1))
150 {
151 curl_easy_setopt(curl, CURLOPT_PROXY, luaL_checkstring(L, -1));
152 }
153
154 // pop the value, leave the key for lua_next
155 lua_pop(L, 1);
156 }
157 }
158 else
159 {
160 if (progressFnIndex && lua_type(L, progressFnIndex) == LUA_TFUNCTION)
161 {
162 state->L = L;
163 lua_pushvalue(L, progressFnIndex);
164 state->RefIndex = luaL_ref(L, LUA_REGISTRYINDEX);
165 }
166
167 if (headersIndex && lua_istable(L, headersIndex))
168 {
169 get_headers(L, headersIndex, &state->headers);
170 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, state->headers);
171 }
172 }
173
174 curl_easy_setopt(curl, CURLOPT_WRITEDATA, state);
175 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlWriteCallback);
176
177 if (state->L != 0)
178 {
179 curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
180 curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, state);
181 curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, curlProgressCallback);
182 }
183
184 // clear error buffer.
185 state->errorBuffer[0] = 0;
186
187 return curl;
188 }
189
190
191
curlCleanup(CURL * curl,curl_state * state)192 void curlCleanup(CURL* curl, curl_state* state)
193 {
194 if (state->headers)
195 {
196 curl_slist_free_all(state->headers);
197 state->headers = 0;
198 }
199 curl_easy_cleanup(curl);
200 }
201
202
203 #endif
204