Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 54 additions & 1 deletion lib/net/http.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ class HTTPHeaderSyntaxError < StandardError; end
# body = 'Some text'
# http.post(path, body) # Can also have a block.
# http.put(path, body)
# http.query(path, body) # Can also have a block.
# http.delete(path)
# http.options(path)
# http.trace(path)
Expand Down Expand Up @@ -207,6 +208,7 @@ class HTTPHeaderSyntaxError < StandardError; end
# - #options: OPTIONS.
# - #trace: TRACE.
# - #patch: PATCH.
# - #query, #request_query: QUERY.
#
# - {WebDAV methods}[https://en.wikipedia.org/wiki/WebDAV#Implementation]:
#
Expand Down Expand Up @@ -553,6 +555,8 @@ class HTTPHeaderSyntaxError < StandardError; end
# Sends a PROPPATCH request and returns a response object.
# - {#put}[rdoc-ref:Net::HTTP#put]:
# Sends a PUT request and returns a response object.
# - {#query}[rdoc-ref:Net::HTTP#query]:
# Sends a QUERY request and returns a response object.
# - {#request}[rdoc-ref:Net::HTTP#request]:
# Sends a request and returns a response object.
# - {#request_get}[rdoc-ref:Net::HTTP#request_get]:
Expand Down Expand Up @@ -2101,6 +2105,25 @@ def patch(path, data, initheader = nil, dest = nil, &block) # :yield: +body_segm
send_entity(path, data, initheader, dest, Patch, &block)
end

# Sends a QUERY request to the server;
# returns an instance of a subclass of Net::HTTPResponse.
#
# The request is based on the Net::HTTP::Query object
# created from string +path+, string +data+, and initial headers hash +initheader+.
#
# data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
# http = Net::HTTP.new(hostname)
# http.query('/todos/1', data) # => #<Net::HTTPOK 200 OK readbody=true>
#
# Related:
#
# - Net::HTTP::Query: request class for \HTTP method QUERY.
# - Net::HTTP.query: sends QUERY request, returns response body.
#
def query(path, data, initheader = nil, dest = nil, &block) # :yield: +body_segment+
send_entity(path, data, initheader, dest, Query, &block)
end

# Sends a PUT request to the server;
# returns an instance of a subclass of Net::HTTPResponse.
#
Expand Down Expand Up @@ -2335,6 +2358,36 @@ def request_put(path, data, initheader = nil, &block) #:nodoc:
request Put.new(path, initheader), data, &block
end

# Sends a QUERY request to the server;
# returns an instance of a subclass of Net::HTTPResponse.
#
# The request is based on the Net::HTTP::Query object
# created from string +path+, string +body+, and initial headers hash +initheader+.
#
# http = Net::HTTP.new(hostname)
# http.query('/todos/1', 'xyzzy')
# # => #<Net::HTTPOK 200 OK readbody=true>
#
# With no block given, returns the response object:
#
# http = Net::HTTP.new(hostname)
# http.request_query('/todos') # => #<Net::HTTPOK 200 OK readbody=true>
#
# With a block given, calls the block with the response object
# and returns the response object:
#
# http.request_query('/todos') do |res|
# p res
# end # => #<Net::HTTPOK 200 OK readbody=true>
#
# Output:
#
# #<Net::HTTPOK 200 OK readbody=false>
#
def request_query(path, data, initheader = nil, &block) # :yield: +response+
request Query.new(path, initheader), data, &block
end

alias get2 request_get #:nodoc: obsolete
alias head2 request_head #:nodoc: obsolete
alias post2 request_post #:nodoc: obsolete
Expand Down Expand Up @@ -2430,7 +2483,7 @@ def send_entity(path, data, initheader, dest, type, &block)

# :stopdoc:

IDEMPOTENT_METHODS_ = %w/GET HEAD PUT DELETE OPTIONS TRACE/.freeze # :nodoc:
IDEMPOTENT_METHODS_ = %w/GET HEAD PUT DELETE OPTIONS TRACE QUERY/.freeze # :nodoc:

def transport_request(req)
count = 0
Expand Down
1 change: 1 addition & 0 deletions lib/net/http/request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
# - Net::HTTP::Options
# - Net::HTTP::Trace
# - Net::HTTP::Patch
# - Net::HTTP::Query
#
# Subclasses for WebDAV requests:
#
Expand Down
35 changes: 35 additions & 0 deletions lib/net/http/requests.rb
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,41 @@ class Net::HTTP::Patch < Net::HTTPRequest
RESPONSE_HAS_BODY = true
end

# \Class for representing
# {HTTP method QUERY}[https://www.rfc-editor.org/rfc/rfc10008.html]:
#
# require 'net/http'
# uri = URI('http://example.com')
# hostname = uri.hostname # => "example.com"
# uri.path = '/posts'
# req = Net::HTTP::Query.new(uri) # => #<Net::HTTP::Query QUERY>
# req.body = '{"title": "foo","body": "bar","userId": 1}'
# req.content_type = 'application/json'
# res = Net::HTTP.start(hostname) do |http|
# http.request(req)
# end
#
# See {Request Headers}[rdoc-ref:Net::HTTPRequest@Request+Headers].
#
# Properties:
#
# - Request body: yes.
# - Response body: yes.
# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: yes.
# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: yes.
#
# Related:
#
# - Net::HTTP#query: sends +QUERY+ request, returns response object.
#
class Net::HTTP::Query < Net::HTTPRequest
# :stopdoc:
METHOD = 'QUERY'
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
end

#
# WebDAV methods --- RFC2518
#
Expand Down
55 changes: 55 additions & 0 deletions sig/net-http.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ module Net
# body = 'Some text'
# http.post(path, body) # Can also have a block.
# http.put(path, body)
# http.query(path, body) # Can also have a block.
# http.delete(path)
# http.options(path)
# http.trace(path)
Expand Down Expand Up @@ -222,6 +223,7 @@ module Net
# * #options: OPTIONS.
# * #trace: TRACE.
# * #patch: PATCH.
# * #query, #request_query: QUERY.
#
# * [WebDAV methods](https://en.wikipedia.org/wiki/WebDAV#Implementation):
#
Expand Down Expand Up @@ -561,6 +563,8 @@ module Net
# returns a response object.
# * [#put](rdoc-ref:Net::HTTP#put): Sends a PUT request and returns a response
# object.
# * [#query](rdoc-ref:Net::HTTP#query): Sends a QUERY request and returns a
# response object.
# * [#request](rdoc-ref:Net::HTTP#request): Sends a request and returns a
# response object.
# * [#request_get](rdoc-ref:Net::HTTP#request_get): Sends a GET request and
Expand Down Expand Up @@ -1689,6 +1693,27 @@ module Net
#
def put: (String path, String data, ?headers initheader) -> Net::HTTPResponse

# <!--
# rdoc-file=lib/net/http.rb
# - query(path, data, initheader = nil, dest = nil) { |body_segment| ... }
# -->
# Sends a QUERY request to the server; returns an instance of a subclass of
# Net::HTTPResponse.
#
# The request is based on the Net::HTTP::Query object created from string
# `path`, string `data`, and initial headers hash `initheader`.
#
# data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
# http = Net::HTTP.new(hostname)
# http.query('/todos/1', data) # => #<Net::HTTPOK 200 OK readbody=true>
#
# Related:
#
# * Net::HTTP::Query: request class for HTTP method QUERY.
# * Net::HTTP.query: sends QUERY request, returns response body.
#
def query: (String path, String data, ?headers initheader, ?bot dest) ?{ (String body_segment) -> void } -> Net::HTTPResponse

# <!--
# rdoc-file=lib/net/http.rb
# - proppatch(path, body, initheader = nil)
Expand Down Expand Up @@ -1918,6 +1943,35 @@ module Net

def request_put: (String path, String data, ?headers initheader) ?{ (Net::HTTPResponse response) -> void } -> Net::HTTPResponse

# <!--
# rdoc-file=lib/net/http.rb
# - request_query(path, data, initheader = nil) { |response| ... }
# -->
# Sends a QUERY request to the server; forms the response into a
# Net::HTTPResponse object.
#
# The request is based on the Net::HTTP::Query object created from string `path`,
# string `data`, and initial headers hash `initheader`.
#
# With no block given, returns the response object:
#
# http = Net::HTTP.new(hostname)
# http.query('/todos')
# # => #<Net::HTTPOK 200 OK readbody=false>
#
# With a block given, calls the block with the response body and returns the
# response object:
#
# http.request_query('/todos') do |res|
# p res
# end # => #<Net::HTTPOK 200 OK readbody=false>
#
# Output:
#
# #<Net::HTTPOK 200 OK readbody=false>
#
def request_query: (String path, String data, ?headers initheader) ?{ (Net::HTTPResponse response) -> void } -> Net::HTTPResponse

# <!--
# rdoc-file=lib/net/http.rb
# - get2(path, initheader = nil)
Expand Down Expand Up @@ -3233,6 +3287,7 @@ module Net
# * Net::HTTP::Options
# * Net::HTTP::Trace
# * Net::HTTP::Patch
# * Net::HTTP::Query
#
# Subclasses for WebDAV requests:
#
Expand Down
28 changes: 28 additions & 0 deletions test/net/http/test_http.rb
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,7 @@ module TestNetHTTP_version_1_2_methods
def test_request
start {|http|
_test_request__GET http
_test_request__QUERY http
_test_request__accept_encoding http
_test_request__file http
# _test_request__range http # WEBrick does not support Range: header.
Expand Down Expand Up @@ -665,6 +666,21 @@ def _test_request__GET(http)
}
end

def _test_request__QUERY(http)
data = 'query data'
req = Net::HTTP::Query.new('/')
req['Accept'] = $test_net_http_data_type
req['Content-Type'] = 'application/x-www-form-urlencoded'
http.request(req, data) {|res|
assert_kind_of Net::HTTPResponse, res
unless self.is_a?(TestNetHTTP_v1_2_chunked)
assert_equal data.size, res['content-length'].to_i
end
assert_kind_of String, res.body
assert_equal data, res.body
}
end

def _test_request__accept_encoding(http)
req = Net::HTTP::Get.new('/', 'accept-encoding' => 'deflate')
http.request(req) {|res|
Expand Down Expand Up @@ -791,6 +807,7 @@ def _test_request__uri_host(http)
def test_send_request
start {|http|
_test_send_request__GET http
_test_send_request__QUERY http
_test_send_request__HEAD http
_test_send_request__POST http
}
Expand All @@ -806,6 +823,17 @@ def _test_send_request__GET(http)
assert_equal $test_net_http_data, res.body
end

def _test_send_request__QUERY(http)
data = 'aaabbb cc ddddddddddd lkjoiu4j3qlkuoa'
res = http.send_request('QUERY', '/', data, 'content-type' => 'application/x-www-form-urlencoded')
assert_kind_of Net::HTTPResponse, res
unless self.is_a?(TestNetHTTP_v1_2_chunked)
assert_equal data.size, res['content-length'].to_i
end
assert_kind_of String, res.body
assert_equal data, res.body
end

def _test_send_request__HEAD(http)
res = http.send_request('HEAD', '/')
assert_kind_of Net::HTTPResponse, res
Expand Down
9 changes: 9 additions & 0 deletions test/net/http/utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,8 @@ def spawn_server
handle_post(path, headers, socket)
when 'PATCH'
handle_patch(path, headers, socket)
when 'QUERY'
handle_query(path, headers, socket)
else
socket.print "HTTP/1.1 405 Method Not Allowed\r\nContent-Length: 0\r\n\r\n"
end
Expand Down Expand Up @@ -330,6 +332,13 @@ def handle_patch(path, headers, socket)
socket.print(response)
end

def handle_query(path, headers, socket)
body = socket.read(headers['Content-Length'].to_i)
content_type = headers['Content-Type'] || 'application/octet-stream'
response = "HTTP/1.1 200 OK\r\nContent-Type: #{content_type}\r\nContent-Length: #{body.bytesize}\r\n\r\n#{body}"
socket.print(response)
end

def parse_content_type(content_type)
return [nil, nil] unless content_type
type, *params = content_type.split(';').map(&:strip)
Expand Down
Loading