I’m not sure where to look for the bug that I seem to have found in the
socket library on Windows 2000. I’ve made some modifications to the Net
module (at end of message), and I am executing the following code using
it to send an HTTP GET request with a very long query string.
host = 'localhost’
port = 80
http = Net::HTTP.new( host, port )
request_method = 'GET’
request_has_body = FALSE
response_has_body = TRUE
N = 320
path = ‘/index.html’ + ‘?’ + ‘%FF’ * ( 41 * 1024 + N )
extra_headers = nil
req = Net::HTTPGenericRequest.new( request_method, request_has_body,
response_has_body, path, extra_headers )
post_data = nil
test = FALSE
response, = http.request( req, post_data, test )
I get the following error message from Ruby 1.7.3:
C:/Progra~1/Ruby/lib/ruby/1.7/net/protocol.rb:501:in sysread': Invalid argument (Errno::EINVAL) from C:/Progra~1/Ruby/lib/ruby/1.7/net/protocol.rb:501:in
rbuf_fill’
from C:/Progra~1/Ruby/lib/ruby/1.7/net/protocol.rb:477:in
readuntil' from C:/Progra~1/Ruby/lib/ruby/1.7/net/protocol.rb:488:in
readline’
from C:/Progra~1/Ruby/lib/ruby/1.7/net/http.rb:1415:in
read_status_line' from C:/Progra~1/Ruby/lib/ruby/1.7/net/http.rb:1399:in
read_new’
from
C:/Perforce_workspace/2.0.5/regress/bin/send_HTTP_request.rb:115:in
request' from C:/Perforce_workspace/2.0.5/regress/bin/send_HTTP_request.rb:108:in
request’
from
C:/Perforce_workspace/2.0.5/regress/bin/send_HTTP_request.rb:106:in
start' from C:/Perforce_workspace/2.0.5/regress/bin/send_HTTP_request.rb:109:in
request’
from
C:/Perforce_workspace/2.0.5/regress/bin/send_HTTP_request.rb:441
Ruby 1.6.7 gives a similar but not identical set of error messages:
C:/Perforce_workspace/2.0.5/nt/tools/Ruby/lib/ruby/1.6/net/protocol.rb:5
76:in write': Invalid argument (Errno::EINVAL) from C:/Perforce_workspace/2.0.5/nt/tools/Ruby/lib/ruby/1.6/net/protocol.rb:5 76:in
do_write’
from
C:/Perforce_workspace/2.0.5/nt/tools/Ruby/lib/ruby/1.6/net/protocol.rb:5
59:in writeline' from C:/Perforce_workspace/2.0.5/nt/tools/Ruby/lib/ruby/1.6/net/protocol.rb:5 59:in
writing’
from
C:/Perforce_workspace/2.0.5/nt/tools/Ruby/lib/ruby/1.6/net/protocol.rb:5
59:in writeline' from C:\Perforce_workspace\2.0.5\regress\bin\send_HTTP_request_TEST.rb:246:in
request’
from
C:\Perforce_workspace\2.0.5\regress\bin\send_HTTP_request_TEST.rb:194:in
exec' from C:\Perforce_workspace\2.0.5\regress\bin\send_HTTP_request_TEST.rb:113:in
request’
from
C:\Perforce_workspace\2.0.5\regress\bin\send_HTTP_request_TEST.rb:108:in
request' from C:\Perforce_workspace\2.0.5\regress\bin\send_HTTP_request_TEST.rb:107:in
start’
from
C:\Perforce_workspace\2.0.5\regress\bin\send_HTTP_request_TEST.rb:107:in
`request’
from
C:\Perforce_workspace\2.0.5\regress\bin\send_HTTP_request_TEST.rb:449
When the value of the variable “N” is less than 320, the sending of the
request works OK, but the error behavior occurs for N >= 320 for both
Ruby 1.7.3 and 1.6.7. I had hoped Ruby would be able to construct and
send query strings and POST request bodies of arbitrary size for
boundary case testing of our product, but I’m running up against this
error, which I don’t really know what to do about. Any ideas out there?
Thanks in advance,
Al
module Net
class HTTP
alias :old_request :request
# Modification: add “test” parameter.
def request( req, body = nil, test = FALSE, &block )
unless started? then
start {
req[‘connection’] = 'close’
return request(req, body, test, &block)
}
end
begin_transport req
req.exec @socket, @curr_http_version, edit_path(req.path), body,
test
begin
res = HTTPResponse.read_new(@socket)
end while HTTPContinue === res
res.reading_body(@socket, req.response_body_permitted?) {
yield res if block_given?
}
end_transport req, res
res
end
attr_accessor :curr_http_version
end
module HTTPHeader
# Change behavior: do not set header names to lowercase.
alias :old_writer :[]=
def []=( key, val )
@header[ key.downcase ] = val
@header_array << [key, val]
end
end
class HTTPResponse
alias :old_initialize :initialize
def initialize( httpv, code, msg )
@http_version = httpv
@code = code
@message = msg
@header = {}
@body = nil
@read = false
@header_array = Array.new
end
attr_reader :header_array
end
class HTTPGenericRequest
attr_accessor :header
# Add header_array instance variable.
alias :old_initialize :initialize
def initialize( m, reqbody, resbody, path, initheader = nil )
@method = m
@request_has_body = reqbody
@response_has_body = resbody
@path = path
@header = tmp = {}
@header_array = Array.new
return unless initheader
initheader.each do |k,v|
key = k.downcase
if tmp.key? key then
$stderr.puts "WARNING: duplicated HTTP header: #{k}" if
$VERBOSE
end
tmp[ key ] = v.strip
end
tmp[‘accept’] ||= '/'
end
alias :old_exec :exec
# Modification: add "test" parameter.
def exec( sock, ver, path, body, test = FALSE )
if body then
raise ArgumentError, 'HTTP request body is not premitted' unless
request_body_permitted?
send_request_with_body sock, ver, path, body, test
else
request sock, ver, path, test
end
end
alias :old_send_request_with_body :send_request_with_body
# Modification: add "test" parameter.
def send_request_with_body( sock, ver, path, body, test = FALSE )
if block_given? then
ac = Accumulator.new
yield ac # must be yield, DO NOT USE block.call
data = ac.terminate
else
data = body
end
# Modification: only calculate and set Content-Length if its
value hasn’t already been specified.
unless @header[‘content-length’]
@header[‘content-length’] = data.size.to_s
@header.delete 'transfer-encoding’
end
# Modification: only set Content-Type if its value hasn't already
been specified.
unless @header[‘content-type’]
$stderr.puts ‘Content-Type did not set; using
application/x-www-form-urlencoded’ if $VERBOSE
@header[‘content-type’] = 'application/x-www-form-urlencoded’
end
# Modification: add "test" argument.
request sock, ver, path, test
# Modification: add if statement.
if test then
puts data
exit
else
sock.write data
end
end
alias :old_request :request
def request( sock, ver, path, test = FALSE )
# Modification: add "test" option.
if test then
sprintf('%s %s HTTP/%s', @method, path, ver)
canonical_each do |k,v|
puts k + ': ' + v
end
puts ''
else
sock.writeline sprintf('%s %s HTTP/%s', @method, path, ver)
canonical_each do |k,v|
sock.writeline k + ': ' + v
end
sock.writeline ''
end
end
end
end
···
–
Albert Davidson Chou, QA Manager
TeaLeaf Technology, Inc.
(415) 932-5031
AChou@TeaLeaf.com | http://www.TeaLeaf.com/
Evaluate TeaLeaf Technology today:
http://www.TeaLeaf.com/demo/