1 /*
2 Copyright (c) 2008-2013 uim Project https://github.com/uim/uim
3
4 All rights reserved.
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
9
10 1. Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15 3. Neither the name of authors nor the names of its contributors
16 may be used to endorse or promote products derived from this software
17 without specific prior written permission.
18
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
20 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
23 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 SUCH DAMAGE.
30
31 */
32
33 #include <config.h>
34
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38 #include <stdio.h>
39
40 #include <curl/curl.h>
41
42 #include "uim.h"
43 #include "uim-scm.h"
44 #include "uim-scm-abbrev.h"
45 #include "gettext.h"
46 #include "dynlib.h"
47
48
49 #ifdef DEBUG
50 #define DPRINTFN(n,x) if ((n) <= verbose_level()) fprintf x;
51 #else
52 #define DPRINTFN(n,x)
53 #endif
54
55 static uim_lisp uim_curl_fetch_simple(uim_lisp);
56 static void *uim_curl_fetch_simple_internal(void *);
57
58 struct uim_curl_post_args {
59 uim_lisp url;
60 uim_lisp post;
61 };
62 static uim_lisp uim_curl_post(uim_lisp, uim_lisp);
63 static void *uim_curl_post_internal(struct uim_curl_post_args *);
64
65 static uim_lisp uim_curl_url_escape(uim_lisp);
66 static void *uim_curl_url_escape_internal(void *);
67
68 static uim_lisp uim_curl_url_unescape(uim_lisp);
69 static void *uim_curl_url_unescape_internal(void *);
70
71 void uim_plugin_instance_init(void);
72 void uim_plugin_instance_quit(void);
73
74 struct curl_memory_struct {
75 char *str;
76 size_t size;
77 };
78 static size_t uim_curl_write_func(void *, size_t, size_t, void *);
79 static CURLcode uim_curl_perform(CURL *);
80
81 static size_t
uim_curl_write_func(void * ptr,size_t size,size_t nmemb,void * data)82 uim_curl_write_func(void *ptr, size_t size, size_t nmemb, void *data)
83 {
84 struct curl_memory_struct *mem = (struct curl_memory_struct *)data;
85 size_t realsize = size * nmemb;
86
87 /*
88 * We know that it isn't possible to overflow during multiplication if
89 * neither operand uses any of the most significant half of the bits in
90 * a size_t.
91 */
92 if((unsigned long long)((nmemb | size) &
93 ((unsigned long long)SIZE_MAX << (sizeof(size_t) << 2))) &&
94 (realsize / size != nmemb))
95 return 0;
96
97 if(SIZE_MAX - mem->size - 1 < realsize)
98 realsize = SIZE_MAX - mem->size - 1;
99
100 if(mem->str != NULL)
101 mem->str = uim_realloc(mem->str, mem->size + realsize + 1);
102 else
103 mem->str = uim_malloc(realsize + 1);
104
105 if(mem->str != NULL) {
106 memcpy(&(mem->str[mem->size]), ptr, realsize);
107 mem->size += realsize;
108 mem->str[mem->size] = '\0';
109 }
110
111 return realsize;
112 }
113
114 static uim_lisp
uim_curl_fetch_simple(uim_lisp url_)115 uim_curl_fetch_simple(uim_lisp url_)
116 {
117 return (uim_lisp)uim_scm_call_with_gc_ready_stack((uim_gc_gate_func_ptr)uim_curl_fetch_simple_internal,
118 (void *)url_);
119 }
120
121 static void *
uim_curl_fetch_simple_internal(void * url_)122 uim_curl_fetch_simple_internal(void *url_)
123 {
124 const char *url = REFER_C_STR((uim_lisp)url_);
125 CURL *curl;
126 CURLcode res;
127 struct curl_memory_struct chunk;
128 uim_lisp fetched_str_;
129
130 curl = curl_easy_init();
131
132 if(curl == NULL)
133 return uim_scm_f();
134
135 memset(&chunk, 0, sizeof(struct curl_memory_struct));
136
137 curl_easy_setopt(curl, CURLOPT_URL, url);
138 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, uim_curl_write_func);
139 curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
140
141 res = uim_curl_perform(curl);
142
143 fetched_str_ = (chunk.str != NULL) ? MAKE_STR(chunk.str) : uim_scm_f();
144
145 curl_easy_cleanup(curl);
146 curl_global_cleanup();
147 free(chunk.str);
148
149 return (void *)fetched_str_;
150 }
151
152 static CURLcode
uim_curl_perform(CURL * curl)153 uim_curl_perform(CURL *curl)
154 {
155 uim_bool use_proxy;
156 char *ua;
157 char *referer;
158 char *http_proxy;
159 CURLcode res;
160
161 ua = uim_scm_symbol_value_str("uim-curl-user-agent");
162 referer = uim_scm_symbol_value_str("uim-curl-referer");
163 use_proxy = uim_scm_symbol_value_bool("uim-curl-use-proxy?");
164 http_proxy = uim_scm_symbol_value_str("uim-curl-http-proxy");
165
166 curl_easy_setopt(curl, CURLOPT_USERAGENT,
167 (ua != NULL) ? ua : "libcurl-agent/1.0");
168 curl_easy_setopt(curl, CURLOPT_REFERER,
169 (referer != NULL) ? referer : "");
170 if (use_proxy) {
171 curl_easy_setopt(curl, CURLOPT_PROXY,
172 (http_proxy != NULL) ? http_proxy : "");
173 }
174
175 res = curl_easy_perform(curl);
176
177 free(ua);
178 free(referer);
179 free(http_proxy);
180
181 return res;
182 }
183
184 static uim_lisp
uim_curl_post(uim_lisp url_,uim_lisp post_)185 uim_curl_post(uim_lisp url_, uim_lisp post_)
186 {
187 struct uim_curl_post_args args;
188
189 args.url = url_;
190 args.post = post_;
191 return (uim_lisp)uim_scm_call_with_gc_ready_stack((uim_gc_gate_func_ptr)uim_curl_post_internal,
192 &args);
193 }
194
195 static void *
uim_curl_post_internal(struct uim_curl_post_args * args)196 uim_curl_post_internal(struct uim_curl_post_args *args)
197 {
198 uim_lisp post_ = args->post;
199 uim_lisp post_car_, post_cdr_;
200 uim_lisp fetched_str_;
201 const char *url = REFER_C_STR(args->url);
202 CURL *curl;
203 CURLcode res;
204 struct curl_memory_struct chunk;
205 struct curl_httppost* post_first = NULL;
206 struct curl_httppost* post_last = NULL;
207
208 curl = curl_easy_init();
209
210 if(curl == NULL)
211 return uim_scm_f();
212
213 memset(&chunk, 0, sizeof(struct curl_memory_struct));
214
215 curl_easy_setopt(curl, CURLOPT_URL, url);
216 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, uim_curl_write_func);
217 curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
218
219 for(post_cdr_ = post_;
220 !NULLP(post_cdr_);
221 post_cdr_ = CDR(post_cdr_)) {
222 const char *name, *value;
223 post_car_ = CAR(post_cdr_);
224
225 name = REFER_C_STR(CAR(post_car_));
226 value = REFER_C_STR(CDR(post_car_));
227
228 curl_formadd(&post_first, &post_last,
229 CURLFORM_COPYNAME, name,
230 CURLFORM_COPYCONTENTS, value,
231 CURLFORM_END);
232 }
233
234 curl_easy_setopt(curl, CURLOPT_HTTPPOST, post_first);
235
236 res = uim_curl_perform(curl);
237
238 fetched_str_ = (chunk.str != NULL) ? MAKE_STR(chunk.str) : uim_scm_f();
239
240 curl_easy_cleanup(curl);
241 curl_formfree(post_first);
242 curl_global_cleanup();
243 free(chunk.str);
244
245 return (void *)fetched_str_;
246 }
247
248 static uim_lisp
uim_curl_url_escape(uim_lisp url_)249 uim_curl_url_escape(uim_lisp url_)
250 {
251 return (uim_lisp)uim_scm_call_with_gc_ready_stack((uim_gc_gate_func_ptr)uim_curl_url_escape_internal,
252 (void *)url_);
253 }
254 static void *
uim_curl_url_escape_internal(void * url_)255 uim_curl_url_escape_internal(void *url_)
256 {
257 uim_lisp escaped_url_;
258 const char *unescaped_url = REFER_C_STR((uim_lisp)url_);
259 char *escaped_url;
260 CURL *curl;
261
262 curl = curl_easy_init();
263
264 if(curl == NULL)
265 return uim_scm_f();
266
267 escaped_url = curl_easy_escape(curl, unescaped_url, strlen(unescaped_url));
268 escaped_url_ = (escaped_url != NULL) ? MAKE_STR(escaped_url) : uim_scm_f();
269
270 curl_free(escaped_url);
271 curl_easy_cleanup(curl);
272 curl_global_cleanup();
273
274 return (void *)escaped_url_;
275 }
276
277 static uim_lisp
uim_curl_url_unescape(uim_lisp url_)278 uim_curl_url_unescape(uim_lisp url_)
279 {
280 return (uim_lisp)uim_scm_call_with_gc_ready_stack((uim_gc_gate_func_ptr)uim_curl_url_unescape_internal,
281 (void *)url_);
282 }
283
284 static void *
uim_curl_url_unescape_internal(void * url_)285 uim_curl_url_unescape_internal(void *url_)
286 {
287 uim_lisp unescaped_url_;
288 const char *escaped_url = REFER_C_STR((uim_lisp)url_);
289 char *unescaped_url;
290 int len; /* curl_easy_unescape uses int, not size_t */
291 CURL *curl;
292
293 curl = curl_easy_init();
294
295 if(curl == NULL)
296 return uim_scm_f();
297
298 unescaped_url = curl_easy_unescape(curl, escaped_url,
299 strlen(escaped_url), &len);
300 unescaped_url_ = (len > 0) ? MAKE_STR(unescaped_url) : uim_scm_f();
301
302 curl_free(unescaped_url);
303 curl_easy_cleanup(curl);
304 curl_global_cleanup();
305
306 return (void *)unescaped_url_;
307 }
308
uim_plugin_instance_init(void)309 void uim_plugin_instance_init(void)
310 {
311 uim_scm_init_proc1("curl-fetch-simple", uim_curl_fetch_simple);
312 uim_scm_init_proc1("curl-url-escape", uim_curl_url_escape);
313 uim_scm_init_proc1("curl-url-unescape", uim_curl_url_unescape);
314 uim_scm_init_proc2("curl-post", uim_curl_post);
315 }
316
uim_plugin_instance_quit(void)317 void uim_plugin_instance_quit(void)
318 {
319 return;
320 }
321