You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

133 lines
5.4 KiB

  1. # frozen_string_literal: true
  2. require 'rails_helper'
  3. require 'securerandom'
  4. describe Request do
  5. subject { Request.new(:get, 'http://example.com') }
  6. describe '#headers' do
  7. it 'returns user agent' do
  8. expect(subject.headers['User-Agent']).to be_present
  9. end
  10. it 'returns the date header' do
  11. expect(subject.headers['Date']).to be_present
  12. end
  13. it 'returns the host header' do
  14. expect(subject.headers['Host']).to be_present
  15. end
  16. it 'does not return virtual request-target header' do
  17. expect(subject.headers['(request-target)']).to be_nil
  18. end
  19. end
  20. describe '#on_behalf_of' do
  21. it 'when used, adds signature header' do
  22. subject.on_behalf_of(Fabricate(:account))
  23. expect(subject.headers['Signature']).to be_present
  24. end
  25. end
  26. describe '#add_headers' do
  27. it 'adds headers to the request' do
  28. subject.add_headers('Test' => 'Foo')
  29. expect(subject.headers['Test']).to eq 'Foo'
  30. end
  31. end
  32. describe '#perform' do
  33. context 'with valid host' do
  34. before { stub_request(:get, 'http://example.com') }
  35. it 'executes a HTTP request' do
  36. expect { |block| subject.perform &block }.to yield_control
  37. expect(a_request(:get, 'http://example.com')).to have_been_made.once
  38. end
  39. it 'executes a HTTP request when the first address is private' do
  40. allow(Addrinfo).to receive(:foreach).with('example.com', nil, nil, :SOCK_STREAM)
  41. .and_yield(Addrinfo.new(["AF_INET", 0, "example.com", "0.0.0.0"], :PF_INET, :SOCK_STREAM))
  42. .and_yield(Addrinfo.new(["AF_INET6", 0, "example.com", "2001:4860:4860::8844"], :PF_INET6, :SOCK_STREAM))
  43. expect { |block| subject.perform &block }.to yield_control
  44. expect(a_request(:get, 'http://example.com')).to have_been_made.once
  45. end
  46. it 'sets headers' do
  47. expect { |block| subject.perform &block }.to yield_control
  48. expect(a_request(:get, 'http://example.com').with(headers: subject.headers)).to have_been_made
  49. end
  50. it 'closes underlaying connection' do
  51. expect_any_instance_of(HTTP::Client).to receive(:close)
  52. expect { |block| subject.perform &block }.to yield_control
  53. end
  54. it 'returns response which implements body_with_limit' do
  55. subject.perform do |response|
  56. expect(response).to respond_to :body_with_limit
  57. end
  58. end
  59. end
  60. context 'with private host' do
  61. around do |example|
  62. WebMock.disable!
  63. example.run
  64. WebMock.enable!
  65. end
  66. it 'raises Mastodon::ValidationError' do
  67. allow(Addrinfo).to receive(:foreach).with('example.com', nil, nil, :SOCK_STREAM)
  68. .and_yield(Addrinfo.new(["AF_INET", 0, "example.com", "0.0.0.0"], :PF_INET, :SOCK_STREAM))
  69. .and_yield(Addrinfo.new(["AF_INET6", 0, "example.com", "2001:db8::face"], :PF_INET6, :SOCK_STREAM))
  70. expect{ subject.perform }.to raise_error Mastodon::ValidationError
  71. end
  72. end
  73. end
  74. describe "response's body_with_limit method" do
  75. it 'rejects body more than 1 megabyte by default' do
  76. stub_request(:any, 'http://example.com').to_return(body: SecureRandom.random_bytes(2.megabytes))
  77. expect { subject.perform { |response| response.body_with_limit } }.to raise_error Mastodon::LengthValidationError
  78. end
  79. it 'accepts body less than 1 megabyte by default' do
  80. stub_request(:any, 'http://example.com').to_return(body: SecureRandom.random_bytes(2.kilobytes))
  81. expect { subject.perform { |response| response.body_with_limit } }.not_to raise_error
  82. end
  83. it 'rejects body by given size' do
  84. stub_request(:any, 'http://example.com').to_return(body: SecureRandom.random_bytes(2.kilobytes))
  85. expect { subject.perform { |response| response.body_with_limit(1.kilobyte) } }.to raise_error Mastodon::LengthValidationError
  86. end
  87. it 'rejects too large chunked body' do
  88. stub_request(:any, 'http://example.com').to_return(body: SecureRandom.random_bytes(2.megabytes), headers: { 'Transfer-Encoding' => 'chunked' })
  89. expect { subject.perform { |response| response.body_with_limit } }.to raise_error Mastodon::LengthValidationError
  90. end
  91. it 'rejects too large monolithic body' do
  92. stub_request(:any, 'http://example.com').to_return(body: SecureRandom.random_bytes(2.megabytes), headers: { 'Content-Length' => 2.megabytes })
  93. expect { subject.perform { |response| response.body_with_limit } }.to raise_error Mastodon::LengthValidationError
  94. end
  95. it 'uses binary encoding if Content-Type does not tell encoding' do
  96. stub_request(:any, 'http://example.com').to_return(body: '', headers: { 'Content-Type' => 'text/html' })
  97. expect(subject.perform { |response| response.body_with_limit.encoding }).to eq Encoding::BINARY
  98. end
  99. it 'uses binary encoding if Content-Type tells unknown encoding' do
  100. stub_request(:any, 'http://example.com').to_return(body: '', headers: { 'Content-Type' => 'text/html; charset=unknown' })
  101. expect(subject.perform { |response| response.body_with_limit.encoding }).to eq Encoding::BINARY
  102. end
  103. it 'uses encoding specified by Content-Type' do
  104. stub_request(:any, 'http://example.com').to_return(body: '', headers: { 'Content-Type' => 'text/html; charset=UTF-8' })
  105. expect(subject.perform { |response| response.body_with_limit.encoding }).to eq Encoding::UTF_8
  106. end
  107. end
  108. end