1 /* purple
2 *
3 * Purple is the legal property of its developers, whose names are too numerous
4 * to list here. Please refer to the COPYRIGHT file distributed with this
5 * source distribution.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
20 */
21
22 #include "internal.h"
23
24 #include <string.h>
25
26 #include "http.h"
27
28 struct _FbHttpConns
29 {
30 GHashTable *cons;
31 gboolean canceled;
32 };
33
34 GQuark
fb_http_error_quark(void)35 fb_http_error_quark(void)
36 {
37 static GQuark q = 0;
38
39 if (G_UNLIKELY(q == 0)) {
40 q = g_quark_from_static_string("fb-http-error-quark");
41 }
42
43 return q;
44 }
45
46 FbHttpConns *
fb_http_conns_new(void)47 fb_http_conns_new(void)
48 {
49 FbHttpConns *cons;
50
51 cons = g_new0(FbHttpConns, 1);
52 cons->cons = g_hash_table_new(g_direct_hash, g_direct_equal);
53 return cons;
54 }
55
56 void
fb_http_conns_free(FbHttpConns * cons)57 fb_http_conns_free(FbHttpConns *cons)
58 {
59 g_return_if_fail(cons != NULL);
60
61 g_hash_table_destroy(cons->cons);
62 g_free(cons);
63 }
64
65 void
fb_http_conns_cancel_all(FbHttpConns * cons)66 fb_http_conns_cancel_all(FbHttpConns *cons)
67 {
68 GHashTableIter iter;
69 gpointer con;
70
71 g_return_if_fail(cons != NULL);
72 g_return_if_fail(!cons->canceled);
73
74 cons->canceled = TRUE;
75 g_hash_table_iter_init(&iter, cons->cons);
76
77 while (g_hash_table_iter_next(&iter, &con, NULL)) {
78 g_hash_table_iter_remove(&iter);
79 purple_http_conn_cancel(con);
80 }
81 }
82
83 gboolean
fb_http_conns_is_canceled(FbHttpConns * cons)84 fb_http_conns_is_canceled(FbHttpConns *cons)
85 {
86 g_return_val_if_fail(cons != NULL, TRUE);
87 return cons->canceled;
88 }
89
90 void
fb_http_conns_add(FbHttpConns * cons,PurpleHttpConnection * con)91 fb_http_conns_add(FbHttpConns *cons, PurpleHttpConnection *con)
92 {
93 g_return_if_fail(cons != NULL);
94 g_return_if_fail(!cons->canceled);
95 g_hash_table_replace(cons->cons, con, con);
96 }
97
98 void
fb_http_conns_remove(FbHttpConns * cons,PurpleHttpConnection * con)99 fb_http_conns_remove(FbHttpConns *cons, PurpleHttpConnection *con)
100 {
101 g_return_if_fail(cons != NULL);
102 g_return_if_fail(!cons->canceled);
103 g_hash_table_remove(cons->cons, con);
104 }
105
106 void
fb_http_conns_reset(FbHttpConns * cons)107 fb_http_conns_reset(FbHttpConns *cons)
108 {
109 g_return_if_fail(cons != NULL);
110 cons->canceled = FALSE;
111 g_hash_table_remove_all(cons->cons);
112 }
113
114 gboolean
fb_http_error_chk(PurpleHttpResponse * res,GError ** error)115 fb_http_error_chk(PurpleHttpResponse *res, GError **error)
116 {
117 const gchar *msg;
118 gint code;
119
120 if (purple_http_response_is_successful(res)) {
121 return TRUE;
122 }
123
124 msg = purple_http_response_get_error(res);
125 code = purple_http_response_get_code(res);
126 g_set_error(error, FB_HTTP_ERROR, code, "%s", msg);
127 return FALSE;
128 }
129
130 FbHttpParams *
fb_http_params_new(void)131 fb_http_params_new(void)
132 {
133 return g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
134 }
135
136 FbHttpParams *
fb_http_params_new_parse(const gchar * data,gboolean isurl)137 fb_http_params_new_parse(const gchar *data, gboolean isurl)
138 {
139 const gchar *tail;
140 gchar *key;
141 gchar **ps;
142 gchar *val;
143 guint i;
144 FbHttpParams *params;
145
146 params = fb_http_params_new();
147
148 if (data == NULL) {
149 return params;
150 }
151
152 if (isurl) {
153 data = strchr(data, '?');
154
155 if (data == NULL) {
156 return params;
157 }
158
159 tail = strchr(++data, '#');
160
161 if (tail != NULL) {
162 data = g_strndup(data, tail - data);
163 } else {
164 data = g_strdup(data);
165 }
166 }
167
168 ps = g_strsplit(data, "&", 0);
169
170 for (i = 0; ps[i] != NULL; i++) {
171 key = ps[i];
172 val = strchr(ps[i], '=');
173
174 if (val == NULL) {
175 continue;
176 }
177
178 *(val++) = 0;
179 key = g_uri_unescape_string(key, NULL);
180 val = g_uri_unescape_string(val, NULL);
181 g_hash_table_replace(params, key, val);
182 }
183
184 if (isurl) {
185 g_free((gchar *) data);
186 }
187
188 g_strfreev(ps);
189 return params;
190 }
191
192 void
fb_http_params_free(FbHttpParams * params)193 fb_http_params_free(FbHttpParams *params)
194 {
195 g_hash_table_destroy(params);
196 }
197
198 gchar *
fb_http_params_close(FbHttpParams * params,const gchar * url)199 fb_http_params_close(FbHttpParams *params, const gchar *url)
200 {
201 GHashTableIter iter;
202 gpointer key;
203 gpointer val;
204 GString *ret;
205
206 g_hash_table_iter_init(&iter, params);
207 ret = g_string_new(NULL);
208
209 while (g_hash_table_iter_next(&iter, &key, &val)) {
210 if (val == NULL) {
211 g_hash_table_iter_remove(&iter);
212 continue;
213 }
214
215 if (ret->len > 0) {
216 g_string_append_c(ret, '&');
217 }
218
219 g_string_append_uri_escaped(ret, key, NULL, TRUE);
220 g_string_append_c(ret, '=');
221 g_string_append_uri_escaped(ret, val, NULL, TRUE);
222 }
223
224 if (url != NULL) {
225 g_string_prepend_c(ret, '?');
226 g_string_prepend(ret, url);
227 }
228
229 fb_http_params_free(params);
230 return g_string_free(ret, FALSE);
231 }
232
233 static const gchar *
fb_http_params_get(FbHttpParams * params,const gchar * name,GError ** error)234 fb_http_params_get(FbHttpParams *params, const gchar *name, GError **error)
235 {
236 const gchar *ret;
237
238 ret = g_hash_table_lookup(params, name);
239
240 if (ret == NULL) {
241 g_set_error(error, FB_HTTP_ERROR, FB_HTTP_ERROR_NOMATCH,
242 _("No matches for %s"), name);
243 return NULL;
244 }
245
246 return ret;
247 }
248
249 gboolean
fb_http_params_get_bool(FbHttpParams * params,const gchar * name,GError ** error)250 fb_http_params_get_bool(FbHttpParams *params, const gchar *name,
251 GError **error)
252 {
253 const gchar *val;
254
255 val = fb_http_params_get(params, name, error);
256
257 if (val == NULL) {
258 return FALSE;
259 }
260
261 return g_ascii_strcasecmp(val, "TRUE") == 0;
262 }
263
264 gdouble
fb_http_params_get_dbl(FbHttpParams * params,const gchar * name,GError ** error)265 fb_http_params_get_dbl(FbHttpParams *params, const gchar *name,
266 GError **error)
267 {
268 const gchar *val;
269
270 val = fb_http_params_get(params, name, error);
271
272 if (val == NULL) {
273 return 0.0;
274 }
275
276 return g_ascii_strtod(val, NULL);
277 }
278
279 gint64
fb_http_params_get_int(FbHttpParams * params,const gchar * name,GError ** error)280 fb_http_params_get_int(FbHttpParams *params, const gchar *name,
281 GError **error)
282 {
283 const gchar *val;
284
285 val = fb_http_params_get(params, name, error);
286
287 if (val == NULL) {
288 return 0;
289 }
290
291 return g_ascii_strtoll(val, NULL, 10);
292 }
293
294 const gchar *
fb_http_params_get_str(FbHttpParams * params,const gchar * name,GError ** error)295 fb_http_params_get_str(FbHttpParams *params, const gchar *name,
296 GError **error)
297 {
298 return fb_http_params_get(params, name, error);
299 }
300
301 gchar *
fb_http_params_dup_str(FbHttpParams * params,const gchar * name,GError ** error)302 fb_http_params_dup_str(FbHttpParams *params, const gchar *name,
303 GError **error)
304 {
305 const gchar *str;
306
307 str = fb_http_params_get(params, name, error);
308 return g_strdup(str);
309 }
310
311 static void
fb_http_params_set(FbHttpParams * params,const gchar * name,gchar * value)312 fb_http_params_set(FbHttpParams *params, const gchar *name, gchar *value)
313 {
314 gchar *key;
315
316 key = g_strdup(name);
317 g_hash_table_replace(params, key, value);
318 }
319
320 void
fb_http_params_set_bool(FbHttpParams * params,const gchar * name,gboolean value)321 fb_http_params_set_bool(FbHttpParams *params, const gchar *name,
322 gboolean value)
323 {
324 gchar *val;
325
326 val = g_strdup(value ? "true" : "false");
327 fb_http_params_set(params, name, val);
328 }
329
330 void
fb_http_params_set_dbl(FbHttpParams * params,const gchar * name,gdouble value)331 fb_http_params_set_dbl(FbHttpParams *params, const gchar *name, gdouble value)
332 {
333 gchar *val;
334
335 val = g_strdup_printf("%f", value);
336 fb_http_params_set(params, name, val);
337 }
338
339 void
fb_http_params_set_int(FbHttpParams * params,const gchar * name,gint64 value)340 fb_http_params_set_int(FbHttpParams *params, const gchar *name, gint64 value)
341 {
342 gchar *val;
343
344 val = g_strdup_printf("%" G_GINT64_FORMAT, value);
345 fb_http_params_set(params, name, val);
346 }
347
348 void
fb_http_params_set_str(FbHttpParams * params,const gchar * name,const gchar * value)349 fb_http_params_set_str(FbHttpParams *params, const gchar *name,
350 const gchar *value)
351 {
352 gchar *val;
353
354 val = g_strdup(value);
355 fb_http_params_set(params, name, val);
356 }
357
358 void
fb_http_params_set_strf(FbHttpParams * params,const gchar * name,const gchar * format,...)359 fb_http_params_set_strf(FbHttpParams *params, const gchar *name,
360 const gchar *format, ...)
361 {
362 gchar *val;
363 va_list ap;
364
365 va_start(ap, format);
366 val = g_strdup_vprintf(format, ap);
367 va_end(ap);
368
369 fb_http_params_set(params, name, val);
370 }
371
372 gboolean
fb_http_urlcmp(const gchar * url1,const gchar * url2,gboolean protocol)373 fb_http_urlcmp(const gchar *url1, const gchar *url2, gboolean protocol)
374 {
375 const gchar *str1;
376 const gchar *str2;
377 gboolean ret = TRUE;
378 gint int1;
379 gint int2;
380 guint i;
381 PurpleHttpURL *purl1;
382 PurpleHttpURL *purl2;
383
384 static const gchar * (*funcs[]) (const PurpleHttpURL *url) = {
385 /* Always first so it can be skipped */
386 purple_http_url_get_protocol,
387
388 purple_http_url_get_fragment,
389 purple_http_url_get_host,
390 purple_http_url_get_password,
391 purple_http_url_get_path,
392 purple_http_url_get_username
393 };
394
395 if ((url1 == NULL) || (url2 == NULL)) {
396 return url1 == url2;
397 }
398
399 if (strstr(url1, url2) != NULL || strstr(url2, url1) != NULL) {
400 return TRUE;
401 }
402
403 purl1 = purple_http_url_parse(url1);
404
405 if (purl1 == NULL) {
406 return g_ascii_strcasecmp(url1, url2) == 0;
407 }
408
409 purl2 = purple_http_url_parse(url2);
410
411 if (purl2 == NULL) {
412 purple_http_url_free(purl1);
413 return g_ascii_strcasecmp(url1, url2) == 0;
414 }
415
416 for (i = protocol ? 0 : 1; i < G_N_ELEMENTS(funcs); i++) {
417 str1 = funcs[i](purl1);
418 str2 = funcs[i](purl2);
419
420 if (!purple_strequal(str1, str2)) {
421 ret = FALSE;
422 break;
423 }
424 }
425
426 if (ret && protocol) {
427 int1 = purple_http_url_get_port(purl1);
428 int2 = purple_http_url_get_port(purl2);
429
430 if (int1 != int2) {
431 ret = FALSE;
432 }
433 }
434
435 purple_http_url_free(purl1);
436 purple_http_url_free(purl2);
437 return ret;
438 }
439