diff options
author | Eric Wong <e+fbsd@80x24.org> | 2014-07-16 19:32:08 +0000 |
---|---|---|
committer | Eric Wong <e+fbsd@80x24.org> | 2014-07-16 19:35:19 +0000 |
commit | 54d8f7898470fa2bb08d308876eecf3e32b33dff (patch) | |
tree | 066362f517f35972b02b7e1a6a21a0c20166a61c /lib/yahns/wbuf.rb | |
parent | 1fd6784e59e9b6d733b1712573d4689affed0140 (diff) | |
download | yahns-54d8f7898470fa2bb08d308876eecf3e32b33dff.tar.gz |
This bug is noticeable on a amd64 FreeBSD 9.2 VM, and possible under Linux, too. This happens as a zero-copy sendfile implementation means pages queued for transmission by the sendfile system call should not be modified at any point after the sendfile syscall is made. To prevent modification, we replace the temporary file with a new one. This has a similar effect as truncate and can still prevent a dirty flush in cases when a client consumes the response fast enough. This reverts the misguided ade89b5142bedbcf07f38aa062bfdbfcb8bc48d3 commit ("wbuf: hack to avoid response corruption on FreeBSD") Note: this bug was finally fixed because I finally noticed this flaw in a different (non-Ruby, non-HTTP) server of mine.
Diffstat (limited to 'lib/yahns/wbuf.rb')
-rw-r--r-- | lib/yahns/wbuf.rb | 21 |
1 files changed, 5 insertions, 16 deletions
diff --git a/lib/yahns/wbuf.rb b/lib/yahns/wbuf.rb index 21bccce..991557e 100644 --- a/lib/yahns/wbuf.rb +++ b/lib/yahns/wbuf.rb @@ -30,16 +30,9 @@ require_relative 'wbuf_common' class Yahns::Wbuf # :nodoc: include Yahns::WbufCommon - # TODO: Figure out why this hack is needed to pass output buffering tests. - # It could be a bug in our code, Ruby, the sendfile gem, or FreeBSD itself. - # Tested on FreeBSD fbsd 9.2-RELEASE FreeBSD 9.2-RELEASE #0 r255898 - # We are able to use bypass mode on Linux to reduce buffering in some - # cases. Without bypass mode, we must always finish writing the entire - # response completely before sending more data to the client. - bypass_ok = RUBY_PLATFORM =~ /linux/ - def initialize(body, persist, tmpdir) @tmpio = Yahns::TmpIO.new(tmpdir) + @tmpdir = tmpdir @sf_offset = @sf_count = 0 @wbuf_persist = persist # whether or not we keep the connection alive @body = body @@ -71,16 +64,12 @@ class Yahns::Wbuf # :nodoc: # we're all caught up, try to prevent dirty data from getting flushed # to disk if we can help it. - @tmpio.truncate(@sf_offset = 0) - @tmpio.rewind + @tmpio.close + @sf_offset = 0 + @tmpio = Yahns::TmpIO.new(@tmpdir) @bypass = true nil - end if bypass_ok - - def wbuf_write(client, buf) - @sf_count += @tmpio.write(buf) - :wait_writable - end unless bypass_ok + end # called by last wbuf_flush def wbuf_close(client) |