Skip to content

Commit

Permalink
Ensure compatibility with --enable-frozen-string-literal
Browse files Browse the repository at this point in the history
  • Loading branch information
byroot committed Mar 21, 2024
1 parent 0ac5192 commit e200863
Show file tree
Hide file tree
Showing 13 changed files with 54 additions and 50 deletions.
6 changes: 5 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ jobs:
matrix:
os: ["ubuntu-latest"]
ruby: ["ruby-head", "3.3", "3.2", "3.1", "3.0", "2.7", "2.6"]
include:
- os: ubuntu-latest
ruby: "3.3"
rubyopt: "--enable-frozen-string-literal --debug-frozen-string-literal"
runs-on: ubuntu-latest
steps:
- name: Check out code
Expand All @@ -26,4 +30,4 @@ jobs:
run: sudo apt-get install -y ragel socat netcat

- name: Tests
run: bundle exec rake
run: bundle exec rake RUBYOPT="${{ matrix.rubyopt }}"
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@ DEPENDENCIES
rake-compiler

BUNDLED WITH
2.3.22
2.5.6
2 changes: 1 addition & 1 deletion lib/pitchfork/http_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class HttpParser
"SERVER_SOFTWARE" => "Pitchfork #{Pitchfork::Const::UNICORN_VERSION}"
}

NULL_IO = StringIO.new("")
NULL_IO = StringIO.new.binmode

# :stopdoc:
HTTP_RESPONSE_START = [ 'HTTP'.freeze, '/1.1 '.freeze ]
Expand Down
2 changes: 1 addition & 1 deletion lib/pitchfork/http_server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -696,7 +696,7 @@ def handle_error(client, e)

def e103_response_write(client, headers)
rss = @request.response_start_sent
buf = rss ? "103 Early Hints\r\n" : "HTTP/1.1 103 Early Hints\r\n"
buf = (rss ? "103 Early Hints\r\n" : "HTTP/1.1 103 Early Hints\r\n").b
headers.each { |key, value| append_header(buf, key, value) }
buf << (rss ? "\r\nHTTP/1.1 ".freeze : "\r\n".freeze)
client.write(buf)
Expand Down
10 changes: 5 additions & 5 deletions lib/pitchfork/stream_input.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def initialize(socket, request) # :nodoc:
@socket = socket
@parser = request
@buf = request.buf
@rbuf = ''
@rbuf = +''
@bytes_read = 0
filter_body(@rbuf, @buf) unless @buf.empty?
end
Expand All @@ -41,7 +41,7 @@ def initialize(socket, request) # :nodoc:
# ios.read(length [, buffer]) will return immediately if there is
# any data and only block when nothing is available (providing
# IO#readpartial semantics).
def read(length = nil, rv = '')
def read(length = nil, rv = ''.b)
if length
if length <= @rbuf.size
length < 0 and raise ArgumentError, "negative length #{length} given"
Expand Down Expand Up @@ -79,16 +79,16 @@ def read(length = nil, rv = '')
# unlike IO#gets.
def gets(sep = $/)
if sep.nil?
read_all(rv = '')
read_all(rv = ''.b)
return rv.empty? ? nil : rv
end
re = /\A(.*?#{Regexp.escape(sep)})/

begin
@rbuf.sub!(re, '') and return $1
@rbuf.sub!(re, ''.b) and return $1
return @rbuf.empty? ? nil : @rbuf.slice!(0, @rbuf.size) if eof?
@socket.readpartial(@@io_chunk_size, @buf) or eof!
filter_body(once = '', @buf)
filter_body(once = ''.b, @buf)
@rbuf << once
end while true
end
Expand Down
4 changes: 2 additions & 2 deletions lib/pitchfork/tee_input.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def initialize(socket, request) # :nodoc:
@len = request.content_length
super
@tmp = @len && @len <= @@client_body_buffer_size ?
StringIO.new("") : new_tmpio
StringIO.new.binmode : new_tmpio
end

# :call-seq:
Expand Down Expand Up @@ -121,7 +121,7 @@ def rewind

# consumes the stream of the socket
def consume!
junk = ""
junk = "".b
nil while read(@@io_chunk_size, junk)
end

Expand Down
2 changes: 1 addition & 1 deletion test/slow/test_server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ def test_client_malformed_body
def do_test(string, chunk, close_after=nil, shutdown_delay=0)
# Do not use instance variables here, because it needs to be thread safe
socket = tcp_socket("127.0.0.1", @port);
request = StringIO.new(string)
request = StringIO.new(+string)
chunks_out = 0

while data = request.read(chunk)
Expand Down
2 changes: 1 addition & 1 deletion test/slow/test_signals.rb
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ def test_response_write
wait_workers_ready("test_stderr.#{$$}.log", 1)
sock = tcp_socket('127.0.0.1', @port)
sock.syswrite("GET / HTTP/1.0\r\n\r\n")
buf = ''
buf = ''.b
header_len = pid = nil
buf = sock.sysread(16384, buf)
pid = buf[/\r\nX-Pid: (\d+)\r\n/, 1].to_i
Expand Down
2 changes: 1 addition & 1 deletion test/slow/test_upload.rb
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ def test_put_trickle_small
@sha1.update(buf)
hdr << buf
sock.syswrite(hdr)
hdr = ''
hdr = ''.b
sleep 0.6
end
read = sock.read.split(/\r\n/)
Expand Down
4 changes: 2 additions & 2 deletions test/unit/test_http_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -364,14 +364,14 @@ def test_parse_error
# make sure we can recover
parser.clear
req.clear
assert_equal req, parser.headers(req, "GET / HTTP/1.0\r\n\r\n")
assert_equal req, parser.headers(req, "GET / HTTP/1.0\r\n\r\n".b)
assert ! parser.keepalive?
end

def test_piecemeal
parser = HttpParser.new
req = parser.env
http = "GET"
http = "GET".b
assert_nil parser.headers(req, http)
assert_nil parser.headers(req, http)
assert_nil parser.headers(req, http << " / HTTP/1.0")
Expand Down
52 changes: 26 additions & 26 deletions test/unit/test_http_parser_ng.rb
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def test_default_keepalive_is_off

def test_identity_byte_headers
req = @parser.env
str = "PUT / HTTP/1.1\r\n"
str = "PUT / HTTP/1.1\r\n".b
str << "Content-Length: 123\r\n"
str << "\r"
hdr = @parser.buf
Expand All @@ -115,7 +115,7 @@ def test_identity_byte_headers
assert ! @parser.keepalive?
assert @parser.headers?
assert_equal 123, @parser.content_length
dst = ""
dst = "".b
buf = '.' * 123
@parser.filter_body(dst, buf)
assert_equal '.' * 123, dst
Expand All @@ -136,7 +136,7 @@ def test_identity_step_headers
assert_equal 0, str.size
assert ! @parser.keepalive?
assert @parser.headers?
dst = ""
dst = "".b
buf = '.' * 123
@parser.filter_body(dst, buf)
assert_equal '.' * 123, dst
Expand All @@ -153,7 +153,7 @@ def test_identity_oneshot_header
assert_equal 0, str.size
assert ! @parser.keepalive?
assert @parser.headers?
dst = ""
dst = "".b
buf = '.' * 123
@parser.filter_body(dst, buf)
assert_equal '.' * 123, dst
Expand All @@ -171,7 +171,7 @@ def test_identity_oneshot_header_with_body
assert_equal '123', req['CONTENT_LENGTH']
assert_equal 123, str.size
assert_equal body, str
tmp = ''
tmp = +''
assert_nil @parser.filter_body(tmp, str)
assert_equal 0, str.size
assert_equal tmp, body
Expand All @@ -185,7 +185,7 @@ def test_identity_oneshot_header_with_body_partial
assert_equal Hash, @parser.parse.class
assert_equal 1, str.size
assert_equal 'a', str
tmp = ''
tmp = +''
assert_nil @parser.filter_body(tmp, str)
assert_equal "", str
assert_equal "a", tmp
Expand All @@ -204,7 +204,7 @@ def test_identity_oneshot_header_with_body_slop
assert_equal Hash, @parser.parse.class
assert_equal 2, str.size
assert_equal 'aG', str
tmp = ''
tmp = +''
assert_nil @parser.filter_body(tmp, str)
assert_equal "G", str
assert_equal "G", @parser.filter_body(tmp, str)
Expand All @@ -219,13 +219,13 @@ def test_chunked
str << "PUT / HTTP/1.1\r\ntransfer-Encoding: chunked\r\n\r\n"
assert_equal req, @parser.parse, "msg=#{str}"
assert_equal 0, str.size
tmp = ""
tmp = "".b
assert_nil @parser.filter_body(tmp, str << "6")
assert_equal 0, tmp.size
assert_nil @parser.filter_body(tmp, str << "\r\n")
assert_equal 0, str.size
assert_equal 0, tmp.size
tmp = ""
tmp = "".b
assert_nil @parser.filter_body(tmp, str << "..")
assert_equal "..", tmp
assert_nil @parser.filter_body(tmp, str << "abcd\r\n0\r\n")
Expand All @@ -245,7 +245,7 @@ def test_chunked_empty
str << "PUT / HTTP/1.1\r\ntransfer-Encoding: chunked\r\n\r\n"
assert_equal req, @parser.parse, "msg=#{str}"
assert_equal 0, str.size
tmp = ""
tmp = "".b
assert_equal str, @parser.filter_body(tmp, str << "0\r\n\r\n")
assert_equal "", tmp
end
Expand All @@ -256,13 +256,13 @@ def test_two_chunks
req = @parser.env
assert_equal req, @parser.parse
assert_equal 0, str.size
tmp = ""
tmp = "".b
assert_nil @parser.filter_body(tmp, str << "6")
assert_equal 0, tmp.size
assert_nil @parser.filter_body(tmp, str << "\r\n")
assert_equal "", str
assert_equal 0, tmp.size
tmp = ""
tmp = "".b
assert_nil @parser.filter_body(tmp, str << "..")
assert_equal 2, tmp.size
assert_equal "..", tmp
Expand All @@ -289,7 +289,7 @@ def test_big_chunk
"4000\r\nabcd"
req = @parser.env
assert_equal req, @parser.parse
tmp = ''
tmp = +''
assert_nil @parser.filter_body(tmp, str)
assert_equal '', str
str << ' ' * 16300
Expand All @@ -315,7 +315,7 @@ def test_two_chunks_oneshot
str << "PUT / HTTP/1.1\r\ntransfer-Encoding: chunked\r\n\r\n" \
"1\r\na\r\n2\r\n..\r\n0\r\n"
assert_equal req, @parser.parse
tmp = ''
tmp = +''
assert_nil @parser.filter_body(tmp, str)
assert_equal 'a..', tmp
rv = @parser.filter_body(tmp, str)
Expand All @@ -331,8 +331,8 @@ def test_chunks_bytewise
req = @parser.env
assert_equal req, @parser.parse
assert_equal "", buf
tmp = ''
body = ''
tmp = +''
body = +''
str = chunked[0..-2]
str.each_byte { |byte|
assert_nil @parser.filter_body(tmp, buf << byte.chr)
Expand All @@ -354,7 +354,7 @@ def test_trailers
assert_equal req, @parser.parse
assert_equal 'Content-MD5', req['HTTP_TRAILER']
assert_nil req['HTTP_CONTENT_MD5']
tmp = ''
tmp = +''
assert_nil @parser.filter_body(tmp, str)
assert_equal 'a..', tmp
md5_b64 = [ Digest::MD5.digest(tmp) ].pack('m').strip.freeze
Expand Down Expand Up @@ -384,7 +384,7 @@ def test_trailers_slowly
assert_equal req, @parser.parse
assert_equal 'Content-MD5', req['HTTP_TRAILER']
assert_nil req['HTTP_CONTENT_MD5']
tmp = ''
tmp = +''
assert_nil @parser.filter_body(tmp, str)
assert_equal 'a..', tmp
md5_b64 = [ Digest::MD5.digest(tmp) ].pack('m').strip.freeze
Expand Down Expand Up @@ -413,7 +413,7 @@ def test_max_chunk
req = @parser.env
assert_equal req, @parser.parse
assert_nil @parser.content_length
@parser.filter_body('', str)
@parser.filter_body(''.b, str)
assert ! @parser.keepalive?
end

Expand All @@ -435,7 +435,7 @@ def test_overflow_chunk
"#{n.to_s(16)}\r\na\r\n2\r\n..\r\n0\r\n"
assert_equal req, @parser.parse
assert_nil @parser.content_length
assert_raises(HttpParserError) { @parser.filter_body('', str) }
assert_raises(HttpParserError) { @parser.filter_body(''.b, str) }
end

def test_overflow_content_length
Expand All @@ -451,7 +451,7 @@ def test_bad_chunk
req = @parser.env
assert_equal req, @parser.parse
assert_nil @parser.content_length
assert_raises(HttpParserError) { @parser.filter_body("", @parser.buf) }
assert_raises(HttpParserError) { @parser.filter_body("".b, @parser.buf) }
end

def test_bad_content_length
Expand All @@ -468,7 +468,7 @@ def test_bad_trailers
"1\r\na\r\n2\r\n..\r\n0\r\n"
assert_equal req, @parser.parse
assert_equal 'Transfer-Encoding', req['HTTP_TRAILER']
tmp = ''
tmp = +''
assert_nil @parser.filter_body(tmp, str)
assert_equal 'a..', tmp
assert_equal '', str
Expand Down Expand Up @@ -598,7 +598,7 @@ def test_chunked_overrides_content_length
assert_equal 'chunked', env['HTTP_TRANSFER_ENCODING']
assert_equal '666', env['CONTENT_LENGTH'],
'Content-Length logged so the app can log a possible client bug/attack'
@parser.filter_body(dst = '', str)
@parser.filter_body(dst = ''.b, str)
assert_equal 'helloworld', dst
@parser.parse # handle the non-existent trailer
assert @parser.next?
Expand All @@ -609,15 +609,15 @@ def test_chunked_order_good
str = "PUT /x HTTP/1.1\r\n" \
"Transfer-Encoding: gzip\r\n" \
"Transfer-Encoding: chunked\r\n" \
"\r\n"
"\r\n".b
env = @parser.headers({}, str)
assert_equal 'gzip,chunked', env['HTTP_TRANSFER_ENCODING']
assert_nil @parser.content_length

@parser.clear
str = "PUT /x HTTP/1.1\r\n" \
"Transfer-Encoding: gzip, chunked\r\n" \
"\r\n"
"\r\n".b
env = @parser.headers({}, str)
assert_equal 'gzip, chunked', env['HTTP_TRANSFER_ENCODING']
assert_nil @parser.content_length
Expand Down Expand Up @@ -677,7 +677,7 @@ def test_ignore_version_header
end

def test_pipelined_requests
host = "example.com"
host = "example.com".b
expect = {
"HTTP_HOST" => host,
"SERVER_NAME" => host,
Expand Down
Loading

0 comments on commit e200863

Please # to comment.