/t/22-chunked-put.t

http://github.com/perlbal/Perlbal · Perl · 186 lines · 139 code · 31 blank · 16 comment · 19 complexity · 726181d3077d1dc64257f04a74a3be44 MD5 · raw file

  1. #!/usr/bin/perl
  2. use strict;
  3. use Perlbal::Test;
  4. use IO::Socket::INET;
  5. use Test::More 'no_plan';
  6. my $port = new_port();
  7. my $dir = tempdir();
  8. my $conf = qq{
  9. SERVER aio_mode = none
  10. CREATE SERVICE test
  11. SET test.role = web_server
  12. SET test.listen = 127.0.0.1:$port
  13. SET test.docroot = $dir
  14. SET test.dirindexing = 0
  15. SET test.enable_put = 1
  16. SET test.enable_delete = 1
  17. SET test.min_put_directory = 0
  18. SET test.persist_client = 1
  19. ENABLE test
  20. };
  21. my $msock = start_server($conf);
  22. my $ua = ua();
  23. ok($ua);
  24. require HTTP::Request;
  25. my $url = "http://127.0.0.1:$port/foo.txt";
  26. my $disk_file = "$dir/foo.txt";
  27. my $contentlen = 0;
  28. my $written_content = "";
  29. sub buffer_file_exists {
  30. -e $disk_file;
  31. }
  32. # cmds can be:
  33. # write:<length> writes <length> bytes
  34. # sleep:<duration> sleeps <duration> seconds, may be fractional
  35. # finish (sends any final writes and/or reads response)
  36. # close close socket
  37. # sub {} coderef to run. gets passed response object
  38. # no-reason response has no reason
  39. # reason:<reason> did buffering for either "size", "rate", or "time"
  40. # empty No files in temp buffer location
  41. # exists Yes, a temporary file exists
  42. sub request {
  43. my $testname = shift;
  44. my $len = shift || 0;
  45. my @cmds = @_;
  46. my $curpos = 0;
  47. my $remain = $len;
  48. $contentlen = 0;
  49. $written_content = "";
  50. my $hdr = "PUT /foo.txt HTTP/1.0\r\nTransfer-Encoding: chunked\r\nExpect: 100-continue\r\n\r\n";
  51. my $sock = IO::Socket::INET->new( PeerAddr => "127.0.0.1:$port" )
  52. or return undef;
  53. my $rv = syswrite($sock, $hdr);
  54. die unless $rv == length($hdr);
  55. # wanting HTTP/1.1 100 Continue\r\n...\r\n lines
  56. {
  57. my $contline = <$sock>;
  58. die "didn't get 100 Continue line, got: $contline"
  59. unless $contline =~ m!^HTTP/1.1 100!;
  60. my $gotempty = 0;
  61. while (defined(my $line = <$sock>)) {
  62. if ($line eq "\r\n") {
  63. $gotempty = 1;
  64. last;
  65. }
  66. }
  67. die "didn't get empty line after 100 Continue" unless $gotempty;
  68. }
  69. my $res = undef; # no response yet
  70. foreach my $cmd (@cmds) {
  71. my $writelen;
  72. if ($cmd =~ /^write:([\d_]+)/) {
  73. $writelen = $1;
  74. $writelen =~ s/_//g;
  75. } elsif ($cmd =~ /^(\d+)/) {
  76. $writelen = $1;
  77. } elsif ($cmd eq "finish") {
  78. $writelen = $remain;
  79. }
  80. if ($cmd =~ /^sleep:([\d\.]+)/) {
  81. select undef, undef, undef, $1;
  82. next;
  83. }
  84. if ($cmd eq "close") {
  85. close($sock);
  86. next;
  87. }
  88. if ($cmd eq "exists") {
  89. ok(buffer_file_exists(), "$testname: buffer file exists");
  90. next;
  91. }
  92. if ($writelen) {
  93. diag("Writing: $writelen");
  94. die "Too long" if $writelen > $remain;
  95. my $buf = chr(int(rand(26)) + 65) x $writelen;
  96. # update what we'll be checking for later,
  97. $contentlen += $writelen;
  98. $written_content .= $buf;
  99. $buf = sprintf("%x\r\n", $writelen) . $buf . "\r\n";
  100. $remain -= $writelen;
  101. if ($remain == 0) {
  102. # one \r\n for chunk ending, one for chunked-body ending,
  103. # after (our empty) trailer...
  104. $buf .= "0\r\n\r\n";
  105. }
  106. my $bufsize = length($buf);
  107. my $off = 0;
  108. while ($off < $bufsize) {
  109. my $rv = syswrite($sock, $buf, $bufsize-$off, $off);
  110. die "Error writing: $!, we had finished $off of $bufsize" unless defined $rv;
  111. die "Got rv=0 from syswrite" unless $rv;
  112. $off += $rv;
  113. }
  114. next unless $cmd eq "finish";
  115. }
  116. if ($cmd eq "finish") {
  117. $res = resp_from_sock($sock);
  118. my $clen = $res ? $res->header('Content-Length') : 0;
  119. ok($res && length($res->content) == $clen, "$testname: good response");
  120. next;
  121. }
  122. if (ref $cmd eq "CODE") {
  123. $cmd->($res, $testname);
  124. next;
  125. }
  126. die "Invalid command: $cmd\n";
  127. }
  128. }
  129. sub delete_file {
  130. my $req = HTTP::Request->new(DELETE => $url);
  131. my $res = $ua->request($req);
  132. return $res->is_success;
  133. }
  134. sub verify_put {
  135. open(my $fh, $disk_file) or die;
  136. my $slurp = do { local $/; <$fh>; };
  137. ok(-s $disk_file == $contentlen && $slurp eq $written_content, "verified put");
  138. }
  139. # disable all of it
  140. request("buffer_off", 500_000,
  141. "write:500",
  142. "write:5",
  143. "write:5",
  144. "write:5",
  145. "sleep:0.25",
  146. "exists",
  147. "write:100000",
  148. "write:60000",
  149. "write:1000",
  150. "finish",
  151. sub {
  152. verify_put();
  153. },
  154. );
  155. 1;