Changeset 617
- Timestamp:
- 01/17/07 07:05:55 (2 years ago)
- Files:
-
- trunk/CHANGES (modified) (1 diff)
- trunk/MANIFEST (modified) (3 diffs)
- trunk/META.yml (modified) (1 diff)
- trunk/doc/http-versions.txt (added)
- trunk/lib/Perlbal/ChunkedUploadState.pm (added)
- trunk/lib/Perlbal/ClientProxy.pm (modified) (11 diffs)
- trunk/t/52-chunked-upload.t (added)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/CHANGES
r613 r617 1 -- supported for "Transfer-Encoding: chunked" requests (HTTP/1.1 feature) 2 as well as the "Expect: 100-continue", which generally accompany 3 chunked requests. requires "buffered_uploads" be enabled. see 4 doc/http-versions.txt for details. 5 1 6 1.53: 2006-12-05 2 7 trunk/MANIFEST
r584 r617 7 7 lib/Perlbal/BackendHTTP.pm 8 8 lib/Perlbal/Cache.pm 9 lib/Perlbal/ChunkedUploadState.pm 9 10 lib/Perlbal/ClientHTTP.pm 10 11 lib/Perlbal/ClientHTTPBase.pm … … 33 34 META.yml Module meta-data (added by MakeMaker) 34 35 devtools/gendocs.pl 36 doc/http-versions.txt 35 37 doc/config-guide.txt 36 38 doc/service-parameters.txt … … 59 61 t/45-buffereduploads.t 60 62 t/50-plugins.t 63 t/52-chunked-upload.t 61 64 trunk/META.yml
r607 r617 2 2 #XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX# 3 3 name: Perlbal 4 version: 1.5 24 version: 1.53 5 5 version_from: lib/Perlbal.pm 6 6 installdirs: site trunk/lib/Perlbal/ClientProxy.pm
r612 r617 10 10 use base "Perlbal::ClientHTTPBase"; 11 11 no warnings qw(deprecated); 12 13 use Perlbal::ChunkedUploadState; 12 14 13 15 use fields ( … … 36 38 'backend_stalled', # boolean: if backend has shut off its reads because we're too slow. 37 39 'unread_data_waiting', # boolean: if we shut off reads while we know data is yet to be read from client 40 'chunked_upload_state', # bool/obj: if processing a chunked upload, Perlbal::ChunkedUploadState object, else undef 41 'request_body_length', # integer: request's body length, either as-declared, 42 # or calculated after chunked upload is complete 38 43 39 44 # for perlbal sending out UDP packets related to upload status (for xmlhttprequest upload bar) … … 99 104 $self->{buoutpos} = 0; 100 105 $self->{bureason} = undef; 106 $self->{chunked_upload_state} = undef; 107 $self->{request_body_length} = undef; 101 108 102 109 $self->{reproxy_uris} = undef; … … 467 474 $self->{bureason} = undef; 468 475 $self->{upload_session} = undef; 476 $self->{chunked_upload_state} = undef; 477 $self->{request_body_length} = undef; 469 478 return 1; 470 479 } … … 569 578 print " disabling reads.\n" if Perlbal::DEBUG >= 3; 570 579 $self->watch_read(0); 580 return; 581 } 582 583 # deal with chunked uploads 584 if (my $cus = $self->{chunked_upload_state}) { 585 $cus->on_readable($self); 586 587 # if we got more than 1MB not flushed to disk, 588 # stop reading for a bit until disk catches up 589 if ($self->{read_ahead} > 1024*1024) { 590 $self->watch_read(0); 591 } 571 592 return; 572 593 } … … 713 734 return if $svc->run_hook('start_http_request', $self); 714 735 715 # if defined we're waiting on some amount of data. also, we have to 716 # subtract out read_size, which is the amount of data that was 717 # extra in the packet with the header that's part of the body. 718 $self->{content_length_remain} = $req_hd->content_length; 719 $self->{unread_data_waiting} = 1 if $self->{content_length_remain}; 736 if ($self->handle_chunked_upload) { 737 # handled in method. 738 } else { 739 # if defined we're waiting on some amount of data. also, we have to 740 # subtract out read_size, which is the amount of data that was 741 # extra in the packet with the header that's part of the body. 742 $self->{request_body_length} = 743 $self->{content_length_remain} = 744 $req_hd->content_length; 745 $self->{unread_data_waiting} = 1 if $self->{content_length_remain}; 746 } 720 747 721 748 # upload-tracking stuff. both starting a new upload track session, … … 729 756 # either start buffering some of the request to memory, or 730 757 # immediately request a backend connection. 731 if ($self->{content_length_remain} && $self->{service}->{buffer_backend_connect}) { 758 if ($self->{chunked_upload_state}) { 759 $self->{request_body_length} = 0; 760 $self->{is_buffering} = 1; 761 $self->{bureason} = 'chunked'; 762 $self->buffered_upload_update; 763 } elsif ($self->{content_length_remain} && $self->{service}->{buffer_backend_connect}) { 732 764 # the deeper path 733 765 $self->start_buffering_request; … … 741 773 $self->request_backend; 742 774 } 775 } 776 777 sub handle_chunked_upload { 778 my Perlbal::ClientProxy $self = shift; 779 my $req_hd = $self->{req_headers}; 780 my $te = $req_hd->header("Transfer-Encoding"); 781 return unless $te && $te eq "chunked"; 782 return unless $self->{service}->{buffer_uploads}; 783 784 $req_hd->header("Transfer-Encoding", undef); # remove it (won't go to backend) 785 786 # TODO: return false if we don't have buffered upload dir configured 787 my $eh = $req_hd->header("Expect"); 788 if ($eh && $eh =~ /\b100-continue\b/) { 789 $self->write(\ "HTTP/1.1 100 Continue\r\n\r\n"); 790 $req_hd->header("Expect", undef); # remove it (won't go to backend) 791 } 792 793 my $args = { 794 on_new_chunk => sub { 795 my $cref = shift; 796 my $len = length($$cref); 797 push @{$self->{read_buf}}, $cref; 798 $self->{read_ahead} += $len; 799 $self->{request_body_length} += $len; 800 # TODO: if too large, disconnect? 801 $self->buffered_upload_update; 802 }, 803 on_disconnect => sub { 804 $self->client_disconnected; 805 }, 806 on_zero_chunk => sub { 807 $self->send_buffered_upload; 808 }, 809 }; 810 811 $self->{chunked_upload_state} = Perlbal::ChunkedUploadState->new(%$args); 812 return 1; 743 813 } 744 814 … … 915 985 916 986 # make sure our buoutpos is the same as the content length... 987 return if $self->{is_writing}; 988 989 # set the content-length that goes to the backend... 990 if ($self->{chunked_upload_state}) { 991 $self->{req_headers}->header("Content-Length", $self->{request_body_length}); 992 } 993 917 994 my $clen = $self->{req_headers}->content_length; 918 995 if ($clen != $self->{buoutpos}) { … … 935 1012 936 1013 # now send the data 937 my $clen = $self->{req_headers}->content_length; 1014 my $clen = $self->{request_body_length}; 1015 938 1016 my $sent = Perlbal::Socket::sendfile($be->{fd}, fileno($self->{bufh}), $clen - $self->{buoutpos}); 939 1017 if ($sent < 0) { … … 1017 1095 } 1018 1096 1097 # if we're processing a chunked upload, ... 1098 if ($self->{chunked_upload_state}) { 1099 # turn reads back on, if we haven't hit the end yet. 1100 if ($self->{unread_data_waiting} && $self->{read_ahead} < 1024*1024) { 1101 $self->watch_read(1); 1102 $self->{unread_data_waiting} = 0; 1103 } 1104 1105 if ($self->{read_ahead} == 0 && $self->{chunked_upload_state}->hit_zero_chunk) { 1106 $self->watch_read(0); 1107 $self->send_buffered_upload; 1108 return; 1109 } 1110 } 1111 1019 1112 # if we're done (no clr and no read ahead!) then send it 1020 if ($self->{read_ahead} <= 0 && $self->{content_length_remain} <= 0) {1113 elsif ($self->{read_ahead} <= 0 && $self->{content_length_remain} <= 0) { 1021 1114 $self->send_buffered_upload; 1022 1115 return;
