proxy_http_rewriter.c revision c27f813900a3c114562efbb8df1065e94766fc48
1/* Copyright (C) 2007-2008 The Android Open Source Project 2** 3** This software is licensed under the terms of the GNU General Public 4** License version 2, as published by the Free Software Foundation, and 5** may be copied, distributed, and modified under those terms. 6** 7** This program is distributed in the hope that it will be useful, 8** but WITHOUT ANY WARRANTY; without even the implied warranty of 9** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10** GNU General Public License for more details. 11*/ 12#include "proxy_http_int.h" 13#include <stdio.h> 14#include <string.h> 15#include "qemu-common.h" 16#include "android/utils/system.h" /* strsep */ 17 18/* this implements a transparent HTTP rewriting proxy 19 * 20 * this is needed because the HTTP spec mandates that 21 * any query made to a proxy uses an absolute URI as 22 * in: 23 * 24 * GET http://www.example.com/index.html HTTP/1.1 25 * 26 * while the Android browser will think it's talking to 27 * a normal web server and will issue a: 28 * 29 * GET /index.html HTTP/1.1 30 * Host: www.example.com 31 * 32 * what we do here is thus the following: 33 * 34 * - read the request header 35 * - rewrite the request's URI to use absolute URI 36 * - send the rewritten header to the proxy 37 * - then read the rest of the request, and tunnel it to the 38 * proxy as well 39 * - read the answer as-is and send it back to the system 40 * 41 * this sounds all easy, but the rules for computing the 42 * sizes of HTTP Message Bodies makes the implementation 43 * a *bit* funky. 44 */ 45 46/* define D_ACTIVE to 1 to dump additionnal debugging 47 * info when -debug-proxy is used. These are only needed 48 * when debugging the proxy code. 49 */ 50#define D_ACTIVE 1 51 52#if D_ACTIVE 53# define D(...) PROXY_LOG(__VA_ARGS__) 54#else 55# define D(...) ((void)0) 56#endif 57 58 59/** ************************************************************* 60 ** 61 ** HTTP HEADERS 62 ** 63 **/ 64 65typedef struct HttpHeader { 66 struct HttpHeader* next; 67 const char* key; 68 const char* value; 69} HttpHeader; 70 71static void 72http_header_free( HttpHeader* h ) 73{ 74 if (h) { 75 qemu_free((char*)h->value); 76 qemu_free(h); 77 } 78} 79 80static int 81http_header_append( HttpHeader* h, const char* value ) 82{ 83 int old = strlen(h->value); 84 int new = strlen(value); 85 char* s = realloc((char*)h->value, old+new+1); 86 if (s == NULL) 87 return -1; 88 memcpy(s + old, value, new+1); 89 h->value = (const char*)s; 90 return 0; 91} 92 93static HttpHeader* 94http_header_alloc( const char* key, const char* value ) 95{ 96 int len = strlen(key)+1; 97 HttpHeader* h = malloc(sizeof(*h) + len+1); 98 if (h) { 99 h->next = NULL; 100 h->key = (const char*)(h+1); 101 memcpy( (char*)h->key, key, len ); 102 h->value = qemu_strdup(value); 103 } 104 return h; 105} 106 107typedef struct { 108 HttpHeader* first; 109 HttpHeader* last; 110} HttpHeaderList; 111 112static void 113http_header_list_init( HttpHeaderList* l ) 114{ 115 l->first = l->last = NULL; 116} 117 118static void 119http_header_list_done( HttpHeaderList* l ) 120{ 121 while (l->first) { 122 HttpHeader* h = l->first; 123 l->first = h->next; 124 http_header_free(h); 125 } 126 l->last = NULL; 127} 128 129static void 130http_header_list_add( HttpHeaderList* l, 131 HttpHeader* h ) 132{ 133 if (!l->first) { 134 l->first = h; 135 } else { 136 l->last->next = h; 137 } 138 h->next = NULL; 139 l->last = h; 140} 141 142static const char* 143http_header_list_find( HttpHeaderList* l, 144 const char* key ) 145{ 146 HttpHeader* h; 147 for (h = l->first; h; h = h->next) 148 if (!strcasecmp(h->key, key)) 149 return h->value; 150 151 return NULL; 152} 153 154/** ************************************************************* 155 ** 156 ** HTTP REQUEST AND REPLY 157 ** 158 **/ 159 160typedef enum { 161 HTTP_REQUEST_UNSUPPORTED = 0, 162 HTTP_REQUEST_GET, 163 HTTP_REQUEST_HEAD, 164 HTTP_REQUEST_POST, 165 HTTP_REQUEST_PUT, 166 HTTP_REQUEST_DELETE, 167} HttpRequestType; 168 169typedef struct { 170 HttpRequestType req_type; 171 char* req_method; 172 char* req_uri; 173 char* req_version; 174 char* rep_version; 175 int rep_code; 176 char* rep_readable; 177 HttpHeaderList headers[1]; 178} HttpRequest; 179 180 181static HttpRequest* 182http_request_alloc( const char* method, 183 const char* uri, 184 const char* version ) 185{ 186 HttpRequest* r = malloc(sizeof(*r)); 187 188 r->req_method = qemu_strdup(method); 189 r->req_uri = qemu_strdup(uri); 190 r->req_version = qemu_strdup(version); 191 r->rep_version = NULL; 192 r->rep_code = -1; 193 r->rep_readable = NULL; 194 195 if (!strcmp(method,"GET")) { 196 r->req_type = HTTP_REQUEST_GET; 197 } else if (!strcmp(method,"POST")) { 198 r->req_type = HTTP_REQUEST_POST; 199 } else if (!strcmp(method,"HEAD")) { 200 r->req_type = HTTP_REQUEST_HEAD; 201 } else if (!strcmp(method,"PUT")) { 202 r->req_type = HTTP_REQUEST_PUT; 203 } else if (!strcmp(method,"DELETE")) { 204 r->req_type = HTTP_REQUEST_DELETE; 205 } else 206 r->req_type = HTTP_REQUEST_UNSUPPORTED; 207 208 http_header_list_init(r->headers); 209 return r; 210} 211 212static void 213http_request_replace_uri( HttpRequest* r, 214 const char* uri ) 215{ 216 const char* old = r->req_uri; 217 r->req_uri = qemu_strdup(uri); 218 qemu_free((char*)old); 219} 220 221static void 222http_request_free( HttpRequest* r ) 223{ 224 if (r) { 225 http_header_list_done(r->headers); 226 227 qemu_free(r->req_method); 228 qemu_free(r->req_uri); 229 qemu_free(r->req_version); 230 qemu_free(r->rep_version); 231 qemu_free(r->rep_readable); 232 qemu_free(r); 233 } 234} 235 236static char* 237http_request_find_header( HttpRequest* r, 238 const char* key ) 239{ 240 return (char*)http_header_list_find(r->headers, key); 241} 242 243 244static int 245http_request_add_header( HttpRequest* r, 246 const char* key, 247 const char* value ) 248{ 249 HttpHeader* h = http_header_alloc(key,value); 250 if (h) { 251 http_header_list_add(r->headers, h); 252 return 0; 253 } 254 return -1; 255} 256 257static int 258http_request_add_to_last_header( HttpRequest* r, 259 const char* line ) 260{ 261 if (r->headers->last) { 262 return http_header_append( r->headers->last, line ); 263 } else { 264 return -1; 265 } 266} 267 268static int 269http_request_set_reply( HttpRequest* r, 270 const char* version, 271 const char* code, 272 const char* readable ) 273{ 274 if (strcmp(version,"HTTP/1.0") && strcmp(version,"HTTP/1.1")) { 275 PROXY_LOG("%s: bad reply protocol: %s", __FUNCTION__, version); 276 return -1; 277 } 278 r->rep_code = atoi(code); 279 if (r->rep_code == 0) { 280 PROXY_LOG("%s: bad reply code: %d", __FUNCTION__, code); 281 return -1; 282 } 283 284 r->rep_version = qemu_strdup(version); 285 r->rep_readable = qemu_strdup(readable); 286 287 /* reset the list of headers */ 288 http_header_list_done(r->headers); 289 return 0; 290} 291 292/** ************************************************************* 293 ** 294 ** REWRITER CONNECTION 295 ** 296 **/ 297 298typedef enum { 299 STATE_CONNECTING = 0, 300 STATE_CREATE_SOCKET_PAIR, 301 STATE_REQUEST_FIRST_LINE, 302 STATE_REQUEST_HEADERS, 303 STATE_REQUEST_SEND, 304 STATE_REQUEST_BODY, 305 STATE_REPLY_FIRST_LINE, 306 STATE_REPLY_HEADERS, 307 STATE_REPLY_SEND, 308 STATE_REPLY_BODY, 309} ConnectionState; 310 311/* root->socket is connected to the proxy server. while 312 * slirp_fd is connected to the slirp code through a 313 * socket_pair() we created for this specific purpose. 314 */ 315 316typedef enum { 317 BODY_NONE = 0, 318 BODY_KNOWN_LENGTH, 319 BODY_UNTIL_CLOSE, 320 BODY_CHUNKED, 321 BODY_MODE_MAX 322} BodyMode; 323 324static const char* const body_mode_str[BODY_MODE_MAX] = { 325 "NONE", "KNOWN_LENGTH", "UNTIL_CLOSE", "CHUNKED" 326}; 327 328typedef struct { 329 ProxyConnection root[1]; 330 int slirp_fd; 331 ConnectionState state; 332 HttpRequest* request; 333 BodyMode body_mode; 334 int64_t body_length; 335 int64_t body_total; 336 int64_t body_sent; 337 int64_t chunk_length; 338 int64_t chunk_total; 339 char body_has_data; 340 char body_is_full; 341 char body_is_closed; 342 char parse_chunk_header; 343 char parse_chunk_trailer; 344} RewriteConnection; 345 346 347static void 348rewrite_connection_free( ProxyConnection* root ) 349{ 350 RewriteConnection* conn = (RewriteConnection*)root; 351 352 if (conn->slirp_fd >= 0) { 353 socket_close(conn->slirp_fd); 354 conn->slirp_fd = -1; 355 } 356 http_request_free(conn->request); 357 proxy_connection_done(root); 358 qemu_free(conn); 359} 360 361 362static int 363rewrite_connection_init( RewriteConnection* conn ) 364{ 365 HttpService* service = (HttpService*) conn->root->service; 366 ProxyConnection* root = conn->root; 367 368 conn->slirp_fd = -1; 369 conn->state = STATE_CONNECTING; 370 371 if (socket_connect( root->socket, &service->server_addr ) < 0) { 372 if (errno == EINPROGRESS || errno == EWOULDBLOCK) { 373 PROXY_LOG("%s: connecting", conn->root->name); 374 } 375 else { 376 PROXY_LOG("%s: cannot connect to proxy: %s", root->name, errno_str); 377 return -1; 378 } 379 } 380 else { 381 PROXY_LOG("%s: immediate connection", root->name); 382 conn->state = STATE_CREATE_SOCKET_PAIR; 383 } 384 return 0; 385} 386 387static int 388rewrite_connection_create_sockets( RewriteConnection* conn ) 389{ 390 /* immediate connection to the proxy. now create a socket 391 * pair and send a 'success' event to slirp */ 392 int slirp_1; 393 ProxyConnection* root = conn->root; 394 395 if (socket_pair( &slirp_1, &conn->slirp_fd ) < 0) { 396 PROXY_LOG("%s: coult not create socket pair: %s", 397 root->name, errno_str); 398 return -1; 399 } 400 401 root->ev_func( root->ev_opaque, slirp_1, PROXY_EVENT_CONNECTED ); 402 conn->state = STATE_REQUEST_FIRST_LINE; 403 return 0; 404} 405 406 407/* read the first line of a given HTTP request. returns -1/0/+1 */ 408static DataStatus 409rewrite_connection_read_request( RewriteConnection* conn ) 410{ 411 ProxyConnection* root = conn->root; 412 DataStatus ret; 413 414 ret = proxy_connection_receive_line(root, conn->slirp_fd); 415 if (ret == DATA_COMPLETED) { 416 /* now parse the first line to see if we can handle it */ 417 char* line = root->str->s; 418 char* method; 419 char* uri; 420 char* version; 421 char* p = line; 422 423 method = strsep(&p, " "); 424 if (p == NULL) { 425 PROXY_LOG("%s: can't parse method in '%'", 426 root->name, line); 427 return DATA_ERROR; 428 } 429 uri = strsep(&p, " "); 430 if (p == NULL) { 431 PROXY_LOG( "%s: can't parse URI in '%s'", 432 root->name, line); 433 return DATA_ERROR; 434 } 435 version = strsep(&p, " "); 436 if (p != NULL) { 437 PROXY_LOG( "%s: extra data after version in '%s'", 438 root->name, line); 439 return DATA_ERROR; 440 } 441 if (conn->request) 442 http_request_free(conn->request); 443 444 conn->request = http_request_alloc( method, uri, version ); 445 if (!conn->request) 446 return DATA_ERROR; 447 448 proxy_connection_rewind(root); 449 } 450 return ret; 451} 452 453 454static DataStatus 455rewrite_connection_read_reply( RewriteConnection* conn ) 456{ 457 ProxyConnection* root = conn->root; 458 DataStatus ret; 459 460 ret = proxy_connection_receive_line( root, root->socket ); 461 if (ret == DATA_COMPLETED) { 462 HttpRequest* request = conn->request; 463 464 char* line = stralloc_cstr( root->str ); 465 char* p = line; 466 char* protocol; 467 char* number; 468 char* readable; 469 470 protocol = strsep(&p, " "); 471 if (p == NULL) { 472 PROXY_LOG("%s: can't parse response protocol: '%s'", 473 root->name, line); 474 return DATA_ERROR; 475 } 476 number = strsep(&p, " "); 477 if (p == NULL) { 478 PROXY_LOG("%s: can't parse response number: '%s'", 479 root->name, line); 480 return DATA_ERROR; 481 } 482 readable = p; 483 484 if (http_request_set_reply(request, protocol, number, readable) < 0) 485 return DATA_ERROR; 486 487 proxy_connection_rewind(root); 488 } 489 return ret; 490} 491 492 493static DataStatus 494rewrite_connection_read_headers( RewriteConnection* conn, 495 int fd ) 496{ 497 int ret; 498 ProxyConnection* root = conn->root; 499 500 for (;;) { 501 char* line; 502 stralloc_t* str = root->str; 503 504 ret = proxy_connection_receive_line(root, fd); 505 if (ret != DATA_COMPLETED) 506 break; 507 508 str->n = 0; 509 line = str->s; 510 511 if (line[0] == 0) { 512 /* an empty line means the end of headers */ 513 ret = 1; 514 break; 515 } 516 517 /* it this a continuation ? */ 518 if (line[0] == ' ' || line[0] == '\t') { 519 ret = http_request_add_to_last_header( conn->request, line ); 520 } 521 else { 522 char* key; 523 char* value; 524 525 value = line; 526 key = strsep(&value, ":"); 527 if (value == NULL) { 528 PROXY_LOG("%s: can't parse header '%s'", root->name, line); 529 ret = -1; 530 break; 531 } 532 value += strspn(value, " "); 533 if (http_request_add_header(conn->request, key, value) < 0) 534 ret = -1; 535 } 536 if (ret == DATA_ERROR) 537 break; 538 } 539 return ret; 540} 541 542static int 543rewrite_connection_rewrite_request( RewriteConnection* conn ) 544{ 545 ProxyConnection* root = conn->root; 546 HttpService* service = (HttpService*) root->service; 547 HttpRequest* r = conn->request; 548 stralloc_t* str = root->str; 549 HttpHeader* h; 550 551 proxy_connection_rewind(conn->root); 552 553 /* only rewrite the URI if it is not absolute */ 554 if (r->req_uri[0] == '/') { 555 char* host = http_request_find_header(r, "Host"); 556 if (host == NULL) { 557 PROXY_LOG("%s: uh oh, not Host: in request ?", root->name); 558 } else { 559 /* now create new URI */ 560 stralloc_add_str(str, "http://"); 561 stralloc_add_str(str, host); 562 stralloc_add_str(str, r->req_uri); 563 http_request_replace_uri(r, stralloc_cstr(str)); 564 proxy_connection_rewind(root); 565 } 566 } 567 568 stralloc_format( str, "%s %s %s\r\n", r->req_method, r->req_uri, r->req_version ); 569 for (h = r->headers->first; h; h = h->next) { 570 stralloc_add_format( str, "%s: %s\r\n", h->key, h->value ); 571 } 572 /* add the service's footer - includes final \r\n */ 573 stralloc_add_bytes( str, service->footer, service->footer_len ); 574 575 return 0; 576} 577 578static int 579rewrite_connection_rewrite_reply( RewriteConnection* conn ) 580{ 581 HttpRequest* r = conn->request; 582 ProxyConnection* root = conn->root; 583 stralloc_t* str = root->str; 584 HttpHeader* h; 585 586 proxy_connection_rewind(root); 587 stralloc_format(str, "%s %d %s\r\n", r->rep_version, r->rep_code, r->rep_readable); 588 for (h = r->headers->first; h; h = h->next) { 589 stralloc_add_format(str, "%s: %s\r\n", h->key, h->value); 590 } 591 stralloc_add_str(str, "\r\n"); 592 593 return 0; 594} 595 596 597static int 598rewrite_connection_get_body_length( RewriteConnection* conn, 599 int is_request ) 600{ 601 HttpRequest* r = conn->request; 602 ProxyConnection* root = conn->root; 603 char* content_length; 604 char* transfer_encoding; 605 606 conn->body_mode = BODY_NONE; 607 conn->body_length = 0; 608 conn->body_total = 0; 609 conn->body_sent = 0; 610 conn->body_is_closed = 0; 611 conn->body_is_full = 0; 612 conn->body_has_data = 0; 613 614 proxy_connection_rewind(root); 615 616 if (is_request) { 617 /* only POST and PUT should have a body */ 618 if (r->req_type != HTTP_REQUEST_POST && 619 r->req_type != HTTP_REQUEST_PUT) 620 { 621 return 0; 622 } 623 } else { 624 /* HTTP 1.1 Section 4.3 Message Body states that HEAD requests must not have 625 * a message body, as well as any 1xx, 204 and 304 replies */ 626 if (r->req_type == HTTP_REQUEST_HEAD || r->rep_code/100 == 1 || 627 r->rep_code == 204 || r->rep_code == 304) 628 return 0; 629 } 630 631 content_length = http_request_find_header(r, "Content-Length"); 632 if (content_length != NULL) { 633 char* end; 634 int64_t body_len = strtoll( content_length, &end, 10 ); 635 if (*end != '\0' || *content_length == '\0' || body_len < 0) { 636 PROXY_LOG("%s: bad content length: %s", root->name, content_length); 637 return DATA_ERROR; 638 } 639 if (body_len > 0) { 640 conn->body_mode = BODY_KNOWN_LENGTH; 641 conn->body_length = body_len; 642 } 643 } else { 644 char* connection = http_request_find_header(r, "Proxy-Connection"); 645 646 if (!connection) 647 connection = http_request_find_header(r, "Connection"); 648 649 if (!connection || strcasecmp(connection, "Close")) { 650 /* hum, we can't support this at all */ 651 PROXY_LOG("%s: can't determine content length, and client wants" 652 " to keep connection opened", 653 root->name); 654 return -1; 655 } 656 /* a negative value means that the data ends when the client 657 * disconnects the connection. 658 */ 659 conn->body_mode = BODY_UNTIL_CLOSE; 660 } 661 transfer_encoding = http_request_find_header(r, "Transfer-Encoding"); 662 if (transfer_encoding && !strcasecmp(transfer_encoding, "Chunked")) { 663 conn->body_mode = BODY_CHUNKED; 664 conn->parse_chunk_header = 0; 665 conn->parse_chunk_trailer = 0; 666 conn->chunk_length = -1; 667 conn->chunk_total = 0; 668 } 669 D("%s: body_length=%lld body_mode=%s", 670 root->name, conn->body_length, 671 body_mode_str[conn->body_mode]); 672 673 proxy_connection_rewind(root); 674 return 0; 675} 676 677#define MAX_BODY_BUFFER 65536 678 679static DataStatus 680rewrite_connection_read_body( RewriteConnection* conn, int fd ) 681{ 682 ProxyConnection* root = conn->root; 683 stralloc_t* str = root->str; 684 int wanted = 0, current, avail; 685 DataStatus ret; 686 687 if (conn->body_is_closed) { 688 return DATA_NEED_MORE; 689 } 690 691 /* first, determine how many bytes we want to read. */ 692 switch (conn->body_mode) { 693 case BODY_NONE: 694 D("%s: INTERNAL ERROR: SHOULDN'T BE THERE", root->name); 695 return DATA_COMPLETED; 696 697 case BODY_KNOWN_LENGTH: 698 { 699 if (conn->body_length == 0) 700 return DATA_COMPLETED; 701 702 if (conn->body_length > MAX_BODY_BUFFER) 703 wanted = MAX_BODY_BUFFER; 704 else 705 wanted = (int)conn->body_length; 706 } 707 break; 708 709 case BODY_UNTIL_CLOSE: 710 wanted = MAX_BODY_BUFFER; 711 break; 712 713 case BODY_CHUNKED: 714 if (conn->chunk_length < 0) { 715 /* chunk_length < 0 means we need to read a chunk header */ 716 /* ensure that 'str' is flushed before doing this */ 717 if (!conn->parse_chunk_header) { 718 if (conn->body_has_data) 719 return DATA_NEED_MORE; 720 D("%s: waiting chunk header", root->name); 721 conn->parse_chunk_header = 1; 722 } 723 ret = proxy_connection_receive_line(root, fd); 724 if (ret == DATA_COMPLETED) { 725 char* line = str->s; 726 char* end; 727 long long length; 728 729 length = strtoll(line, &end, 16); 730 if (line[0] == ' ' || (end[0] != '\0' && end[0] != ';')) { 731 PROXY_LOG("%s: invalid chunk header: %s", 732 root->name, line); 733 return DATA_ERROR; 734 } 735 if (length < 0) { 736 PROXY_LOG("%s: invalid chunk length %lld", 737 root->name, length); 738 return DATA_ERROR; 739 } 740 conn->chunk_length = length; 741 conn->chunk_total = 0; 742 if (length == 0) { 743 /* the last chunk, no we need to add the trailer */ 744 conn->parse_chunk_trailer = 0; 745 } 746 conn->parse_chunk_header = 0; 747 } 748 } 749 750 if (conn->chunk_length == 0) { 751 /* chunk_length == 0 means we're reading the chunk trailer */ 752 /* ensure that 'str' is flushed before reading the trailer */ 753 if (!conn->parse_chunk_trailer) { 754 if (conn->body_has_data) 755 return DATA_NEED_MORE; 756 conn->parse_chunk_trailer = 1; 757 } 758 ret = rewrite_connection_read_headers(conn, fd); 759 if (ret == DATA_COMPLETED) { 760 conn->body_is_closed = 1; 761 } 762 return ret; 763 } 764 765 /* if we get here, body_length > 0 */ 766 if (conn->chunk_length > MAX_BODY_BUFFER) 767 wanted = MAX_BODY_BUFFER; 768 else 769 wanted = (int)conn->chunk_length; 770 break; 771 772 default: 773 ; 774 } 775 776 /* we don't want more than MAX_BODY_BUFFER bytes in the 777 * buffer we used to pass the body */ 778 current = str->n; 779 avail = MAX_BODY_BUFFER - current; 780 if (avail <= 0) { 781 /* wait for some flush */ 782 conn->body_is_full = 1; 783 D("%s: waiting to flush %d bytes", 784 root->name, current); 785 return DATA_NEED_MORE; 786 } 787 788 if (wanted > avail) 789 wanted = avail; 790 791 ret = proxy_connection_receive(root, fd, wanted); 792 conn->body_has_data = (str->n > 0); 793 conn->body_is_full = (str->n == MAX_BODY_BUFFER); 794 795 if (ret == DATA_ERROR) { 796 if (conn->body_mode == BODY_UNTIL_CLOSE) { 797 /* a disconnection here is normal and signals the 798 * end of the body */ 799 conn->body_total += root->str_recv; 800 D("%s: body completed by close (%lld bytes)", 801 root->name, conn->body_total); 802 conn->body_is_closed = 1; 803 ret = DATA_COMPLETED; 804 } 805 } else { 806 avail = root->str_recv; 807 ret = DATA_NEED_MORE; /* we're not really done yet */ 808 809 switch (conn->body_mode) { 810 case BODY_CHUNKED: 811 conn->chunk_total += avail; 812 conn->chunk_length -= avail; 813 814 if (conn->chunk_length == 0) { 815 D("%s: chunk completed (%lld bytes)", 816 root->name, conn->chunk_length); 817 conn->body_total += conn->chunk_total; 818 conn->chunk_total = 0; 819 conn->chunk_length = -1; 820 } 821 break; 822 823 case BODY_KNOWN_LENGTH: 824 conn->body_length -= avail; 825 conn->body_total += avail; 826 827 if (conn->body_length == 0) { 828 D("%s: body completed (%lld bytes)", 829 root->name, conn->body_total); 830 conn->body_is_closed = 1; 831 ret = DATA_COMPLETED; 832 } 833 break; 834 835 case BODY_UNTIL_CLOSE: 836 conn->body_total += avail; 837 break; 838 839 default: 840 ; 841 } 842 } 843 return ret; 844} 845 846static DataStatus 847rewrite_connection_send_body( RewriteConnection* conn, int fd ) 848{ 849 ProxyConnection* root = conn->root; 850 stralloc_t* str = root->str; 851 DataStatus ret = DATA_NEED_MORE; 852 853 if (conn->body_has_data) { 854 ret = proxy_connection_send(root, fd); 855 if (ret != DATA_ERROR) { 856 int pos = root->str_pos; 857 858 memmove(str->s, str->s+pos, str->n-pos); 859 str->n -= pos; 860 root->str_pos = 0; 861 conn->body_is_full = (str->n == MAX_BODY_BUFFER); 862 conn->body_has_data = (str->n > 0); 863 conn->body_sent += root->str_sent; 864 865 /* ensure that we return DATA_COMPLETED only when 866 * we have sent everything, and there is no more 867 * body pieces to read */ 868 if (ret == DATA_COMPLETED) { 869 if (!conn->body_is_closed || conn->body_has_data) 870 ret = DATA_NEED_MORE; 871 else { 872 D("%s: sent all body (%lld bytes)", 873 root->name, conn->body_sent); 874 } 875 } 876 D("%s: sent closed=%d data=%d n=%d ret=%d", 877 root->name, conn->body_is_closed, 878 conn->body_has_data, str->n, 879 ret); 880 } 881 } 882 return ret; 883} 884 885 886static void 887rewrite_connection_select( ProxyConnection* root, 888 ProxySelect* sel ) 889{ 890 RewriteConnection* conn = (RewriteConnection*)root; 891 int slirp = conn->slirp_fd; 892 int proxy = root->socket; 893 894 switch (conn->state) { 895 case STATE_CONNECTING: 896 case STATE_CREATE_SOCKET_PAIR: 897 /* try to connect to the proxy server */ 898 proxy_select_set( sel, proxy, PROXY_SELECT_WRITE ); 899 break; 900 901 case STATE_REQUEST_FIRST_LINE: 902 case STATE_REQUEST_HEADERS: 903 proxy_select_set( sel, slirp, PROXY_SELECT_READ ); 904 break; 905 906 case STATE_REQUEST_SEND: 907 proxy_select_set( sel, proxy, PROXY_SELECT_WRITE ); 908 break; 909 910 case STATE_REQUEST_BODY: 911 if (!conn->body_is_closed && !conn->body_is_full) 912 proxy_select_set( sel, slirp, PROXY_SELECT_READ ); 913 914 if (conn->body_has_data) 915 proxy_select_set( sel, proxy, PROXY_SELECT_WRITE ); 916 break; 917 918 case STATE_REPLY_FIRST_LINE: 919 case STATE_REPLY_HEADERS: 920 proxy_select_set( sel, proxy, PROXY_SELECT_READ ); 921 break; 922 923 case STATE_REPLY_SEND: 924 proxy_select_set( sel, slirp, PROXY_SELECT_WRITE ); 925 break; 926 927 case STATE_REPLY_BODY: 928 if (conn->body_has_data) 929 proxy_select_set( sel, slirp, PROXY_SELECT_WRITE ); 930 931 if (!conn->body_is_closed && !conn->body_is_full) 932 proxy_select_set( sel, proxy, PROXY_SELECT_READ ); 933 break; 934 default: 935 ; 936 }; 937} 938 939static void 940rewrite_connection_poll( ProxyConnection* root, 941 ProxySelect* sel ) 942{ 943 RewriteConnection* conn = (RewriteConnection*)root; 944 945 int slirp = conn->slirp_fd; 946 int proxy = root->socket; 947 int has_slirp = proxy_select_poll(sel, slirp); 948 int has_proxy = proxy_select_poll(sel, proxy); 949 DataStatus ret = DATA_NEED_MORE; 950 951 switch (conn->state) { 952 case STATE_CONNECTING: 953 if (has_proxy) { 954 PROXY_LOG("%s: connected to proxy", root->name); 955 conn->state = STATE_CREATE_SOCKET_PAIR; 956 } 957 break; 958 959 case STATE_CREATE_SOCKET_PAIR: 960 if (has_proxy) { 961 if (rewrite_connection_create_sockets(conn) < 0) { 962 ret = DATA_ERROR; 963 } else { 964 D("%s: socket pair created", root->name); 965 conn->state = STATE_REQUEST_FIRST_LINE; 966 } 967 } 968 break; 969 970 case STATE_REQUEST_FIRST_LINE: 971 if (has_slirp) { 972 ret = rewrite_connection_read_request(conn); 973 if (ret == DATA_COMPLETED) { 974 PROXY_LOG("%s: request first line ok", root->name); 975 conn->state = STATE_REQUEST_HEADERS; 976 } 977 } 978 break; 979 980 case STATE_REQUEST_HEADERS: 981 if (has_slirp) { 982 ret = rewrite_connection_read_headers(conn, slirp); 983 if (ret == DATA_COMPLETED) { 984 PROXY_LOG("%s: request headers ok", root->name); 985 if (rewrite_connection_rewrite_request(conn) < 0) 986 ret = DATA_ERROR; 987 else 988 conn->state = STATE_REQUEST_SEND; 989 } 990 } 991 break; 992 993 case STATE_REQUEST_SEND: 994 if (has_proxy) { 995 ret = proxy_connection_send(root, proxy); 996 if (ret == DATA_COMPLETED) { 997 if (rewrite_connection_get_body_length(conn, 1) < 0) { 998 ret = DATA_ERROR; 999 } else if (conn->body_mode != BODY_NONE) { 1000 PROXY_LOG("%s: request sent, waiting for body", 1001 root->name); 1002 conn->state = STATE_REQUEST_BODY; 1003 } else { 1004 PROXY_LOG("%s: request sent, waiting for reply", 1005 root->name); 1006 conn->state = STATE_REPLY_FIRST_LINE; 1007 } 1008 } 1009 } 1010 break; 1011 1012 case STATE_REQUEST_BODY: 1013 if (has_slirp) { 1014 ret = rewrite_connection_read_body(conn, slirp); 1015 } 1016 if (ret != DATA_ERROR && has_proxy) { 1017 ret = rewrite_connection_send_body(conn, proxy); 1018 if (ret == DATA_COMPLETED) { 1019 PROXY_LOG("%s: request body ok, waiting for reply", 1020 root->name); 1021 conn->state = STATE_REPLY_FIRST_LINE; 1022 } 1023 } 1024 break; 1025 1026 case STATE_REPLY_FIRST_LINE: 1027 if (has_proxy) { 1028 ret = rewrite_connection_read_reply(conn); 1029 if (ret == DATA_COMPLETED) { 1030 PROXY_LOG("%s: reply first line ok", root->name); 1031 conn->state = STATE_REPLY_HEADERS; 1032 } 1033 } 1034 break; 1035 1036 case STATE_REPLY_HEADERS: 1037 if (has_proxy) { 1038 ret = rewrite_connection_read_headers(conn, proxy); 1039 if (ret == DATA_COMPLETED) { 1040 PROXY_LOG("%s: reply headers ok", root->name); 1041 if (rewrite_connection_rewrite_reply(conn) < 0) 1042 ret = DATA_ERROR; 1043 else 1044 conn->state = STATE_REPLY_SEND; 1045 } 1046 } 1047 break; 1048 1049 case STATE_REPLY_SEND: 1050 if (has_slirp) { 1051 ret = proxy_connection_send(conn->root, slirp); 1052 if (ret == DATA_COMPLETED) { 1053 if (rewrite_connection_get_body_length(conn, 0) < 0) { 1054 ret = DATA_ERROR; 1055 } else if (conn->body_mode != BODY_NONE) { 1056 PROXY_LOG("%s: reply sent, waiting for body", 1057 root->name); 1058 conn->state = STATE_REPLY_BODY; 1059 } else { 1060 PROXY_LOG("%s: reply sent, looping to waiting request", 1061 root->name); 1062 conn->state = STATE_REQUEST_FIRST_LINE; 1063 } 1064 } 1065 } 1066 break; 1067 1068 case STATE_REPLY_BODY: 1069 if (has_proxy) { 1070 ret = rewrite_connection_read_body(conn, proxy); 1071 } 1072 if (ret != DATA_ERROR && has_slirp) { 1073 ret = rewrite_connection_send_body(conn, slirp); 1074 if (ret == DATA_COMPLETED) { 1075 if (conn->body_mode == BODY_UNTIL_CLOSE) { 1076 PROXY_LOG("%s: closing connection", root->name); 1077 ret = DATA_ERROR; 1078 } else { 1079 PROXY_LOG("%s: reply body ok, looping to waiting request", 1080 root->name); 1081 conn->state = STATE_REQUEST_FIRST_LINE; 1082 } 1083 } 1084 } 1085 break; 1086 1087 default: 1088 ; 1089 } 1090 if (ret == DATA_ERROR) 1091 proxy_connection_free(root, 0, PROXY_EVENT_NONE); 1092 1093 return; 1094} 1095 1096 1097ProxyConnection* 1098http_rewriter_connect( HttpService* service, 1099 SockAddress* address ) 1100{ 1101 RewriteConnection* conn; 1102 int s; 1103 1104 s = socket_create_inet( SOCKET_STREAM ); 1105 if (s < 0) 1106 return NULL; 1107 1108 conn = qemu_mallocz(sizeof(*conn)); 1109 if (conn == NULL) { 1110 socket_close(s); 1111 return NULL; 1112 } 1113 1114 proxy_connection_init( conn->root, s, address, service->root, 1115 rewrite_connection_free, 1116 rewrite_connection_select, 1117 rewrite_connection_poll ); 1118 1119 if ( rewrite_connection_init( conn ) < 0 ) { 1120 rewrite_connection_free( conn->root ); 1121 return NULL; 1122 } 1123 1124 return conn->root; 1125} 1126