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