Changeset ab19567
- Timestamp:
- 2013-06-16T12:15:15Z (11 years ago)
- Branches:
- master
- Children:
- 1a2c1c0
- Parents:
- 41a94dd (diff), dd7b931 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
lib/http_client.c
r41a94dd rab19567 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * 4 * Copyright 2002-201 2Wilmer van der Gaast and others *4 * Copyright 2002-2013 Wilmer van der Gaast and others * 5 5 \********************************************************************/ 6 6 … … 69 69 req->request_length = strlen( request ); 70 70 req->redir_ttl = 3; 71 req->content_length = -1; 71 72 72 73 if( getenv( "BITLBEE_DEBUG" ) ) … … 96 97 request = g_strdup_printf( "GET %s HTTP/1.0\r\n" 97 98 "Host: %s\r\n" 98 "Connection: close\r\n"99 99 "User-Agent: BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\r\n" 100 100 "\r\n", url->file, url->host ); … … 193 193 } 194 194 195 typedef enum { 196 CR_OK, 197 CR_EOF, 198 CR_ERROR, 199 CR_ABORT, 200 } http_ret_t; 201 195 202 static gboolean http_handle_headers( struct http_request *req ); 203 static http_ret_t http_process_chunked_data( struct http_request *req, const char *buffer, int len ); 204 static http_ret_t http_process_data( struct http_request *req, const char *buffer, int len ); 196 205 197 206 static gboolean http_incoming_data( gpointer data, int source, b_input_condition cond ) … … 199 208 struct http_request *req = data; 200 209 char buffer[4096]; 201 char *s;202 size_t content_length;203 210 int st; 204 211 … … 244 251 } 245 252 246 if( st > 0 && !req->sbuf ) 247 { 248 req->reply_headers = g_realloc( req->reply_headers, req->bytes_read + st + 1 ); 249 memcpy( req->reply_headers + req->bytes_read, buffer, st ); 250 req->bytes_read += st; 251 252 st = 0; 253 } 254 255 if( st >= 0 && ( req->flags & HTTPC_STREAMING ) ) 256 { 257 if( !req->reply_body && 258 ( strstr( req->reply_headers, "\r\n\r\n" ) || 259 strstr( req->reply_headers, "\n\n" ) ) ) 260 { 261 size_t hlen; 262 263 /* We've now received all headers, so process them once 264 before we start feeding back data. */ 265 if( !http_handle_headers( req ) ) 266 return FALSE; 267 268 hlen = req->reply_body - req->reply_headers; 269 270 req->sblen = req->bytes_read - hlen; 271 req->sbuf = g_memdup( req->reply_body, req->sblen + 1 ); 272 req->reply_headers = g_realloc( req->reply_headers, hlen + 1 ); 273 274 req->reply_body = req->sbuf; 275 } 276 277 if( st > 0 ) 278 { 279 int pos = req->reply_body - req->sbuf; 280 req->sbuf = g_realloc( req->sbuf, req->sblen + st + 1 ); 281 memcpy( req->sbuf + req->sblen, buffer, st ); 282 req->bytes_read += st; 283 req->sblen += st; 284 req->sbuf[req->sblen] = '\0'; 285 req->reply_body = req->sbuf + pos; 286 req->body_size = req->sblen - pos; 287 } 288 289 if( req->reply_body ) 290 req->func( req ); 291 } 253 if( st > 0 ) 254 { 255 http_ret_t c; 256 257 if( req->flags & HTTPC_CHUNKED ) 258 c = http_process_chunked_data( req, buffer, st ); 259 else 260 c = http_process_data( req, buffer, st ); 261 262 if( c == CR_EOF ) 263 goto eof; 264 else if( c == CR_ERROR || c == CR_ABORT ) 265 return FALSE; 266 } 267 268 if( req->content_length != -1 && 269 req->body_size >= req->content_length ) 270 goto eof; 292 271 293 272 if( ssl_pending( req->ssl ) ) … … 311 290 goto cleanup; 312 291 } 313 314 if( !( req->flags & HTTPC_STREAMING ) )315 {316 /* Returns FALSE if we were redirected, in which case we should abort317 and not run any callback yet. */318 if( !http_handle_headers( req ) )319 return FALSE;320 }321 292 322 293 cleanup: … … 326 297 closesocket( req->fd ); 327 298 328 if( ( s = get_rfc822_header( req->reply_headers, "Content-Length", 0 ) ) && 329 sscanf( s, "%zd", &content_length ) == 1 ) 330 { 331 if( content_length < req->body_size ) 332 { 333 req->status_code = -1; 334 g_free( req->status_string ); 335 req->status_string = g_strdup( "Response truncated" ); 336 } 337 } 338 g_free( s ); 299 if( req->body_size < req->content_length ) 300 { 301 req->status_code = -1; 302 g_free( req->status_string ); 303 req->status_string = g_strdup( "Response truncated" ); 304 } 339 305 340 306 if( getenv( "BITLBEE_DEBUG" ) && req ) … … 347 313 } 348 314 315 static http_ret_t http_process_chunked_data( struct http_request *req, const char *buffer, int len ) 316 { 317 char *chunk, *eos, *s; 318 319 if( len < 0 ) 320 return TRUE; 321 322 if( len > 0 ) 323 { 324 req->cbuf = g_realloc( req->cbuf, req->cblen + len + 1 ); 325 memcpy( req->cbuf + req->cblen, buffer, len ); 326 req->cblen += len; 327 req->cbuf[req->cblen] = '\0'; 328 } 329 330 /* Turns out writing a proper chunked-encoding state machine is not 331 that simple. :-( I've tested this one feeding it byte by byte so 332 I hope it's solid now. */ 333 chunk = req->cbuf; 334 eos = req->cbuf + req->cblen; 335 while( TRUE ) 336 { 337 int clen = 0; 338 339 /* Might be a \r\n from the last chunk. */ 340 s = chunk; 341 while( isspace( *s ) ) 342 s ++; 343 /* Chunk length. Might be incomplete. */ 344 if( s < eos && sscanf( s, "%x", &clen ) != 1 ) 345 return CR_ERROR; 346 while( isxdigit( *s ) ) 347 s ++; 348 349 /* If we read anything here, it *must* be \r\n. */ 350 if( strncmp( s, "\r\n", MIN( 2, eos - s ) ) != 0 ) 351 return CR_ERROR; 352 s += 2; 353 354 if( s >= eos ) 355 break; 356 357 /* 0-length chunk means end of response. */ 358 if( clen == 0 ) 359 return CR_EOF; 360 361 /* Wait for the whole chunk to arrive. */ 362 if( s + clen > eos ) 363 break; 364 if( http_process_data( req, s, clen ) != CR_OK ) 365 return CR_ABORT; 366 367 chunk = s + clen; 368 } 369 370 if( chunk != req->cbuf ) 371 { 372 req->cblen = eos - chunk; 373 s = g_memdup( chunk, req->cblen + 1 ); 374 g_free( req->cbuf ); 375 req->cbuf = s; 376 } 377 378 return CR_OK; 379 } 380 381 static http_ret_t http_process_data( struct http_request *req, const char *buffer, int len ) 382 { 383 if( len <= 0 ) 384 return CR_OK; 385 386 if( !req->reply_body ) 387 { 388 req->reply_headers = g_realloc( req->reply_headers, req->bytes_read + len + 1 ); 389 memcpy( req->reply_headers + req->bytes_read, buffer, len ); 390 req->bytes_read += len; 391 req->reply_headers[req->bytes_read] = '\0'; 392 393 if( strstr( req->reply_headers, "\r\n\r\n" ) || 394 strstr( req->reply_headers, "\n\n" ) ) 395 { 396 /* We've now received all headers. Look for something 397 interesting. */ 398 if( !http_handle_headers( req ) ) 399 return CR_ABORT; 400 401 /* Start parsing the body as chunked if required. */ 402 if( req->flags & HTTPC_CHUNKED ) 403 return http_process_chunked_data( req, NULL, 0 ); 404 } 405 } 406 else 407 { 408 int pos = req->reply_body - req->sbuf; 409 req->sbuf = g_realloc( req->sbuf, req->sblen + len + 1 ); 410 memcpy( req->sbuf + req->sblen, buffer, len ); 411 req->bytes_read += len; 412 req->sblen += len; 413 req->sbuf[req->sblen] = '\0'; 414 req->reply_body = req->sbuf + pos; 415 req->body_size = req->sblen - pos; 416 } 417 418 if( ( req->flags & HTTPC_STREAMING ) && req->reply_body ) 419 req->func( req ); 420 421 return CR_OK; 422 } 423 349 424 /* Splits headers and body. Checks result code, in case of 300s it'll handle 350 425 redirects. If this returns FALSE, don't call any callbacks! */ 351 426 static gboolean http_handle_headers( struct http_request *req ) 352 427 { 353 char *end1, *end2 ;428 char *end1, *end2, *s; 354 429 int evil_server = 0; 355 430 … … 377 452 } 378 453 379 *end1 = 0;454 *end1 = '\0'; 380 455 381 456 if( getenv( "BITLBEE_DEBUG" ) ) … … 387 462 req->reply_body = end1 + 2; 388 463 389 req->body_size = req->reply_headers + req->bytes_read - req->reply_body; 464 /* Separately allocated space for headers and body. */ 465 req->sblen = req->body_size = req->reply_headers + req->bytes_read - req->reply_body; 466 req->sbuf = req->reply_body = g_memdup( req->reply_body, req->body_size + 1 ); 467 req->reply_headers = g_realloc( req->reply_headers, end1 - req->reply_headers + 1 ); 390 468 391 469 if( ( end1 = strchr( req->reply_headers, ' ' ) ) != NULL ) … … 452 530 don't need this yet anyway, I won't implement it. */ 453 531 454 req->status_string = g_strdup( "Can't handle re cursive redirects" );532 req->status_string = g_strdup( "Can't handle relative redirects" ); 455 533 456 534 return TRUE; … … 460 538 /* A whole URL */ 461 539 url_t *url; 462 char *s ;540 char *s, *version, *headers; 463 541 const char *new_method; 464 542 … … 488 566 return TRUE; 489 567 } 568 headers = s; 490 569 491 570 /* More or less HTTP/1.0 compliant, from my reading of RFC 2616. … … 507 586 new_method = "POST"; 508 587 588 if( ( version = strstr( req->request, " HTTP/" ) ) && 589 ( s = strstr( version, "\r\n" ) ) ) 590 { 591 version ++; 592 version = g_strndup( version, s - version ); 593 } 594 else 595 version = g_strdup( "HTTP/1.0" ); 596 509 597 /* Okay, this isn't fun! We have to rebuild the request... :-( */ 510 new_request = g_strdup_printf( "%s %s HTTP/1.0\r\nHost: %s%s", 511 new_method, url->file, url->host, s ); 598 new_request = g_strdup_printf( "%s %s %s\r\nHost: %s%s", 599 new_method, url->file, version, 600 url->host, headers ); 512 601 513 602 new_host = g_strdup( url->host ); … … 521 610 522 611 g_free( url ); 612 g_free( version ); 523 613 } 524 614 … … 557 647 g_free( req->request ); 558 648 g_free( req->reply_headers ); 649 g_free( req->sbuf ); 559 650 req->request = new_request; 560 651 req->request_length = strlen( new_request ); 561 652 req->bytes_read = req->bytes_written = req->inpa = 0; 562 653 req->reply_headers = req->reply_body = NULL; 654 req->sbuf = req->cbuf = NULL; 655 req->sblen = req->cblen = 0; 563 656 564 657 return FALSE; 658 } 659 660 if( ( s = get_rfc822_header( req->reply_headers, "Content-Length", 0 ) ) && 661 sscanf( s, "%d", &req->content_length ) != 1 ) 662 req->content_length = -1; 663 g_free( s ); 664 665 if( ( s = get_rfc822_header( req->reply_headers, "Transfer-Encoding", 0 ) ) ) 666 { 667 if( strcasestr( s, "chunked" ) ) 668 { 669 req->flags |= HTTPC_CHUNKED; 670 req->cbuf = req->sbuf; 671 req->cblen = req->sblen; 672 673 req->reply_body = req->sbuf = g_strdup( "" ); 674 req->body_size = req->sblen = 0; 675 } 676 g_free( s ); 565 677 } 566 678 … … 607 719 g_free( req->status_string ); 608 720 g_free( req->sbuf ); 721 g_free( req->cbuf ); 609 722 g_free( req ); 610 723 } -
lib/http_client.h
r41a94dd rab19567 42 42 HTTPC_STREAMING = 1, 43 43 HTTPC_EOF = 2, 44 HTTPC_CHUNKED = 4, 44 45 45 46 /* Let's reserve 0x1000000+ for lib users. */ … … 77 78 int bytes_written; 78 79 int bytes_read; 80 int content_length; /* "Content-Length:" header or -1 */ 79 81 80 82 /* Used in streaming mode. Caller should read from reply_body. */ 81 83 char *sbuf; 82 84 size_t sblen; 85 86 /* Chunked encoding only. Raw chunked stream is decoded from here. */ 87 char *cbuf; 88 size_t cblen; 83 89 }; 84 90 -
lib/oauth.c
r41a94dd rab19567 262 262 "Content-Type: application/x-www-form-urlencoded\r\n" 263 263 "Content-Length: %zd\r\n" 264 "Connection: close\r\n"265 264 "\r\n" 266 265 "%s", url_p.file, url_p.host, strlen( post ), post ); -
lib/oauth2.c
r41a94dd rab19567 96 96 "Content-Type: application/x-www-form-urlencoded\r\n" 97 97 "Content-Length: %zd\r\n" 98 "Connection: close\r\n"99 98 "\r\n" 100 99 "%s", url_p.file, url_p.host, strlen( args_s ), args_s ); -
lib/proxy.c
r41a94dd rab19567 158 158 } 159 159 160 event_debug("proxy_connect_none( \"%s\", %d ) = %d\n", host, port , fd);160 event_debug("proxy_connect_none( \"%s\", %d ) = %d\n", host, port_, fd); 161 161 162 162 if (connect(fd, phb->gai_cur->ai_addr, phb->gai_cur->ai_addrlen) < 0 && !sockerr_again()) { -
protocols/twitter/twitter.c
r41a94dd rab19567 289 289 char *def_url; 290 290 char *def_tul; 291 char *def_mentions; 291 292 292 293 if (strcmp(acc->prpl->name, "twitter") == 0) { 293 294 def_url = TWITTER_API_URL; 294 295 def_tul = "20"; 296 def_mentions = "true"; 295 297 } else { /* if( strcmp( acc->prpl->name, "identica" ) == 0 ) */ 296 298 def_url = IDENTICA_API_URL; 297 299 def_tul = "0"; 300 def_mentions = "false"; 298 301 } 299 302 … … 308 311 s->flags |= ACC_SET_OFFLINE_ONLY; 309 312 310 s = set_add(&acc->set, "fetch_mentions", "true", set_eval_bool, acc);313 s = set_add(&acc->set, "fetch_mentions", def_mentions, set_eval_bool, acc); 311 314 312 315 s = set_add(&acc->set, "message_length", "140", set_eval_int, acc); -
protocols/twitter/twitter_http.c
r41a94dd rab19567 78 78 79 79 // Make the request. 80 g_string_printf(request, "%s %s%s%s%s HTTP/1. 0\r\n"80 g_string_printf(request, "%s %s%s%s%s HTTP/1.1\r\n" 81 81 "Host: %s\r\n" 82 82 "User-Agent: BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\r\n",
Note: See TracChangeset
for help on using the changeset viewer.