Project

General

Profile

Feature #3622 ยป expect-continue.diff

nahi (Hiroshi Nakamura), 09/10/2010 07:40 PM

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
......
1190 1201

  
1191 1202
    def transport_request(req)
1192 1203
      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?
1204
      res = catch(:response) {
1205
        req.exec @socket, @curr_http_version, edit_path(req.path)
1206
        begin
1207
          res = HTTPResponse.read_new(@socket)
1208
        end while res.kind_of?(HTTPContinue)
1209
        res.reading_body(@socket, req.response_body_permitted?) {
1210
          yield res if block_given?
1211
        }
1212
        res
1199 1213
      }
1200 1214
      end_transport req, res
1201 1215
      res
......
1739 1753
      self.content_length = body.bytesize
1740 1754
      delete 'Transfer-Encoding'
1741 1755
      supply_default_content_type
1756
      wait_for_continue sock, ver if sock.continue_timeout
1742 1757
      write_header sock, ver, path
1743 1758
      sock.write body
1744 1759
    end
......
1749 1764
            "Content-Length not given and Transfer-Encoding is not `chunked'"
1750 1765
      end
1751 1766
      supply_default_content_type
1767
      wait_for_continue sock, ver if sock.continue_timeout
1752 1768
      write_header sock, ver, path
1753 1769
      if chunked?
1754 1770
        while s = f.read(1024)
......
1768 1784
      set_content_type 'application/x-www-form-urlencoded'
1769 1785
    end
1770 1786

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

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

  
1771 1803
    def write_header(sock, ver, path)
1772 1804
      buf = "#{@method} #{path} HTTP/#{ver}\r\n"
1773 1805
      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 = {