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