comparison libpurple/util.c @ 17673:3d035cdd103b

Add some notes about why Yahoo! web messenger login doesn't work (it's because they redirect us to an https page and purple_util_fetch_url() doesn't support https), and add checks to purple_util_fetch_url() to not allow us to be redirected more than 5 times.
author Mark Doliner <mark@kingant.net>
date Sun, 03 Jun 2007 21:42:54 +0000
parents d8102e923bd1
children a7a8e4245b33
comparison
equal deleted inserted replaced
17672:df788cd53596 17673:3d035cdd103b
44 char *page; 44 char *page;
45 45
46 } website; 46 } website;
47 47
48 char *url; 48 char *url;
49 int num_times_redirected;
49 gboolean full; 50 gboolean full;
50 char *user_agent; 51 char *user_agent;
51 gboolean http11; 52 gboolean http11;
52 char *request; 53 char *request;
53 gsize request_written; 54 gsize request_written;
3184 g_free(cmd); 3185 g_free(cmd);
3185 if (params) 3186 if (params)
3186 g_hash_table_destroy(params); 3187 g_hash_table_destroy(params);
3187 } 3188 }
3188 3189
3190 /*
3191 * TODO: Should probably add a "gboolean *ret_ishttps" parameter that
3192 * is set to TRUE if this URL is https, otherwise it is set to
3193 * FALSE. But that change will break the API.
3194 *
3195 * This is important for Yahoo! web messenger login. They now
3196 * force https login, and if you access the web messenger login
3197 * page via http then it redirects you to the https version, but
3198 * purple_util_fetch_url() ignores the "https" and attempts to
3199 * fetch the URL via http again, which gets redirected again.
3200 */
3189 gboolean 3201 gboolean
3190 purple_url_parse(const char *url, char **ret_host, int *ret_port, 3202 purple_url_parse(const char *url, char **ret_host, int *ret_port,
3191 char **ret_path, char **ret_user, char **ret_passwd) 3203 char **ret_path, char **ret_user, char **ret_passwd)
3192 { 3204 {
3193 char scan_info[255]; 3205 char scan_info[255];
3204 static char user_ctrl[] = "A-Za-z0-9.~_/*!&%%?=+^-"; 3216 static char user_ctrl[] = "A-Za-z0-9.~_/*!&%%?=+^-";
3205 static char passwd_ctrl[] = "A-Za-z0-9.~_/*!&%%?=+^-"; 3217 static char passwd_ctrl[] = "A-Za-z0-9.~_/*!&%%?=+^-";
3206 3218
3207 g_return_val_if_fail(url != NULL, FALSE); 3219 g_return_val_if_fail(url != NULL, FALSE);
3208 3220
3209 if ((turl = strstr(url, "http://")) != NULL || 3221 if ((turl = purple_strcasestr(url, "http://")) != NULL)
3210 (turl = strstr(url, "HTTP://")) != NULL)
3211 { 3222 {
3212 turl += 7; 3223 turl += 7;
3224 url = turl;
3225 }
3226 else if ((turl = purple_strcasestr(url, "https://")) != NULL)
3227 {
3228 turl += 8;
3213 url = turl; 3229 url = turl;
3214 } 3230 }
3215 3231
3216 /* parse out authentication information if supplied */ 3232 /* parse out authentication information if supplied */
3217 /* Only care about @ char BEFORE the first / */ 3233 /* Only care about @ char BEFORE the first / */
3289 static gboolean 3305 static gboolean
3290 parse_redirect(const char *data, size_t data_len, gint sock, 3306 parse_redirect(const char *data, size_t data_len, gint sock,
3291 PurpleUtilFetchUrlData *gfud) 3307 PurpleUtilFetchUrlData *gfud)
3292 { 3308 {
3293 gchar *s; 3309 gchar *s;
3294 3310 gchar *new_url, *temp_url, *end;
3295 if ((s = g_strstr_len(data, data_len, "Location: ")) != NULL) 3311 gboolean full;
3296 { 3312 int len;
3297 gchar *new_url, *temp_url, *end; 3313
3298 gboolean full; 3314 if ((s = g_strstr_len(data, data_len, "Location: ")) == NULL)
3299 int len; 3315 /* We're not being redirected */
3300 3316 return FALSE;
3301 s += strlen("Location: "); 3317
3302 end = strchr(s, '\r'); 3318 s += strlen("Location: ");
3303 3319 end = strchr(s, '\r');
3304 /* Just in case :) */ 3320
3305 if (end == NULL) 3321 /* Just in case :) */
3306 end = strchr(s, '\n'); 3322 if (end == NULL)
3307 3323 end = strchr(s, '\n');
3308 if (end == NULL) 3324
3309 return FALSE; 3325 if (end == NULL)
3310 3326 return FALSE;
3311 len = end - s; 3327
3312 3328 len = end - s;
3313 new_url = g_malloc(len + 1); 3329
3314 strncpy(new_url, s, len); 3330 new_url = g_malloc(len + 1);
3315 new_url[len] = '\0'; 3331 strncpy(new_url, s, len);
3316 3332 new_url[len] = '\0';
3317 full = gfud->full; 3333
3318 3334 full = gfud->full;
3319 if (*new_url == '/' || g_strstr_len(new_url, len, "://") == NULL) 3335
3320 { 3336 if (*new_url == '/' || g_strstr_len(new_url, len, "://") == NULL)
3321 temp_url = new_url; 3337 {
3322 3338 temp_url = new_url;
3323 new_url = g_strdup_printf("%s:%d%s", gfud->website.address, 3339
3324 gfud->website.port, temp_url); 3340 new_url = g_strdup_printf("%s:%d%s", gfud->website.address,
3325 3341 gfud->website.port, temp_url);
3326 g_free(temp_url); 3342
3327 3343 g_free(temp_url);
3328 full = FALSE; 3344
3329 } 3345 full = FALSE;
3330 3346 }
3331 purple_debug_info("util", "Redirecting to %s\n", new_url); 3347
3332 3348 purple_debug_info("util", "Redirecting to %s\n", new_url);
3333 /* 3349
3334 * Try again, with this new location. This code is somewhat 3350 gfud->num_times_redirected++;
3335 * ugly, but we need to reuse the gfud because whoever called 3351 if (gfud->num_times_redirected >= 5)
3336 * us is holding a reference to it. 3352 {
3337 */ 3353 purple_util_fetch_url_error(gfud,
3338 g_free(gfud->url); 3354 _("Could not open %s: Redirected too many times"),
3339 gfud->url = new_url; 3355 gfud->url);
3340 gfud->full = full;
3341 g_free(gfud->request);
3342 gfud->request = NULL;
3343
3344 purple_input_remove(gfud->inpa);
3345 gfud->inpa = 0;
3346 close(gfud->fd);
3347 gfud->fd = -1;
3348 gfud->request_written = 0;
3349 gfud->len = 0;
3350 gfud->data_len = 0;
3351
3352 g_free(gfud->website.user);
3353 g_free(gfud->website.passwd);
3354 g_free(gfud->website.address);
3355 g_free(gfud->website.page);
3356 purple_url_parse(new_url, &gfud->website.address, &gfud->website.port,
3357 &gfud->website.page, &gfud->website.user, &gfud->website.passwd);
3358
3359 gfud->connect_data = purple_proxy_connect(NULL, NULL,
3360 gfud->website.address, gfud->website.port,
3361 url_fetch_connect_cb, gfud);
3362
3363 if (gfud->connect_data == NULL)
3364 {
3365 purple_util_fetch_url_error(gfud, _("Unable to connect to %s"),
3366 gfud->website.address);
3367 }
3368
3369 return TRUE; 3356 return TRUE;
3370 } 3357 }
3371 3358
3372 return FALSE; 3359 /*
3360 * Try again, with this new location. This code is somewhat
3361 * ugly, but we need to reuse the gfud because whoever called
3362 * us is holding a reference to it.
3363 */
3364 g_free(gfud->url);
3365 gfud->url = new_url;
3366 gfud->full = full;
3367 g_free(gfud->request);
3368 gfud->request = NULL;
3369
3370 purple_input_remove(gfud->inpa);
3371 gfud->inpa = 0;
3372 close(gfud->fd);
3373 gfud->fd = -1;
3374 gfud->request_written = 0;
3375 gfud->len = 0;
3376 gfud->data_len = 0;
3377
3378 g_free(gfud->website.user);
3379 g_free(gfud->website.passwd);
3380 g_free(gfud->website.address);
3381 g_free(gfud->website.page);
3382 purple_url_parse(new_url, &gfud->website.address, &gfud->website.port,
3383 &gfud->website.page, &gfud->website.user, &gfud->website.passwd);
3384
3385 gfud->connect_data = purple_proxy_connect(NULL, NULL,
3386 gfud->website.address, gfud->website.port,
3387 url_fetch_connect_cb, gfud);
3388
3389 if (gfud->connect_data == NULL)
3390 {
3391 purple_util_fetch_url_error(gfud, _("Unable to connect to %s"),
3392 gfud->website.address);
3393 }
3394
3395 return TRUE;
3373 } 3396 }
3374 3397
3375 static size_t 3398 static size_t
3376 parse_content_len(const char *data, size_t data_len) 3399 parse_content_len(const char *data, size_t data_len)
3377 { 3400 {