# -*- encoding: utf-8 -*- require File.expand_path('helper', File.dirname(__FILE__)) class TestHTTPClient < Test::Unit::TestCase include Helper include HTTPClient::Util def setup super setup_server setup_client end def teardown super end def test_initialize setup_proxyserver escape_noproxy do @proxyio.string = "" @client = HTTPClient.new(proxyurl) assert_equal(urify(proxyurl), @client.proxy) assert_equal(200, @client.head(serverurl).status) assert(/accept/ =~ @proxyio.string) end end def test_agent_name @client = HTTPClient.new(nil, "agent_name_foo") str = "" @client.debug_dev = str @client.get(serverurl) lines = str.split(/(?:\r?\n)+/) assert_equal("= Request", lines[0]) assert_match(/^User-Agent: agent_name_foo \(#{HTTPClient::VERSION}/, lines[4]) end def test_from @client = HTTPClient.new(nil, nil, "from_bar") str = "" @client.debug_dev = str @client.get(serverurl) lines = str.split(/(?:\r?\n)+/) assert_equal("= Request", lines[0]) assert_match(/^From: from_bar/, lines[4]) end def test_debug_dev str = "" @client.debug_dev = str assert_equal(str.object_id, @client.debug_dev.object_id) assert(str.empty?) @client.get(serverurl) assert(!str.empty?) end def test_debug_dev_stream str = "" @client.debug_dev = str conn = @client.get_async(serverurl) Thread.pass while !conn.finished? assert(!str.empty?) end def test_protocol_version_http09 @client.protocol_version = 'HTTP/0.9' @client.debug_dev = str = '' @client.test_loopback_http_response << "hello\nworld\n" res = @client.get(serverurl + 'hello') assert_equal('0.9', res.http_version) assert_equal(nil, res.status) assert_equal(nil, res.reason) assert_equal("hello\nworld\n", res.content) lines = str.split(/(?:\r?\n)+/) assert_equal("= Request", lines[0]) assert_equal("! CONNECTION ESTABLISHED", lines[2]) assert_equal("GET /hello HTTP/0.9", lines[3]) assert_equal("Connection: close", lines[6]) assert_equal("= Response", lines[7]) assert_match(/^hello$/, lines[8]) assert_match(/^world$/, lines[9]) end def test_protocol_version_http10 assert_equal(nil, @client.protocol_version) @client.protocol_version = 'HTTP/1.0' assert_equal('HTTP/1.0', @client.protocol_version) str = "" @client.debug_dev = str @client.get(serverurl + 'hello') lines = str.split(/(?:\r?\n)+/) assert_equal("= Request", lines[0]) assert_equal("! CONNECTION ESTABLISHED", lines[2]) assert_equal("GET /hello HTTP/1.0", lines[3]) assert_equal("Connection: close", lines[6]) assert_equal("= Response", lines[7]) end def test_header_accept_by_default str = "" @client.debug_dev = str @client.get(serverurl) lines = str.split(/(?:\r?\n)+/) assert_equal("Accept: */*", lines[4]) end def test_header_accept str = "" @client.debug_dev = str @client.get(serverurl, :header => {:Accept => 'text/html'}) lines = str.split(/(?:\r?\n)+/) assert_equal("Accept: text/html", lines[4]) end def test_host_given str = "" @client.debug_dev = str @client.get(serverurl) lines = str.split(/(?:\r?\n)+/) assert_equal("= Request", lines[0]) assert_equal("! CONNECTION ESTABLISHED", lines[2]) assert_equal("GET / HTTP/1.1", lines[3]) assert_equal("Host: localhost:#{serverport}", lines[6]) # @client.reset_all str = "" @client.debug_dev = str @client.get(serverurl, nil, {'Host' => 'foo'}) lines = str.split(/(?:\r?\n)+/) assert_equal("= Request", lines[0]) assert_equal("! CONNECTION ESTABLISHED", lines[2]) assert_equal("GET / HTTP/1.1", lines[3]) assert_equal("Host: foo", lines[4]) # use given param end def test_redirect_returns_not_modified assert_nothing_raised do timeout(2) do @client.get(serverurl + 'status', {:status => 306}, {:follow_redirect => true}) end end end def test_protocol_version_http11 assert_equal(nil, @client.protocol_version) str = "" @client.debug_dev = str @client.get(serverurl) lines = str.split(/(?:\r?\n)+/) assert_equal("= Request", lines[0]) assert_equal("! CONNECTION ESTABLISHED", lines[2]) assert_equal("GET / HTTP/1.1", lines[3]) assert_equal("Host: localhost:#{serverport}", lines[6]) @client.protocol_version = 'HTTP/1.1' assert_equal('HTTP/1.1', @client.protocol_version) str = "" @client.debug_dev = str @client.get(serverurl) lines = str.split(/(?:\r?\n)+/) assert_equal("= Request", lines[0]) assert_equal("! CONNECTION ESTABLISHED", lines[2]) assert_equal("GET / HTTP/1.1", lines[3]) @client.protocol_version = 'HTTP/1.0' str = "" @client.debug_dev = str @client.get(serverurl) lines = str.split(/(?:\r?\n)+/) assert_equal("= Request", lines[0]) assert_equal("! CONNECTION ESTABLISHED", lines[2]) assert_equal("GET / HTTP/1.0", lines[3]) end def test_proxy setup_proxyserver escape_noproxy do begin @client.proxy = "http://" rescue assert_match(/InvalidURIError/, $!.class.to_s) end @client.proxy = "" assert_nil(@client.proxy) @client.proxy = "http://admin:admin@foo:1234" assert_equal(urify("http://admin:admin@foo:1234"), @client.proxy) uri = urify("http://bar:2345") @client.proxy = uri assert_equal(uri, @client.proxy) # @proxyio.string = "" @client.proxy = nil assert_equal(200, @client.head(serverurl).status) assert(/accept/ !~ @proxyio.string) # @proxyio.string = "" @client.proxy = proxyurl @client.debug_dev = str = "" assert_equal(200, @client.head(serverurl).status) assert(/accept/ =~ @proxyio.string) assert(/Host: localhost:#{serverport}/ =~ str) end end def test_host_header @client.proxy = proxyurl @client.debug_dev = str = "" @client.test_loopback_http_response << "HTTP/1.0 200 OK\r\n\r\n" assert_equal(200, @client.head('http://www.example.com/foo').status) # ensure no ':80' is added. some servers dislike that. assert(/\r\nHost: www\.example\.com\r\n/ =~ str) # @client.debug_dev = str = "" @client.test_loopback_http_response << "HTTP/1.0 200 OK\r\n\r\n" assert_equal(200, @client.head('http://www.example.com:12345/foo').status) # ensure ':12345' exists. assert(/\r\nHost: www\.example\.com:12345\r\n/ =~ str) end def test_proxy_env setup_proxyserver escape_env do ENV['http_proxy'] = "http://admin:admin@foo:1234" ENV['NO_PROXY'] = "foobar" client = HTTPClient.new assert_equal(urify("http://admin:admin@foo:1234"), client.proxy) assert_equal('foobar', client.no_proxy) end end def test_proxy_env_cgi setup_proxyserver escape_env do ENV['REQUEST_METHOD'] = 'GET' # CGI environment emulation ENV['http_proxy'] = "http://admin:admin@foo:1234" ENV['no_proxy'] = "foobar" client = HTTPClient.new assert_equal(nil, client.proxy) ENV['CGI_HTTP_PROXY'] = "http://admin:admin@foo:1234" client = HTTPClient.new assert_equal(urify("http://admin:admin@foo:1234"), client.proxy) end end def test_empty_proxy_env setup_proxyserver escape_env do ENV['http_proxy'] = "" client = HTTPClient.new assert_equal(nil, client.proxy) end end def test_noproxy_for_localhost @proxyio.string = "" @client.proxy = proxyurl assert_equal(200, @client.head(serverurl).status) assert(/accept/ !~ @proxyio.string) end def test_no_proxy setup_proxyserver escape_noproxy do # proxy is not set. assert_equal(nil, @client.no_proxy) @client.no_proxy = 'localhost' assert_equal('localhost', @client.no_proxy) @proxyio.string = "" @client.proxy = nil assert_equal(200, @client.head(serverurl).status) assert(/accept/ !~ @proxyio.string) # @proxyio.string = "" @client.proxy = proxyurl assert_equal(200, @client.head(serverurl).status) assert(/accept/ !~ @proxyio.string) # @client.no_proxy = 'foobar' @proxyio.string = "" @client.proxy = proxyurl assert_equal(200, @client.head(serverurl).status) assert(/accept/ =~ @proxyio.string) # @client.no_proxy = 'foobar,localhost:baz' @proxyio.string = "" @client.proxy = proxyurl assert_equal(200, @client.head(serverurl).status) assert(/accept/ !~ @proxyio.string) # @client.no_proxy = 'foobar,localhost:443' @proxyio.string = "" @client.proxy = proxyurl assert_equal(200, @client.head(serverurl).status) assert(/accept/ =~ @proxyio.string) # @client.no_proxy = "foobar,localhost:443:localhost:#{serverport},baz" @proxyio.string = "" @client.proxy = proxyurl assert_equal(200, @client.head(serverurl).status) assert(/accept/ !~ @proxyio.string) end end def test_no_proxy_with_initial_dot @client.debug_dev = str = "" @client.test_loopback_http_response << "HTTP/1.0 200 OK\r\n\r\n" @client.no_proxy = '' @client.proxy = proxyurl @client.head('http://www.foo.com') assert(/CONNECT TO localhost/ =~ str, 'via proxy') # @client.debug_dev = str = "" @client.test_loopback_http_response << "HTTP/1.0 200 OK\r\n\r\n" @client.no_proxy = '.foo.com' @client.proxy = proxyurl @client.head('http://www.foo.com') assert(/CONNECT TO www.foo.com/ =~ str, 'no proxy because .foo.com matches with www.foo.com') # @client.debug_dev = str = "" @client.test_loopback_http_response << "HTTP/1.0 200 OK\r\n\r\n" @client.no_proxy = '.foo.com' @client.proxy = proxyurl @client.head('http://foo.com') assert(/CONNECT TO localhost/ =~ str, 'via proxy because .foo.com does not matche with foo.com') # @client.debug_dev = str = "" @client.test_loopback_http_response << "HTTP/1.0 200 OK\r\n\r\n" @client.no_proxy = 'foo.com' @client.proxy = proxyurl @client.head('http://foo.com') assert(/CONNECT TO foo.com/ =~ str, 'no proxy because foo.com matches with foo.com') end def test_cookie_update_while_authentication escape_noproxy do @client.test_loopback_http_response << < true).header.request_uri) assert_equal(expected, @client.get(serverurl + 'redirect2', :follow_redirect => true).header.request_uri) end def test_redirect_non_https url = serverurl + 'redirect1' https_url = urify(url) https_url.scheme = 'https' # redirect_to_http = "HTTP/1.0 302 OK\nLocation: #{url}\n\n" redirect_to_https = "HTTP/1.0 302 OK\nLocation: #{https_url}\n\n" # # https -> http is denied @client.test_loopback_http_response << redirect_to_http assert_raises(HTTPClient::BadResponseError) do @client.get_content(https_url) end # # http -> http is OK @client.reset_all @client.test_loopback_http_response << redirect_to_http assert_equal('hello', @client.get_content(url)) # # http -> https is OK @client.reset_all @client.test_loopback_http_response << redirect_to_https assert_raises(OpenSSL::SSL::SSLError) do # trying to normal endpoint with SSL -> SSL negotiation failure @client.get_content(url) end # # https -> https is OK @client.reset_all @client.test_loopback_http_response << redirect_to_https assert_raises(OpenSSL::SSL::SSLError) do # trying to normal endpoint with SSL -> SSL negotiation failure @client.get_content(https_url) end # # https -> http with strict_redirect_uri_callback @client.redirect_uri_callback = @client.method(:strict_redirect_uri_callback) @client.test_loopback_http_response << redirect_to_http assert_raises(HTTPClient::BadResponseError) do @client.get_content(https_url) end end def test_redirect_see_other assert_equal('hello', @client.post_content(serverurl + 'redirect_see_other')) end def test_redirect_relative @client.test_loopback_http_response << "HTTP/1.0 302 OK\nLocation: hello\n\n" silent do assert_equal('hello', @client.get_content(serverurl + 'redirect1')) end # @client.reset_all @client.redirect_uri_callback = @client.method(:strict_redirect_uri_callback) assert_equal('hello', @client.get_content(serverurl + 'redirect1')) @client.reset_all @client.test_loopback_http_response << "HTTP/1.0 302 OK\nLocation: hello\n\n" begin @client.get_content(serverurl + 'redirect1') assert(false) rescue HTTPClient::BadResponseError => e assert_equal(302, e.res.status) end end def test_redirect_https_relative url = serverurl + 'redirect1' https_url = urify(url) https_url.scheme = 'https' @client.test_loopback_http_response << "HTTP/1.0 302 OK\nLocation: /foo\n\n" @client.test_loopback_http_response << "HTTP/1.0 200 OK\n\nhello" silent do assert_equal('hello', @client.get_content(https_url)) end end def test_no_content assert_nothing_raised do timeout(2) do @client.get(serverurl + 'status', :status => 101) @client.get(serverurl + 'status', :status => 204) @client.get(serverurl + 'status', :status => 304) end end end def test_get_content assert_equal('hello', @client.get_content(serverurl + 'hello')) assert_equal('hello', @client.get_content(serverurl + 'redirect1')) assert_equal('hello', @client.get_content(serverurl + 'redirect2')) url = serverurl.sub(/localhost/, '127.0.0.1') assert_equal('hello', @client.get_content(url + 'hello')) assert_equal('hello', @client.get_content(url + 'redirect1')) assert_equal('hello', @client.get_content(url + 'redirect2')) @client.reset(serverurl) @client.reset(url) @client.reset(serverurl) @client.reset(url) assert_raises(HTTPClient::BadResponseError) do @client.get_content(serverurl + 'notfound') end assert_raises(HTTPClient::BadResponseError) do @client.get_content(serverurl + 'redirect_self') end called = false @client.redirect_uri_callback = lambda { |uri, res| newuri = res.header['location'][0] called = true newuri } assert_equal('hello', @client.get_content(serverurl + 'relative_redirect')) assert(called) end GZIP_CONTENT = "\x1f\x8b\x08\x00\x1a\x96\xe0\x4c\x00\x03\xcb\x48\xcd\xc9\xc9\x07\x00\x86\xa6\x10\x36\x05\x00\x00\x00" DEFLATE_CONTENT = "\x78\x9c\xcb\x48\xcd\xc9\xc9\x07\x00\x06\x2c\x02\x15" GZIP_CONTENT.force_encoding('BINARY') if GZIP_CONTENT.respond_to?(:force_encoding) DEFLATE_CONTENT.force_encoding('BINARY') if DEFLATE_CONTENT.respond_to?(:force_encoding) def test_get_gzipped_content @client.transparent_gzip_decompression = false content = @client.get_content(serverurl + 'compressed?enc=gzip') assert_not_equal('hello', content) assert_equal(GZIP_CONTENT, content) @client.transparent_gzip_decompression = true assert_equal('hello', @client.get_content(serverurl + 'compressed?enc=gzip')) assert_equal('hello', @client.get_content(serverurl + 'compressed?enc=deflate')) @client.transparent_gzip_decompression = false end def test_get_content_with_block @client.get_content(serverurl + 'hello') do |str| assert_equal('hello', str) end @client.get_content(serverurl + 'redirect1') do |str| assert_equal('hello', str) end @client.get_content(serverurl + 'redirect2') do |str| assert_equal('hello', str) end end def test_post_content assert_equal('hello', @client.post_content(serverurl + 'hello')) assert_equal('hello', @client.post_content(serverurl + 'redirect1')) assert_equal('hello', @client.post_content(serverurl + 'redirect2')) assert_raises(HTTPClient::BadResponseError) do @client.post_content(serverurl + 'notfound') end assert_raises(HTTPClient::BadResponseError) do @client.post_content(serverurl + 'redirect_self') end called = false @client.redirect_uri_callback = lambda { |uri, res| newuri = res.header['location'][0] called = true newuri } assert_equal('hello', @client.post_content(serverurl + 'relative_redirect')) assert(called) end def test_post_content_io post_body = StringIO.new("1234567890") assert_equal('post,1234567890', @client.post_content(serverurl + 'servlet', post_body)) post_body = StringIO.new("1234567890") assert_equal('post,1234567890', @client.post_content(serverurl + 'servlet_redirect', post_body)) # post_body = StringIO.new("1234567890") post_body.read(5) assert_equal('post,67890', @client.post_content(serverurl + 'servlet_redirect', post_body)) end def test_head assert_equal("head", @client.head(serverurl + 'servlet').header["x-head"][0]) param = {'1'=>'2', '3'=>'4'} res = @client.head(serverurl + 'servlet', param) assert_equal(param, params(res.header["x-query"][0])) end def test_head_async param = {'1'=>'2', '3'=>'4'} conn = @client.head_async(serverurl + 'servlet', param) Thread.pass while !conn.finished? res = conn.pop assert_equal(param, params(res.header["x-query"][0])) end def test_get assert_equal("get", @client.get(serverurl + 'servlet').content) param = {'1'=>'2', '3'=>'4'} res = @client.get(serverurl + 'servlet', param) assert_equal(param, params(res.header["x-query"][0])) assert_nil(res.contenttype) # url = serverurl.to_s + 'servlet?5=6&7=8' res = @client.get(url, param) assert_equal(param.merge("5"=>"6", "7"=>"8"), params(res.header["x-query"][0])) assert_nil(res.contenttype) end def test_head_follow_redirect expected = urify(serverurl + 'hello') assert_equal(expected, @client.head(serverurl + 'hello', :follow_redirect => true).header.request_uri) assert_equal(expected, @client.head(serverurl + 'redirect1', :follow_redirect => true).header.request_uri) assert_equal(expected, @client.head(serverurl + 'redirect2', :follow_redirect => true).header.request_uri) end def test_get_follow_redirect assert_equal('hello', @client.get(serverurl + 'hello', :follow_redirect => true).body) assert_equal('hello', @client.get(serverurl + 'redirect1', :follow_redirect => true).body) assert_equal('hello', @client.get(serverurl + 'redirect2', :follow_redirect => true).body) end def test_get_async param = {'1'=>'2', '3'=>'4'} conn = @client.get_async(serverurl + 'servlet', param) Thread.pass while !conn.finished? res = conn.pop assert_equal(param, params(res.header["x-query"][0])) end def test_get_async_for_largebody conn = @client.get_async(serverurl + 'largebody') res = conn.pop assert_equal(1000*1000, res.content.read.length) end def test_get_with_block called = false res = @client.get(serverurl + 'servlet') { |str| assert_equal('get', str) called = true } assert(called) # res does not have a content assert_nil(res.content) end def test_get_with_block_chunk_string_recycle @client.read_block_size = 2 body = [] res = @client.get(serverurl + 'servlet') { |str| body << str } assert_equal(2, body.size) assert_equal("get", body.join) # Was "tt" by String object recycle... end def test_post assert_equal("post", @client.post(serverurl + 'servlet').content[0, 4]) param = {'1'=>'2', '3'=>'4'} res = @client.post(serverurl + 'servlet', param) assert_equal(param, params(res.header["x-query"][0])) end def test_post_follow_redirect assert_equal('hello', @client.post(serverurl + 'hello', :follow_redirect => true).body) assert_equal('hello', @client.post(serverurl + 'redirect1', :follow_redirect => true).body) assert_equal('hello', @client.post(serverurl + 'redirect2', :follow_redirect => true).body) end def test_post_with_content_type param = [['1', '2'], ['3', '4']] ext = {'content-type' => 'application/x-www-form-urlencoded', 'hello' => 'world'} assert_equal("post", @client.post(serverurl + 'servlet').content[0, 4], ext) res = @client.post(serverurl + 'servlet', param, ext) assert_equal(Hash[param], params(res.header["x-query"][0])) # ext = [['content-type', 'multipart/form-data'], ['hello', 'world']] assert_equal("post", @client.post(serverurl + 'servlet').content[0, 4], ext) res = @client.post(serverurl + 'servlet', param, ext) assert_match(/Content-Disposition: form-data; name="1"/, res.content) assert_match(/Content-Disposition: form-data; name="3"/, res.content) # ext = {'content-type' => 'multipart/form-data; boundary=hello'} assert_equal("post", @client.post(serverurl + 'servlet').content[0, 4], ext) res = @client.post(serverurl + 'servlet', param, ext) assert_match(/Content-Disposition: form-data; name="1"/, res.content) assert_match(/Content-Disposition: form-data; name="3"/, res.content) assert_equal("post,--hello\r\nContent-Disposition: form-data; name=\"1\"\r\n\r\n2\r\n--hello\r\nContent-Disposition: form-data; name=\"3\"\r\n\r\n4\r\n--hello--\r\n\r\n", res.content) end def test_post_with_custom_multipart_and_boolean_params param = [['boolean_true', true]] ext = { 'content-type' => 'multipart/form-data' } assert_equal("post", @client.post(serverurl + 'servlet').content[0, 4], ext) res = @client.post(serverurl + 'servlet', param, ext) assert_match(/Content-Disposition: form-data; name="boolean_true"\r\n\r\ntrue\r\n/, res.content) # param = [['boolean_false', false]] res = @client.post(serverurl + 'servlet', param, ext) assert_match(/Content-Disposition: form-data; name="boolean_false"\r\n\r\nfalse\r\n/, res.content) # param = [['nil', nil]] res = @client.post(serverurl + 'servlet', param, ext) assert_match(/Content-Disposition: form-data; name="nil"\r\n\r\n\r\n/, res.content) end def test_post_with_file STDOUT.sync = true File.open(__FILE__) do |file| res = @client.post(serverurl + 'servlet', {1=>2, 3=>file}) assert_match(/^Content-Disposition: form-data; name="1"\r\n/nm, res.content) assert_match(/^Content-Disposition: form-data; name="3";/, res.content) assert_match(/FIND_TAG_IN_THIS_FILE/, res.content) end end def test_post_with_file_without_size STDOUT.sync = true File.open(__FILE__) do |file| def file.size # Simulates some strange Windows behaviour raise SystemCallError.new "Unknown Error (20047)" end assert_nothing_raised do @client.post(serverurl + 'servlet', {1=>2, 3=>file}) end end end def test_post_with_io # streaming, but not chunked myio = StringIO.new("X" * (HTTP::Message::Body::DEFAULT_CHUNK_SIZE + 1)) def myio.read(*args) @called ||= 0 @called += 1 super end def myio.called @called end @client.debug_dev = str = StringIO.new res = @client.post(serverurl + 'servlet', {1=>2, 3=>myio}) assert_match(/\r\nContent-Disposition: form-data; name="1"\r\n/m, res.content) assert_match(/\r\n2\r\n/m, res.content) assert_match(/\r\nContent-Disposition: form-data; name="3"; filename=""\r\n/m, res.content) assert_match(/\r\nContent-Length:/m, str.string) assert_equal(3, myio.called) end def test_post_with_io_nosize # streaming + chunked post myio = StringIO.new("4") def myio.size nil end @client.debug_dev = str = StringIO.new res = @client.post(serverurl + 'servlet', {1=>2, 3=>myio}) assert_match(/\r\nContent-Disposition: form-data; name="1"\r\n/m, res.content) assert_match(/\r\n2\r\n/m, res.content) assert_match(/\r\nContent-Disposition: form-data; name="3"; filename=""\r\n/m, res.content) assert_match(/\r\n4\r\n/m, res.content) assert_match(/\r\nTransfer-Encoding: chunked\r\n/m, str.string) end def test_post_async param = {'1'=>'2', '3'=>'4'} conn = @client.post_async(serverurl + 'servlet', param) Thread.pass while !conn.finished? res = conn.pop assert_equal(param, params(res.header["x-query"][0])) end def test_post_with_block called = false res = @client.post(serverurl + 'servlet') { |str| assert_equal('post,', str) called = true } assert(called) assert_nil(res.content) # called = false param = [['1', '2'], ['3', '4']] res = @client.post(serverurl + 'servlet', param) { |str| assert_equal('post,1=2&3=4', str) called = true } assert(called) assert_equal('1=2&3=4', res.header["x-query"][0]) assert_nil(res.content) end def test_post_with_custom_multipart ext = {'content-type' => 'multipart/form-data'} assert_equal("post", @client.post(serverurl + 'servlet').content[0, 4], ext) body = [{ 'Content-Disposition' => 'form-data; name="1"', :content => "2"}, { 'Content-Disposition' => 'form-data; name="3"', :content => "4"}] res = @client.post(serverurl + 'servlet', body, ext) assert_match(/Content-Disposition: form-data; name="1"/, res.content) assert_match(/Content-Disposition: form-data; name="3"/, res.content) # ext = {'content-type' => 'multipart/form-data; boundary=hello'} assert_equal("post", @client.post(serverurl + 'servlet').content[0, 4], ext) res = @client.post(serverurl + 'servlet', body, ext) assert_match(/Content-Disposition: form-data; name="1"/, res.content) assert_match(/Content-Disposition: form-data; name="3"/, res.content) assert_equal("post,--hello\r\nContent-Disposition: form-data; name=\"1\"\r\n\r\n2\r\n--hello\r\nContent-Disposition: form-data; name=\"3\"\r\n\r\n4\r\n--hello--\r\n\r\n", res.content) end def test_post_with_custom_multipart_and_file STDOUT.sync = true File.open(__FILE__) do |file| ext = { 'Content-Type' => 'multipart/alternative' } body = [{ 'Content-Type' => 'text/plain', :content => "this is only a test" }, { 'Content-Type' => 'application/x-ruby', :content => file }] res = @client.post(serverurl + 'servlet', body, ext) assert_match(/^Content-Type: text\/plain\r\n/m, res.content) assert_match(/^this is only a test\r\n/m, res.content) assert_match(/^Content-Type: application\/x-ruby\r\n/m, res.content) assert_match(/FIND_TAG_IN_THIS_FILE/, res.content) end end def test_put assert_equal("put", @client.put(serverurl + 'servlet').content) param = {'1'=>'2', '3'=>'4'} @client.debug_dev = str = '' res = @client.put(serverurl + 'servlet', param) assert_equal(param, params(res.header["x-query"][0])) assert_equal('Content-Type: application/x-www-form-urlencoded', str.split(/\r?\n/)[5]) end def test_put_bytesize res = @client.put(serverurl + 'servlet', 'txt' => 'あいうえお') assert_equal('txt=%E3%81%82%E3%81%84%E3%81%86%E3%81%88%E3%81%8A', res.header["x-query"][0]) assert_equal('15', res.header["x-size"][0]) end def test_put_async param = {'1'=>'2', '3'=>'4'} conn = @client.put_async(serverurl + 'servlet', param) Thread.pass while !conn.finished? res = conn.pop assert_equal(param, params(res.header["x-query"][0])) end def test_delete assert_equal("delete", @client.delete(serverurl + 'servlet').content) end # Not prohibited by spec, but normally it's ignored def test_delete_with_body param = {'1'=>'2', '3'=>'4'} @client.debug_dev = str = '' assert_equal("delete", @client.delete(serverurl + 'servlet', param).content) assert_equal({'1' => ['2'], '3' => ['4']}, HTTP::Message.parse(str.split(/\r?\n\r?\n/)[2])) end def test_delete_async conn = @client.delete_async(serverurl + 'servlet') Thread.pass while !conn.finished? res = conn.pop assert_equal('delete', res.content.read) end def test_options assert_equal("options", @client.options(serverurl + 'servlet').content) end def test_options_async conn = @client.options_async(serverurl + 'servlet') Thread.pass while !conn.finished? res = conn.pop assert_equal('options', res.content.read) end def test_propfind assert_equal("propfind", @client.propfind(serverurl + 'servlet').content) end def test_propfind_async conn = @client.propfind_async(serverurl + 'servlet') Thread.pass while !conn.finished? res = conn.pop assert_equal('propfind', res.content.read) end def test_proppatch assert_equal("proppatch", @client.proppatch(serverurl + 'servlet').content) param = {'1'=>'2', '3'=>'4'} res = @client.proppatch(serverurl + 'servlet', param) assert_equal('proppatch', res.content) assert_equal(param, params(res.header["x-query"][0])) end def test_proppatch_async param = {'1'=>'2', '3'=>'4'} conn = @client.proppatch_async(serverurl + 'servlet', param) Thread.pass while !conn.finished? res = conn.pop assert_equal('proppatch', res.content.read) assert_equal(param, params(res.header["x-query"][0])) end def test_trace assert_equal("trace", @client.trace(serverurl + 'servlet').content) param = {'1'=>'2', '3'=>'4'} res = @client.trace(serverurl + 'servlet', param) assert_equal(param, params(res.header["x-query"][0])) end def test_trace_async param = {'1'=>'2', '3'=>'4'} conn = @client.trace_async(serverurl + 'servlet', param) Thread.pass while !conn.finished? res = conn.pop assert_equal(param, params(res.header["x-query"][0])) end def test_chunked assert_equal('chunked', @client.get_content(serverurl + 'chunked', { 'msg' => 'chunked' })) end def test_chunked_empty assert_equal('', @client.get_content(serverurl + 'chunked', { 'msg' => '' })) end def test_get_query assert_equal({'1'=>'2'}, check_query_get({1=>2})) assert_equal({'a'=>'A', 'B'=>'b'}, check_query_get({"a"=>"A", "B"=>"b"})) assert_equal({'&'=>'&'}, check_query_get({"&"=>"&"})) assert_equal({'= '=>' =+'}, check_query_get({"= "=>" =+"})) assert_equal( ['=', '&'].sort, check_query_get([["=", "="], ["=", "&"]])['='].to_ary.sort ) assert_equal({'123'=>'45'}, check_query_get('123=45')) assert_equal({'12 3'=>'45', ' '=>' '}, check_query_get('12+3=45&+=+')) assert_equal({}, check_query_get('')) assert_equal({'1'=>'2'}, check_query_get({1=>StringIO.new('2')})) assert_equal({'1'=>'2', '3'=>'4'}, check_query_get(StringIO.new('3=4&1=2'))) hash = check_query_get({"a"=>["A","a"], "B"=>"b"}) assert_equal({'a'=>'A', 'B'=>'b'}, hash) assert_equal(['A','a'], hash['a'].to_ary) hash = check_query_get({"a"=>WEBrick::HTTPUtils::FormData.new("A","a"), "B"=>"b"}) assert_equal({'a'=>'A', 'B'=>'b'}, hash) assert_equal(['A','a'], hash['a'].to_ary) hash = check_query_get({"a"=>[StringIO.new("A"),StringIO.new("a")], "B"=>StringIO.new("b")}) assert_equal({'a'=>'A', 'B'=>'b'}, hash) assert_equal(['A','a'], hash['a'].to_ary) end def test_post_body assert_equal({'1'=>'2'}, check_query_post({1=>2})) assert_equal({'a'=>'A', 'B'=>'b'}, check_query_post({"a"=>"A", "B"=>"b"})) assert_equal({'&'=>'&'}, check_query_post({"&"=>"&"})) assert_equal({'= '=>' =+'}, check_query_post({"= "=>" =+"})) assert_equal( ['=', '&'].sort, check_query_post([["=", "="], ["=", "&"]])['='].to_ary.sort ) assert_equal({'123'=>'45'}, check_query_post('123=45')) assert_equal({'12 3'=>'45', ' '=>' '}, check_query_post('12+3=45&+=+')) assert_equal({}, check_query_post('')) # post_body = StringIO.new("foo=bar&foo=baz") assert_equal( ["bar", "baz"], check_query_post(post_body)["foo"].to_ary.sort ) end def test_extra_headers str = "" @client.debug_dev = str @client.head(serverurl, nil, {"ABC" => "DEF"}) lines = str.split(/(?:\r?\n)+/) assert_equal("= Request", lines[0]) assert_match("ABC: DEF", lines[4]) # str = "" @client.debug_dev = str @client.get(serverurl, nil, [["ABC", "DEF"], ["ABC", "DEF"]]) lines = str.split(/(?:\r?\n)+/) assert_equal("= Request", lines[0]) assert_match("ABC: DEF", lines[4]) assert_match("ABC: DEF", lines[5]) end def test_http_custom_date_header @client.debug_dev = (str = "") res = @client.get(serverurl + 'hello', :header => {'Date' => 'foo'}) lines = str.split(/(?:\r?\n)+/) assert_equal('Date: foo', lines[4]) end def test_timeout assert_equal(60, @client.connect_timeout) assert_equal(120, @client.send_timeout) assert_equal(60, @client.receive_timeout) # @client.connect_timeout = 1 @client.send_timeout = 2 @client.receive_timeout = 3 assert_equal(1, @client.connect_timeout) assert_equal(2, @client.send_timeout) assert_equal(3, @client.receive_timeout) end def test_connect_timeout # ToDo end def test_send_timeout # ToDo end def test_receive_timeout # this test takes 2 sec assert_equal('hello', @client.get_content(serverurl + 'sleep?sec=2')) @client.receive_timeout = 1 assert_equal('hello', @client.get_content(serverurl + 'sleep?sec=0')) assert_raise(HTTPClient::ReceiveTimeoutError) do @client.get_content(serverurl + 'sleep?sec=2') end @client.receive_timeout = 3 assert_equal('hello', @client.get_content(serverurl + 'sleep?sec=2')) end def test_receive_timeout_post # this test takes 2 sec assert_equal('hello', @client.post(serverurl + 'sleep', :sec => 2).content) @client.receive_timeout = 1 assert_equal('hello', @client.post(serverurl + 'sleep', :sec => 0).content) assert_raise(HTTPClient::ReceiveTimeoutError) do @client.post(serverurl + 'sleep', :sec => 2) end @client.receive_timeout = 3 assert_equal('hello', @client.post(serverurl + 'sleep', :sec => 2).content) end def test_async_error assert_raise( SocketError ) do conn = @client.get_async("http://non-existing-host/") conn.pop end end def test_reset url = serverurl + 'servlet' assert_nothing_raised do 5.times do @client.get(url) @client.reset(url) end end end def test_reset_all assert_nothing_raised do 5.times do @client.get(serverurl + 'servlet') @client.reset_all end end end def test_cookies cookiefile = File.join(File.dirname(File.expand_path(__FILE__)), 'test_cookies_file') File.open(cookiefile, "wb") do |f| f << "http://rubyforge.org/account/login.php\tsession_ser\tLjEwMy45Ni40Ni0q%2A-fa0537de8cc31\t2000000000\t.rubyforge.org\t/\t13\n" end @client.set_cookie_store(cookiefile) cookie = @client.cookie_manager.cookies.first url = cookie.url assert(cookie.domain_match(url.host, cookie.domain)) # @client.reset_all @client.test_loopback_http_response << "HTTP/1.0 200 OK\nSet-Cookie: foo=bar; expires=#{Time.at(1924873200).gmtime.httpdate}\n\nOK" @client.get_content('http://rubyforge.org/account/login.php') @client.save_cookie_store str = File.read(cookiefile) assert_match(%r(http://rubyforge.org/account/login.php\tfoo\tbar\t1924873200\trubyforge.org\t/account\t1), str) File.unlink(cookiefile) end def test_eof_error_length io = StringIO.new('') def io.gets(*arg) @buf ||= ["HTTP/1.0 200 OK\n", "content-length: 123\n", "\n"] @buf.shift end def io.readpartial(size, buf) @second ||= false if !@second @second = '1st' buf << "abc" buf elsif @second == '1st' @second = '2nd' raise EOFError.new else raise Exception.new end end def io.eof? true end @client.test_loopback_http_response << io assert_nothing_raised do @client.get('http://foo/bar') end end def test_eof_error_rest io = StringIO.new('') def io.gets(*arg) @buf ||= ["HTTP/1.0 200 OK\n", "\n"] @buf.shift end def io.readpartial(size, buf) @second ||= false if !@second @second = '1st' buf << "abc" buf elsif @second == '1st' @second = '2nd' raise EOFError.new else raise Exception.new end end def io.eof? true end @client.test_loopback_http_response << io assert_nothing_raised do @client.get('http://foo/bar') end end def test_urify extend HTTPClient::Util assert_nil(urify(nil)) uri = 'http://foo' assert_equal(urify(uri), urify(uri)) assert_equal(urify(uri), urify(urify(uri))) end def test_connection c = HTTPClient::Connection.new assert(c.finished?) assert_nil(c.join) end def test_site site = HTTPClient::Site.new assert_equal('tcp', site.scheme) assert_equal('0.0.0.0', site.host) assert_equal(0, site.port) assert_equal('tcp://0.0.0.0:0', site.addr) assert_equal('tcp://0.0.0.0:0', site.to_s) assert_nothing_raised do site.inspect end # site = HTTPClient::Site.new(urify('http://localhost:12345/foo')) assert_equal('http', site.scheme) assert_equal('localhost', site.host) assert_equal(12345, site.port) assert_equal('http://localhost:12345', site.addr) assert_equal('http://localhost:12345', site.to_s) assert_nothing_raised do site.inspect end # site1 = HTTPClient::Site.new(urify('http://localhost:12341/')) site2 = HTTPClient::Site.new(urify('http://localhost:12342/')) site3 = HTTPClient::Site.new(urify('http://localhost:12342/')) assert(!(site1 == site2)) h = { site1 => 'site1', site2 => 'site2' } h[site3] = 'site3' assert_equal('site1', h[site1]) assert_equal('site3', h[site2]) end def test_http_header res = @client.get(serverurl + 'hello') assert_equal('text/html', res.contenttype) assert_equal(5, res.header.get(nil).size) # res.header.delete('connection') assert_equal(4, res.header.get(nil).size) # res.header['foo'] = 'bar' assert_equal(['bar'], res.header['foo']) # assert_equal([['foo', 'bar']], res.header.get('foo')) res.header['foo'] = ['bar', 'bar2'] assert_equal([['foo', 'bar'], ['foo', 'bar2']], res.header.get('foo')) end def test_mime_type assert_equal('text/plain', HTTP::Message.mime_type('foo.txt')) assert_equal('text/html', HTTP::Message.mime_type('foo.html')) assert_equal('text/html', HTTP::Message.mime_type('foo.htm')) assert_equal('application/msword', HTTP::Message.mime_type('foo.doc')) assert_equal('image/png', HTTP::Message.mime_type('foo.png')) assert_equal('image/gif', HTTP::Message.mime_type('foo.gif')) assert_equal('image/jpeg', HTTP::Message.mime_type('foo.jpg')) assert_equal('image/jpeg', HTTP::Message.mime_type('foo.jpeg')) assert_equal('application/octet-stream', HTTP::Message.mime_type('foo.unknown')) # handler = lambda { |path| 'hello/world' } assert_nil(HTTP::Message.mime_type_handler) assert_nil(HTTP::Message.get_mime_type_func) HTTP::Message.mime_type_handler = handler assert_not_nil(HTTP::Message.mime_type_handler) assert_not_nil(HTTP::Message.get_mime_type_func) assert_equal('hello/world', HTTP::Message.mime_type('foo.txt')) HTTP::Message.mime_type_handler = nil assert_equal('text/plain', HTTP::Message.mime_type('foo.txt')) HTTP::Message.set_mime_type_func(nil) assert_equal('text/plain', HTTP::Message.mime_type('foo.txt')) # handler = lambda { |path| nil } HTTP::Message.mime_type_handler = handler assert_equal('application/octet-stream', HTTP::Message.mime_type('foo.txt')) end def test_connect_request req = HTTP::Message.new_connect_request(urify('https://foo/bar')) assert_equal("CONNECT foo:443 HTTP/1.0\r\n\r\n", req.dump) req = HTTP::Message.new_connect_request(urify('https://example.com/')) assert_equal("CONNECT example.com:443 HTTP/1.0\r\n\r\n", req.dump) end def test_response res = HTTP::Message.new_response('response') res.contenttype = 'text/plain' res.header.body_date = Time.at(946652400) assert_equal( [ "", "Content-Length: 8", "Content-Type: text/plain", "Last-Modified: Fri, 31 Dec 1999 15:00:00 GMT", "Status: 200 OK", "response" ], res.dump.split(/\r\n/).sort ) assert_equal(['8'], res.header['Content-Length']) assert_equal('8', res.headers['Content-Length']) res.header.set('foo', 'bar') assert_equal( [ "", "Content-Length: 8", "Content-Type: text/plain", "Last-Modified: Fri, 31 Dec 1999 15:00:00 GMT", "Status: 200 OK", "foo: bar", "response" ], res.dump.split(/\r\n/).sort ) # nil body res = HTTP::Message.new_response(nil) assert_equal( [ "Content-Length: 0", "Content-Type: text/html; charset=us-ascii", "Status: 200 OK" ], res.dump.split(/\r\n/).sort ) # for mod_ruby env Object.const_set('Apache', nil) begin res = HTTP::Message.new_response('response') assert(res.dump.split(/\r\n/).any? { |line| /^Date/ =~ line }) # res = HTTP::Message.new_response('response') res.contenttype = 'text/plain' res.header.body_date = Time.at(946652400) res.header['Date'] = Time.at(946652400).httpdate assert_equal( [ "", "Content-Length: 8", "Content-Type: text/plain", "Date: Fri, 31 Dec 1999 15:00:00 GMT", "HTTP/1.1 200 OK", "Last-Modified: Fri, 31 Dec 1999 15:00:00 GMT", "response" ], res.dump.split(/\r\n/).sort ) ensure Object.instance_eval { remove_const('Apache') } end end def test_response_cookies res = HTTP::Message.new_response('response') res.contenttype = 'text/plain' res.header.body_date = Time.at(946652400) assert_nil(res.cookies) # res.header['Set-Cookie'] = [ 'CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT', 'PART_NUMBER=ROCKET_LAUNCHER_0001; path=/' ] assert_equal( [ "", "Content-Length: 8", "Content-Type: text/plain", "Last-Modified: Fri, 31 Dec 1999 15:00:00 GMT", "Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT", "Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/", "Status: 200 OK", "response" ], res.dump.split(/\r\n/).sort ) assert_equal(2, res.cookies.size) assert_equal('CUSTOMER', res.cookies[0].name) assert_equal('PART_NUMBER', res.cookies[1].name) end def test_ok_response_success res = HTTP::Message.new_response('response') assert_equal(true, res.ok?) res.status = 404 assert_equal(false, res.ok?) res.status = 500 assert_equal(false, res.ok?) res.status = 302 assert_equal(false, res.ok?) end if !defined?(JRUBY_VERSION) and RUBY_VERSION < '1.9' def test_timeout_scheduler assert_equal('hello', @client.get_content(serverurl + 'hello')) status = HTTPClient.timeout_scheduler.instance_eval { @thread.kill; @thread.join; @thread.status } assert(!status) # dead assert_equal('hello', @client.get_content(serverurl + 'hello')) end end def test_session_manager mgr = HTTPClient::SessionManager.new(@client) assert_nil(mgr.instance_eval { @proxy }) assert_nil(mgr.debug_dev) @client.debug_dev = Object.new @client.proxy = 'http://myproxy:12345' mgr = HTTPClient::SessionManager.new(@client) assert_equal('http://myproxy:12345', mgr.instance_eval { @proxy }.to_s) assert_equal(@client.debug_dev, mgr.debug_dev) end def create_keepalive_disconnected_thread(idx, sock) Thread.new { # return "12345" for the first connection sock.gets sock.gets sock.write("HTTP/1.1 200 OK\r\n") sock.write("Content-Length: 5\r\n") sock.write("\r\n") sock.write("12345") # for the next connection, close while reading the request for emulating # KeepAliveDisconnected sock.gets sock.close } end def test_keepalive_disconnected client = HTTPClient.new server = TCPServer.open('127.0.0.1', 0) server.listen(30) # set enough backlogs endpoint = "http://127.0.0.1:#{server.addr[1]}/" Thread.new { Thread.abort_on_exception = true # emulate 10 keep-alive connections 10.times do |idx| sock = server.accept create_keepalive_disconnected_thread(idx, sock) end # return "23456" for the request which gets KeepAliveDisconnected 5.times do sock = server.accept sock.gets sock.gets sock.write("HTTP/1.1 200 OK\r\n") sock.write("\r\n") sock.write("23456") sock.close end # return "34567" for the rest requests while true sock = server.accept sock.gets sock.gets sock.write("HTTP/1.1 200 OK\r\n") sock.write("Connection: close\r\n") sock.write("Content-Length: 5\r\n") sock.write("\r\n") sock.write("34567") sock.close end } # allocate 10 keep-alive connections (0...10).to_a.map { Thread.new { assert_equal("12345", client.get(endpoint).content) } }.each { |th| th.join } # send 5 requests, which should get KeepAliveDesconnected. # doing these requests, rest keep-alive connections are invalidated. (0...5).to_a.map { Thread.new { assert_equal("23456", client.get(endpoint).content) } }.each { |th| th.join } # rest requests won't get KeepAliveDisconnected; how can I check this? (0...10).to_a.map { Thread.new { assert_equal("34567", client.get(endpoint).content) } }.each { |th| th.join } end def create_keepalive_thread(count, sock) Thread.new { Thread.abort_on_exception = true count.times do req = sock.gets while line = sock.gets break if line.chomp.empty? end case req when /chunked/ sock.write("HTTP/1.1 200 OK\r\n") sock.write("Transfer-Encoding: chunked\r\n") sock.write("\r\n") sock.write("1a\r\n") sock.write("abcdefghijklmnopqrstuvwxyz\r\n") sock.write("10\r\n") sock.write("1234567890abcdef\r\n") sock.write("0\r\n") sock.write("\r\n") else sock.write("HTTP/1.1 200 OK\r\n") sock.write("Content-Length: 5\r\n") sock.write("\r\n") sock.write("12345") end end sock.close } end def test_keepalive server = TCPServer.open('localhost', 0) server_thread = Thread.new { Thread.abort_on_exception = true sock = server.accept create_keepalive_thread(10, sock) } url = "http://localhost:#{server.addr[1]}/" begin # content-length 5.times do assert_equal('12345', @client.get(url).body) end # chunked 5.times do assert_equal('abcdefghijklmnopqrstuvwxyz1234567890abcdef', @client.get(url + 'chunked').body) end ensure server.close server_thread.join end end def test_socket_local @client.socket_local.host = '127.0.0.1' assert_equal('hello', @client.get_content(serverurl + 'hello')) @client.reset_all @client.socket_local.port = serverport begin @client.get_content(serverurl + 'hello') rescue Errno::EADDRINUSE, SocketError assert(true) end end def test_body_param_order ary = ('b'..'d').map { |k| ['key2', k] } << ['key1', 'a'] << ['key3', 'z'] assert_equal("key2=b&key2=c&key2=d&key1=a&key3=z", HTTP::Message.escape_query(ary)) end if RUBY_VERSION > "1.9" def test_charset body = @client.get(serverurl + 'charset').body assert_equal(Encoding::EUC_JP, body.encoding) assert_equal('あいうえお'.encode(Encoding::EUC_JP), body) end end if RUBY_VERSION >= "1.9.3" def test_continue @client.debug_dev = str = '' res = @client.get(serverurl + 'continue', :header => {:Expect => '100-continue'}) assert_equal(200, res.status) assert_equal('done!', res.body) assert_match(/Expect: 100-continue/, str) end end def test_ipv6literaladdress_in_uri server = TCPServer.open('::1', 0) rescue return # Skip if IPv6 is unavailable. server_thread = Thread.new { Thread.abort_on_exception = true sock = server.accept while line = sock.gets break if line.chomp.empty? end sock.write("HTTP/1.1 200 OK\r\n") sock.write("Content-Length: 5\r\n") sock.write("\r\n") sock.write("12345") sock.close } uri = "http://[::1]:#{server.addr[1]}/" begin assert_equal('12345', @client.get(uri).body) ensure server.close server_thread.kill server_thread.join end end private def check_query_get(query) WEBrick::HTTPUtils.parse_query( @client.get(serverurl + 'servlet', query).header["x-query"][0] ) end def check_query_post(query) WEBrick::HTTPUtils.parse_query( @client.post(serverurl + 'servlet', query).header["x-query"][0] ) end def setup_server @server = WEBrick::HTTPServer.new( :BindAddress => "localhost", :Logger => @logger, :Port => 0, :AccessLog => [], :DocumentRoot => File.dirname(File.expand_path(__FILE__)) ) @serverport = @server.config[:Port] [ :hello, :sleep, :servlet_redirect, :redirect1, :redirect2, :redirect3, :redirect_self, :relative_redirect, :redirect_see_other, :chunked, :largebody, :status, :compressed, :charset, :continue ].each do |sym| @server.mount( "/#{sym}", WEBrick::HTTPServlet::ProcHandler.new(method("do_#{sym}").to_proc) ) end @server.mount('/servlet', TestServlet.new(@server)) @server_thread = start_server_thread(@server) end def escape_noproxy backup = HTTPClient::NO_PROXY_HOSTS.dup HTTPClient::NO_PROXY_HOSTS.clear yield ensure HTTPClient::NO_PROXY_HOSTS.replace(backup) end def do_hello(req, res) res['content-type'] = 'text/html' res.body = "hello" end def do_sleep(req, res) sec = req.query['sec'].to_i sleep sec res['content-type'] = 'text/html' res.body = "hello" end def do_servlet_redirect(req, res) res.set_redirect(WEBrick::HTTPStatus::Found, serverurl + "servlet") end def do_redirect1(req, res) res.set_redirect(WEBrick::HTTPStatus::MovedPermanently, serverurl + "hello") end def do_redirect2(req, res) res.set_redirect(WEBrick::HTTPStatus::TemporaryRedirect, serverurl + "redirect3") end def do_redirect3(req, res) res.set_redirect(WEBrick::HTTPStatus::Found, serverurl + "hello") end def do_redirect_self(req, res) res.set_redirect(WEBrick::HTTPStatus::Found, serverurl + "redirect_self") end def do_relative_redirect(req, res) res.set_redirect(WEBrick::HTTPStatus::Found, "hello") end def do_redirect_see_other(req, res) if req.request_method == 'POST' res.set_redirect(WEBrick::HTTPStatus::SeeOther, serverurl + "redirect_see_other") # self else res.body = 'hello' end end def do_chunked(req, res) res.chunked = true piper, pipew = IO.pipe res.body = piper pipew << req.query['msg'] pipew.close end def do_largebody(req, res) res['content-type'] = 'text/html' res.body = "a" * 1000 * 1000 end def do_compressed(req, res) res['content-type'] = 'application/octet-stream' if req.query['enc'] == 'gzip' res['content-encoding'] = 'gzip' res.body = GZIP_CONTENT elsif req.query['enc'] == 'deflate' res['content-encoding'] = 'deflate' res.body = DEFLATE_CONTENT end end def do_charset(req, res) if RUBY_VERSION > "1.9" res.body = 'あいうえお'.encode("euc-jp") res['Content-Type'] = 'text/plain; charset=euc-jp' else res.body = 'this endpoint is for 1.9 or later' end end def do_status(req, res) res.status = req.query['status'].to_i end def do_continue(req, res) req.continue res.body = 'done!' end class TestServlet < WEBrick::HTTPServlet::AbstractServlet def get_instance(*arg) self end def do_HEAD(req, res) res["x-head"] = 'head' # use this for test purpose only. res["x-query"] = query_response(req) end def do_GET(req, res) res.body = 'get' res["x-query"] = query_response(req) end def do_POST(req, res) res["content-type"] = "text/plain" # iso-8859-1, not US-ASCII res.body = 'post,' + req.body.to_s res["x-query"] = body_response(req) end def do_PUT(req, res) res["x-query"] = body_response(req) param = WEBrick::HTTPUtils.parse_query(req.body) || {} res["x-size"] = (param['txt'] || '').size res.body = param['txt'] || 'put' end def do_DELETE(req, res) res.body = 'delete' end def do_OPTIONS(req, res) # check RFC for legal response. res.body = 'options' end def do_PROPFIND(req, res) res.body = 'propfind' end def do_PROPPATCH(req, res) res.body = 'proppatch' res["x-query"] = body_response(req) end def do_TRACE(req, res) # client SHOULD reflect the message received back to the client as the # entity-body of a 200 (OK) response. [RFC2616] res.body = 'trace' res["x-query"] = query_response(req) end private def query_response(req) query_escape(WEBrick::HTTPUtils.parse_query(req.query_string)) end def body_response(req) query_escape(WEBrick::HTTPUtils.parse_query(req.body)) end def query_escape(query) escaped = [] query.sort_by { |k, v| k }.collect do |k, v| v.to_ary.each do |ve| escaped << CGI.escape(k) + '=' + CGI.escape(ve) end end escaped.join('&') end end end