Project

General

Profile

Feature #3622 ยป expect-continue.3.diff

drbrain (Eric Hodel), 09/11/2010 05:26 AM

View differences:

lib/net/http.rb (working copy)
517 517
      @started = false
518 518
      @open_timeout = nil
519 519
      @read_timeout = 60
520
      @continue_timeout = nil
520 521
      @debug_output = nil
521 522
      @use_ssl = false
522 523
      @ssl_context = nil
......
570 571
      @read_timeout = sec
571 572
    end
572 573

  
574
    # Seconds to wait for 100 Continue response.  If the HTTP object does not
575
    # receive a response in this many seconds it sends the request body.
576
    attr_reader :continue_timeout
577

  
578
    # Setter for the continue_timeout attribute.
579
    def continue_timeout=(sec)
580
      @socket.continue_timeout = sec if @socket
581
      @continue_timeout = sec
582
    end
583

  
573 584
    # returns true if the HTTP session is started.
574 585
    def started?
575 586
      @started
......
660 671
      end
661 672
      @socket = BufferedIO.new(s)
662 673
      @socket.read_timeout = @read_timeout
674
      @socket.continue_timeout = @continue_timeout
663 675
      @socket.debug_output = @debug_output
664 676
      if use_ssl?
665 677
        if proxy?
......
1190 1202

  
1191 1203
    def transport_request(req)
1192 1204
      begin_transport req
1193
      req.exec @socket, @curr_http_version, edit_path(req.path)
1194
      begin
1195
        res = HTTPResponse.read_new(@socket)
1196
      end while res.kind_of?(HTTPContinue)
1197
      res.reading_body(@socket, req.response_body_permitted?) {
1198
        yield res if block_given?
1205
      res = catch(:response) {
1206
        req.exec @socket, @curr_http_version, edit_path(req.path)
1207
        begin
1208
          res = HTTPResponse.read_new(@socket)
1209
        end while res.kind_of?(HTTPContinue)
1210
        res.reading_body(@socket, req.response_body_permitted?) {
1211
          yield res if block_given?
1212
        }
1213
        res
1199 1214
      }
1200 1215
      end_transport req, res
1201 1216
      res
......
1740 1755
      delete 'Transfer-Encoding'
1741 1756
      supply_default_content_type
1742 1757
      write_header sock, ver, path
1758
      wait_for_continue sock, ver if sock.continue_timeout
1743 1759
      sock.write body
1744 1760
    end
1745 1761

  
......
1750 1766
      end
1751 1767
      supply_default_content_type
1752 1768
      write_header sock, ver, path
1769
      wait_for_continue sock, ver if sock.continue_timeout
1753 1770
      if chunked?
1754 1771
        while s = f.read(1024)
1755 1772
          sock.write(sprintf("%x\r\n", s.length) << s << "\r\n")
......
1768 1785
      set_content_type 'application/x-www-form-urlencoded'
1769 1786
    end
1770 1787

  
1788
    ##
1789
    # Waits up to the continue timeout for a response from the server provided
1790
    # we're speaking HTTP 1.1 and are expecting a 100-continue response.
1791

  
1792
    def wait_for_continue(sock, ver)
1793
      if ver >= '1.1' and @header['expect'] and
1794
          @header['expect'].include?('100-continue') then
1795
        if IO.select [sock.io], nil, nil, sock.continue_timeout then
1796
          res = HTTPResponse.read_new sock
1797
          unless res.kind_of?(Net::HTTPContinue)
1798
            throw :response, res
1799
          end
1800
        end
1801
      end
1802
    end
1803

  
1771 1804
    def write_header(sock, ver, path)
1772 1805
      buf = "#{@method} #{path} HTTP/#{ver}\r\n"
1773 1806
      each_capitalized do |k,v|
lib/net/protocol.rb (working copy)
50 50
    def initialize(io)
51 51
      @io = io
52 52
      @read_timeout = 60
53
      @continue_timeout = nil
53 54
      @debug_output = nil
54 55
      @rbuf = ''
55 56
    end
56 57

  
57 58
    attr_reader :io
58 59
    attr_accessor :read_timeout
60
    attr_accessor :continue_timeout
59 61
    attr_accessor :debug_output
60 62

  
61 63
    def inspect
test/net/http/test_http.rb (working copy)
372 372
  end
373 373
end
374 374

  
375
class TestNetHTTPContinue < Test::Unit::TestCase
376
  CONFIG = {
377
    'host' => '127.0.0.1',
378
    'port' => 10081,
379
    'proxy_host' => nil,
380
    'proxy_port' => nil,
381
    'chunked' => true,
382
  }
383

  
384
  include TestNetHTTPUtils
385

  
386
  def logfile
387
    @debug = StringIO.new('')
388
  end
389

  
390
  def mount_proc(&block)
391
    @server.mount('/continue', WEBrick::HTTPServlet::ProcHandler.new(block.to_proc))
392
  end
393

  
394
  def test_expect_continue
395
    mount_proc {|req, res|
396
      req.continue
397
      res.body = req.query['body']
398
    }
399
    start {|http|
400
      http.continue_timeout = 0.2
401
      http.request_post('/continue', 'body=BODY', 'expect' => '100-continue') {|res|
402
        assert_equal('BODY', res.read_body)
403
      }
404
    }
405
    assert_match(/Expect: 100-continue/, @debug.string)
406
    assert_match(/HTTP\/1.1 100 continue/, @debug.string)
407
  end
408

  
409
  def test_expect_continue_timeout
410
    mount_proc {|req, res|
411
      sleep 0.2
412
      req.continue # just ignored because it's '100'
413
      res.body = req.query['body']
414
    }
415
    start {|http|
416
      http.continue_timeout = 0
417
      http.request_post('/continue', 'body=BODY', 'expect' => '100-continue') {|res|
418
        assert_equal('BODY', res.read_body)
419
      }
420
    }
421
    assert_match(/Expect: 100-continue/, @debug.string)
422
    assert_match(/HTTP\/1.1 100 continue/, @debug.string)
423
  end
424

  
425
  def test_expect_continue_error
426
    mount_proc {|req, res|
427
      res.status = 501
428
      res.body = req.query['body']
429
    }
430
    start {|http|
431
      http.continue_timeout = 0
432
      http.request_post('/continue', 'body=ERROR', 'expect' => '100-continue') {|res|
433
        assert_equal('ERROR', res.read_body)
434
      }
435
    }
436
    assert_match(/Expect: 100-continue/, @debug.string)
437
    assert_not_match(/HTTP\/1.1 100 continue/, @debug.string)
438
  end
439

  
440
  def test_expect_continue_error_while_waiting
441
    mount_proc {|req, res|
442
      res.status = 501
443
      res.body = req.query['body']
444
    }
445
    start {|http|
446
      http.continue_timeout = 0.5
447
      http.request_post('/continue', 'body=ERROR', 'expect' => '100-continue') {|res|
448
        assert_equal('ERROR', res.read_body)
449
      }
450
    }
451
    assert_match(/Expect: 100-continue/, @debug.string)
452
    assert_not_match(/HTTP\/1.1 100 continue/, @debug.string)
453
  end
454
end
455

  
375 456
=begin
376 457
class TestNetHTTP_proxy < Test::Unit::TestCase
377 458
  CONFIG = {