1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
| | # -*- encoding: binary -*-
# Copyright (C) 2013-2016 all contributors <yahns-public@yhbt.net>
# License: GPL-3.0+ (https://www.gnu.org/licenses/gpl-3.0.txt)
# frozen_string_literal: true
begin
raise LoadError, "SENDFILE_BROKEN env set" if ENV["SENDFILE_BROKEN"]
require 'sendfile'
rescue LoadError
require_relative 'sendfile_compat'
IO.__send__ :include, Yahns::SendfileCompat
end
module Yahns::WbufCommon # :nodoc:
# returns true / false for persistent/non-persistent connections
# returns :wait_*able when blocked
# returns :ignore if hijacked
# currently, we rely on each thread having exclusive access to the
# client socket, so this is never called concurrently with wbuf_write
def wbuf_flush(client)
case rv = client.trysendfile(@tmpio, @sf_offset, @sf_count)
when Integer
if (@sf_count -= rv) == 0 # all sent!
@sf_offset = 0
return wbuf_close(client)
end
@sf_offset += rv # keep going otherwise
when :wait_writable, :wait_readable
return rv
when nil
# response got truncated, drop the connection
# this may happens when using Rack::File or similar, we can't
# keep the connection alive because we already sent our Content-Length
# header the client would be confused.
@wbuf_persist = false
return wbuf_close(client)
else
raise "BUG: rv=#{rv.inspect} " \
"on tmpio=#{@tmpio.inspect} " \
"sf_offset=#@sf_offset sf_count=#@sf_count"
end while @sf_count > 0
wbuf_close(client)
rescue
@wbuf_persist = false # ensure a hijack response is not called
wbuf_close(client)
raise
end
def wbuf_close_common(client)
@body.close if @body.respond_to?(:close)
if @wbuf_persist.respond_to?(:call) # hijack
client.response_hijacked(@wbuf_persist) # :ignore
else
@wbuf_persist # true, false, :ignore, or Yahns::StreamFile
end
end
end
|