Mercurial > pidgin
comparison src/util.c @ 13200:33bef17125c2
[gaim-migrate @ 15563]
This is the soon-to-be-infamous nonblocking network activity patch that I've been working on. Feel free to yell at me if this makes you unhappy.
committer: Tailor Script <tailor@pidgin.im>
author | Daniel Atallah <daniel.atallah@gmail.com> |
---|---|
date | Thu, 09 Feb 2006 04:17:56 +0000 |
parents | b230ed49c5d1 |
children | 15b3926e2147 |
comparison
equal
deleted
inserted
replaced
13199:d8f238864c88 | 13200:33bef17125c2 |
---|---|
47 char *url; | 47 char *url; |
48 gboolean full; | 48 gboolean full; |
49 char *user_agent; | 49 char *user_agent; |
50 gboolean http11; | 50 gboolean http11; |
51 char *request; | 51 char *request; |
52 gsize request_written; | |
52 gboolean include_headers; | 53 gboolean include_headers; |
53 | 54 |
54 int inpa; | 55 int inpa; |
55 | 56 |
56 gboolean sentreq; | 57 gboolean got_headers; |
57 gboolean startsaving; | |
58 gboolean has_explicit_data_len; | 58 gboolean has_explicit_data_len; |
59 char *webdata; | 59 char *webdata; |
60 unsigned long len; | 60 unsigned long len; |
61 unsigned long data_len; | 61 unsigned long data_len; |
62 | 62 |
3216 } | 3216 } |
3217 | 3217 |
3218 return content_len; | 3218 return content_len; |
3219 } | 3219 } |
3220 | 3220 |
3221 | |
3221 static void | 3222 static void |
3222 url_fetched_cb(gpointer url_data, gint sock, GaimInputCondition cond) | 3223 url_fetched_cb(gpointer url_data, gint sock, GaimInputCondition cond) |
3223 { | 3224 { |
3224 GaimFetchUrlData *gfud = url_data; | 3225 GaimFetchUrlData *gfud = url_data; |
3225 int len; | 3226 int len; |
3226 char buf[4096]; | 3227 char buf[4096]; |
3227 char *data_cursor; | 3228 char *data_cursor; |
3228 gboolean got_eof = FALSE; | 3229 gboolean got_eof = FALSE; |
3229 | 3230 |
3230 if (sock == -1) | 3231 while((len = read(sock, buf, sizeof(buf))) > 0) { |
3231 { | |
3232 gfud->callback(gfud->user_data, NULL, 0); | |
3233 | |
3234 destroy_fetch_url_data(gfud); | |
3235 | |
3236 return; | |
3237 } | |
3238 | |
3239 if (!gfud->sentreq) | |
3240 { | |
3241 char *send; | |
3242 char buf[1024]; | |
3243 | |
3244 if (gfud->request) { | |
3245 send = gfud->request; | |
3246 } else { | |
3247 if (gfud->user_agent) { | |
3248 /* Host header is not forbidden in HTTP/1.0 requests, and HTTP/1.1 | |
3249 * clients must know how to handle the "chunked" transfer encoding. | |
3250 * Gaim doesn't know how to handle "chunked", so should always send | |
3251 * the Host header regardless, to get around some observed problems | |
3252 */ | |
3253 g_snprintf(buf, sizeof(buf), | |
3254 "GET %s%s HTTP/%s\r\n" | |
3255 "Connection: close\r\n" | |
3256 "User-Agent: %s\r\n" | |
3257 "Host: %s\r\n\r\n", | |
3258 (gfud->full ? "" : "/"), | |
3259 (gfud->full ? gfud->url : gfud->website.page), | |
3260 (gfud->http11 ? "1.1" : "1.0"), | |
3261 gfud->user_agent, gfud->website.address); | |
3262 } else { | |
3263 g_snprintf(buf, sizeof(buf), | |
3264 "GET %s%s HTTP/%s\r\n" | |
3265 "Connection: close\r\n" | |
3266 "Host: %s\r\n\r\n", | |
3267 (gfud->full ? "" : "/"), | |
3268 (gfud->full ? gfud->url : gfud->website.page), | |
3269 (gfud->http11 ? "1.1" : "1.0"), | |
3270 gfud->website.address); | |
3271 } | |
3272 send = buf; | |
3273 } | |
3274 | |
3275 gaim_debug_misc("gaim_url_fetch", "Request: %s\n", send); | |
3276 | |
3277 write(sock, send, strlen(send)); | |
3278 fcntl(sock, F_SETFL, O_NONBLOCK); | |
3279 gfud->sentreq = TRUE; | |
3280 gfud->inpa = gaim_input_add(sock, GAIM_INPUT_READ, | |
3281 url_fetched_cb, url_data); | |
3282 gfud->data_len = 4096; | |
3283 gfud->webdata = g_malloc(gfud->data_len); | |
3284 | |
3285 return; | |
3286 } | |
3287 | |
3288 while ((len = read(sock, buf, sizeof(buf))) > 0) | |
3289 { | |
3290 /* If we've filled up our butfer, make it bigger */ | 3232 /* If we've filled up our butfer, make it bigger */ |
3291 if ((gfud->len + len) >= gfud->data_len) | 3233 if((gfud->len + len) >= gfud->data_len) { |
3292 { | 3234 while((gfud->len + len) >= gfud->data_len) |
3293 gfud->data_len += MAX(((gfud->data_len) / 2), sizeof(buf)); | 3235 gfud->data_len += sizeof(buf); |
3294 | 3236 |
3295 gfud->webdata = g_realloc(gfud->webdata, gfud->data_len); | 3237 gfud->webdata = g_realloc(gfud->webdata, gfud->data_len); |
3296 } | 3238 } |
3297 | 3239 |
3298 data_cursor = gfud->webdata + gfud->len; | 3240 data_cursor = gfud->webdata + gfud->len; |
3301 | 3243 |
3302 memcpy(data_cursor, buf, len); | 3244 memcpy(data_cursor, buf, len); |
3303 | 3245 |
3304 gfud->webdata[gfud->len] = '\0'; | 3246 gfud->webdata[gfud->len] = '\0'; |
3305 | 3247 |
3306 if (!gfud->startsaving) | 3248 if(!gfud->got_headers) { |
3307 { | |
3308 char *tmp; | 3249 char *tmp; |
3309 | 3250 |
3310 /** See if we've reached the end of the headers yet */ | 3251 /** See if we've reached the end of the headers yet */ |
3311 if ((tmp = strstr(gfud->webdata, "\r\n\r\n"))) { | 3252 if((tmp = strstr(gfud->webdata, "\r\n\r\n"))) { |
3312 char * new_data; | 3253 char * new_data; |
3313 guint header_len = (tmp + 4 - gfud->webdata); | 3254 guint header_len = (tmp + 4 - gfud->webdata); |
3314 size_t content_len, body_len = 0; | 3255 size_t content_len, body_len = 0; |
3315 | 3256 |
3316 gaim_debug_misc("gaim_url_fetch", "Response headers: '%.*s'\n", | 3257 gaim_debug_misc("gaim_url_fetch", "Response headers: '%.*s'\n", |
3318 | 3259 |
3319 /* See if we can find a redirect. */ | 3260 /* See if we can find a redirect. */ |
3320 if (parse_redirect(gfud->webdata, header_len, sock, gfud)) | 3261 if (parse_redirect(gfud->webdata, header_len, sock, gfud)) |
3321 return; | 3262 return; |
3322 | 3263 |
3323 gfud->startsaving = TRUE; | 3264 gfud->got_headers = TRUE; |
3324 | 3265 |
3325 /* No redirect. See if we can find a content length. */ | 3266 /* No redirect. See if we can find a content length. */ |
3326 content_len = parse_content_len(gfud->webdata, header_len); | 3267 content_len = parse_content_len(gfud->webdata, header_len); |
3327 | 3268 |
3328 if (content_len == 0) | 3269 if (content_len == 0) |
3381 got_eof = TRUE; | 3322 got_eof = TRUE; |
3382 break; | 3323 break; |
3383 } | 3324 } |
3384 } | 3325 } |
3385 | 3326 |
3386 if (len <= 0) { | 3327 if(len <= 0) { |
3387 if (errno == EWOULDBLOCK) { | 3328 if(errno == EAGAIN) { |
3388 errno = 0; | |
3389 return; | 3329 return; |
3390 } else if (errno != ETIMEDOUT) { | 3330 } else if (errno != ETIMEDOUT) { |
3391 got_eof = TRUE; | 3331 got_eof = TRUE; |
3392 } else { | 3332 } else { |
3393 gaim_input_remove(gfud->inpa); | 3333 gaim_input_remove(gfud->inpa); |
3410 close(sock); | 3350 close(sock); |
3411 gfud->callback(gfud->user_data, gfud->webdata, gfud->len); | 3351 gfud->callback(gfud->user_data, gfud->webdata, gfud->len); |
3412 | 3352 |
3413 destroy_fetch_url_data(gfud); | 3353 destroy_fetch_url_data(gfud); |
3414 } | 3354 } |
3355 } | |
3356 | |
3357 static void | |
3358 url_fetch_connect_cb(gpointer url_data, gint sock, GaimInputCondition cond) { | |
3359 GaimFetchUrlData *gfud = url_data; | |
3360 int len, total_len; | |
3361 | |
3362 if(sock == -1) { | |
3363 gfud->callback(gfud->user_data, NULL, 0); | |
3364 destroy_fetch_url_data(gfud); | |
3365 return; | |
3366 } | |
3367 | |
3368 if (!gfud->request) { | |
3369 if (gfud->user_agent) { | |
3370 /* Host header is not forbidden in HTTP/1.0 requests, and HTTP/1.1 | |
3371 * clients must know how to handle the "chunked" transfer encoding. | |
3372 * Gaim doesn't know how to handle "chunked", so should always send | |
3373 * the Host header regardless, to get around some observed problems | |
3374 */ | |
3375 gfud->request = g_strdup_printf( | |
3376 "GET %s%s HTTP/%s\r\n" | |
3377 "Connection: close\r\n" | |
3378 "User-Agent: %s\r\n" | |
3379 "Host: %s\r\n\r\n", | |
3380 (gfud->full ? "" : "/"), | |
3381 (gfud->full ? gfud->url : gfud->website.page), | |
3382 (gfud->http11 ? "1.1" : "1.0"), | |
3383 gfud->user_agent, gfud->website.address); | |
3384 } else { | |
3385 gfud->request = g_strdup_printf( | |
3386 "GET %s%s HTTP/%s\r\n" | |
3387 "Connection: close\r\n" | |
3388 "Host: %s\r\n\r\n", | |
3389 (gfud->full ? "" : "/"), | |
3390 (gfud->full ? gfud->url : gfud->website.page), | |
3391 (gfud->http11 ? "1.1" : "1.0"), | |
3392 gfud->website.address); | |
3393 } | |
3394 } | |
3395 | |
3396 gaim_debug_misc("gaim_url_fetch", "Request: '%s'\n", gfud->request); | |
3397 | |
3398 if(!gfud->inpa) | |
3399 gfud->inpa = gaim_input_add(sock, GAIM_INPUT_WRITE, | |
3400 url_fetch_connect_cb, gfud); | |
3401 | |
3402 total_len = strlen(gfud->request); | |
3403 | |
3404 len = write(sock, gfud->request + gfud->request_written, | |
3405 total_len - gfud->request_written); | |
3406 | |
3407 if(len < 0 && errno == EAGAIN) | |
3408 return; | |
3409 else if(len < 0) { | |
3410 gaim_input_remove(gfud->inpa); | |
3411 close(sock); | |
3412 gfud->callback(gfud->user_data, NULL, 0); | |
3413 destroy_fetch_url_data(gfud); | |
3414 return; | |
3415 } | |
3416 gfud->request_written += len; | |
3417 | |
3418 if(gfud->request_written != total_len) | |
3419 return; | |
3420 | |
3421 gaim_input_remove(gfud->inpa); | |
3422 | |
3423 gfud->inpa = gaim_input_add(sock, GAIM_INPUT_READ, url_fetched_cb, | |
3424 gfud); | |
3415 } | 3425 } |
3416 | 3426 |
3417 void | 3427 void |
3418 gaim_url_fetch_request(const char *url, gboolean full, | 3428 gaim_url_fetch_request(const char *url, gboolean full, |
3419 const char *user_agent, gboolean http11, | 3429 const char *user_agent, gboolean http11, |
3442 | 3452 |
3443 gaim_url_parse(url, &gfud->website.address, &gfud->website.port, | 3453 gaim_url_parse(url, &gfud->website.address, &gfud->website.port, |
3444 &gfud->website.page, &gfud->website.user, &gfud->website.passwd); | 3454 &gfud->website.page, &gfud->website.user, &gfud->website.passwd); |
3445 | 3455 |
3446 if (gaim_proxy_connect(NULL, gfud->website.address, | 3456 if (gaim_proxy_connect(NULL, gfud->website.address, |
3447 gfud->website.port, url_fetched_cb, | 3457 gfud->website.port, url_fetch_connect_cb, gfud) != 0) { |
3448 gfud) != 0) | |
3449 { | |
3450 destroy_fetch_url_data(gfud); | 3458 destroy_fetch_url_data(gfud); |
3451 | 3459 |
3452 cb(user_data, g_strdup(_("g003: Error opening connection.\n")), 0); | 3460 cb(user_data, g_strdup(_("g003: Error opening connection.\n")), 0); |
3453 } | 3461 } |
3454 } | 3462 } |
3729 | 3737 |
3730 for(; *str; str = g_utf8_next_char(str)) { | 3738 for(; *str; str = g_utf8_next_char(str)) { |
3731 gunichar wc = g_utf8_get_char(str); | 3739 gunichar wc = g_utf8_get_char(str); |
3732 | 3740 |
3733 /* super simple check. hopefully not too wrong. */ | 3741 /* super simple check. hopefully not too wrong. */ |
3734 if(wc >= 0x80) { | 3742 if(wc >= 0x80) { |
3735 g_string_append_printf(out, "&#%u;", (guint32) wc); | 3743 g_string_append_printf(out, "&#%u;", (guint32) wc); |
3736 } else { | 3744 } else { |
3737 g_string_append_unichar(out, wc); | 3745 g_string_append_unichar(out, wc); |
3738 } | 3746 } |
3739 } | 3747 } |
3755 out = g_string_new(""); | 3763 out = g_string_new(""); |
3756 | 3764 |
3757 while( (b = strstr(buf, "&#")) ) { | 3765 while( (b = strstr(buf, "&#")) ) { |
3758 gunichar wc; | 3766 gunichar wc; |
3759 int base = 0; | 3767 int base = 0; |
3760 | 3768 |
3761 /* append everything leading up to the &# */ | 3769 /* append everything leading up to the &# */ |
3762 g_string_append_len(out, buf, b-buf); | 3770 g_string_append_len(out, buf, b-buf); |
3763 | 3771 |
3764 b += 2; /* skip past the &# */ | 3772 b += 2; /* skip past the &# */ |
3765 | 3773 |
3766 /* strtoul will handle 0x prefix as hex, but not x */ | 3774 /* strtoul will handle 0x prefix as hex, but not x */ |
3767 if(*b == 'x' || *b == 'X') | 3775 if(*b == 'x' || *b == 'X') |
3768 base = 16; | 3776 base = 16; |
3769 | 3777 |
3770 /* advances buf to the end of the ncr segment */ | 3778 /* advances buf to the end of the ncr segment */ |
3813 | 3821 |
3814 return ret; | 3822 return ret; |
3815 } | 3823 } |
3816 | 3824 |
3817 /* previously conversation::find_nick() */ | 3825 /* previously conversation::find_nick() */ |
3818 gboolean | 3826 gboolean |
3819 gaim_utf8_has_word(const char *haystack, const char *needle) | 3827 gaim_utf8_has_word(const char *haystack, const char *needle) |
3820 { | 3828 { |
3821 char *hay, *pin, *p; | 3829 char *hay, *pin, *p; |
3822 int n; | 3830 int n; |
3823 gboolean ret = FALSE; | 3831 gboolean ret = FALSE; |