Changeset ca8037e
- Timestamp:
- 2013-06-09T21:17:45Z (12 years ago)
- Branches:
- master
- Children:
- 777461b
- Parents:
- 41a94dd
- Location:
- lib
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
lib/http_client.c
r41a94dd rca8037e 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. :-( */ 332 chunk = req->cbuf; 333 eos = req->cbuf + req->cblen; 334 while( TRUE ) 335 { 336 int clen = 0; 337 338 /* Might be a \r\n from the last chunk. */ 339 s = chunk; 340 while( isspace( *s ) ) 341 s ++; 342 /* Chunk length. Might be incomplete. */ 343 if( s < eos && sscanf( s, "%x", &clen ) != 1 ) 344 return CR_ERROR; 345 while( isxdigit( *s ) ) 346 s ++; 347 348 /* If we read anything here, it *must* be \r\n. */ 349 if( strncmp( s, "\r\n", MIN( 2, eos - s ) ) != 0 ) 350 return CR_ERROR; 351 s += 2; 352 353 if( s >= eos ) 354 break; 355 356 /* 0-length chunk means end of response. */ 357 if( clen == 0 ) 358 return CR_EOF; 359 360 if( s + clen > eos ) 361 break; 362 if( http_process_data( req, s, clen ) != CR_OK ) 363 return CR_ABORT; 364 365 chunk = s + clen; 366 } 367 368 if( chunk != req->cbuf ) 369 { 370 req->cblen = eos - chunk; 371 s = g_memdup( chunk, req->cblen + 1 ); 372 g_free( req->cbuf ); 373 req->cbuf = s; 374 } 375 376 return CR_OK; 377 } 378 379 static http_ret_t http_process_data( struct http_request *req, const char *buffer, int len ) 380 { 381 if( len <= 0 ) 382 return CR_OK; 383 384 if( !req->reply_body ) 385 { 386 req->reply_headers = g_realloc( req->reply_headers, req->bytes_read + len + 1 ); 387 memcpy( req->reply_headers + req->bytes_read, buffer, len ); 388 req->bytes_read += len; 389 req->reply_headers[req->bytes_read] = '\0'; 390 391 if( strstr( req->reply_headers, "\r\n\r\n" ) || 392 strstr( req->reply_headers, "\n\n" ) ) 393 { 394 /* We've now received all headers. Look for something 395 interesting. */ 396 if( !http_handle_headers( req ) ) 397 return CR_ABORT; 398 399 /* Start parsing the body as chunked if required. */ 400 if( req->flags & HTTPC_CHUNKED ) 401 return http_process_chunked_data( req, NULL, 0 ); 402 } 403 } 404 else 405 { 406 int pos = req->reply_body - req->sbuf; 407 req->sbuf = g_realloc( req->sbuf, req->sblen + len + 1 ); 408 memcpy( req->sbuf + req->sblen, buffer, len ); 409 req->bytes_read += len; 410 req->sblen += len; 411 req->sbuf[req->sblen] = '\0'; 412 req->reply_body = req->sbuf + pos; 413 req->body_size = req->sblen - pos; 414 } 415 416 if( ( req->flags & HTTPC_STREAMING ) && req->reply_body ) 417 req->func( req ); 418 419 return CR_OK; 420 } 421 349 422 /* Splits headers and body. Checks result code, in case of 300s it'll handle 350 423 redirects. If this returns FALSE, don't call any callbacks! */ 351 424 static gboolean http_handle_headers( struct http_request *req ) 352 425 { 353 char *end1, *end2 ;426 char *end1, *end2, *s; 354 427 int evil_server = 0; 355 428 … … 377 450 } 378 451 379 *end1 = 0;452 *end1 = '\0'; 380 453 381 454 if( getenv( "BITLBEE_DEBUG" ) ) … … 387 460 req->reply_body = end1 + 2; 388 461 389 req->body_size = req->reply_headers + req->bytes_read - req->reply_body; 462 /* Separately allocated space for headers and body. */ 463 req->sblen = req->body_size = req->reply_headers + req->bytes_read - req->reply_body; 464 req->sbuf = req->reply_body = g_memdup( req->reply_body, req->body_size + 1 ); 465 req->reply_headers = g_realloc( req->reply_headers, end1 - req->reply_headers + 1 ); 390 466 391 467 if( ( end1 = strchr( req->reply_headers, ' ' ) ) != NULL ) … … 452 528 don't need this yet anyway, I won't implement it. */ 453 529 454 req->status_string = g_strdup( "Can't handle re cursive redirects" );530 req->status_string = g_strdup( "Can't handle relative redirects" ); 455 531 456 532 return TRUE; … … 508 584 509 585 /* 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",586 new_request = g_strdup_printf( "%s %s HTTP/1.1\r\nHost: %s%s", 511 587 new_method, url->file, url->host, s ); 512 588 … … 564 640 return FALSE; 565 641 } 642 643 if( ( s = get_rfc822_header( req->reply_headers, "Content-Length", 0 ) ) && 644 sscanf( s, "%d", &req->content_length ) != 1 ) 645 req->content_length = -1; 646 g_free( s ); 647 648 if( ( s = get_rfc822_header( req->reply_headers, "Transfer-Encoding", 0 ) ) ) 649 { 650 if( strcasestr( s, "chunked" ) ) 651 { 652 req->flags |= HTTPC_CHUNKED; 653 req->cbuf = req->sbuf; 654 req->cblen = req->sblen; 655 656 req->reply_body = req->sbuf = g_strdup( "" ); 657 req->body_size = req->sblen = 0; 658 } 659 g_free( s ); 660 } 566 661 567 662 return TRUE; … … 607 702 g_free( req->status_string ); 608 703 g_free( req->sbuf ); 704 g_free( req->cbuf ); 609 705 g_free( req ); 610 706 } -
lib/http_client.h
r41a94dd rca8037e 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 rca8037e 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 rca8037e 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 rca8037e 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()) {
Note: See TracChangeset
for help on using the changeset viewer.