yahns 1.12.5 → 1.13.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Documentation/yahns-rackup.pod +0 -10
- data/Documentation/yahns_config.pod +3 -0
- data/GIT-VERSION-FILE +1 -1
- data/GIT-VERSION-GEN +1 -1
- data/NEWS +80 -0
- data/examples/init.sh +34 -9
- data/examples/logrotate.conf +5 -0
- data/examples/yahns.socket +17 -0
- data/examples/yahns@.service +50 -0
- data/examples/yahns_rack_basic.conf.rb +0 -6
- data/extras/autoindex.rb +3 -2
- data/extras/exec_cgi.rb +1 -0
- data/extras/try_gzip_static.rb +19 -5
- data/lib/yahns/chunk_body.rb +27 -0
- data/lib/yahns/fdmap.rb +7 -4
- data/lib/yahns/http_client.rb +39 -10
- data/lib/yahns/http_response.rb +41 -22
- data/lib/yahns/openssl_client.rb +7 -3
- data/lib/yahns/proxy_http_response.rb +132 -159
- data/lib/yahns/proxy_pass.rb +6 -170
- data/lib/yahns/queue_epoll.rb +1 -0
- data/lib/yahns/queue_kqueue.rb +1 -0
- data/lib/yahns/req_res.rb +164 -0
- data/lib/yahns/server.rb +2 -1
- data/lib/yahns/server_mp.rb +1 -1
- data/lib/yahns/version.rb +1 -1
- data/lib/yahns/wbuf.rb +5 -6
- data/lib/yahns/wbuf_common.rb +5 -10
- data/lib/yahns/wbuf_lite.rb +111 -0
- data/man/yahns-rackup.1 +29 -29
- data/man/yahns_config.5 +47 -35
- data/test/helper.rb +12 -0
- data/test/test_auto_chunk.rb +56 -0
- data/test/test_extras_exec_cgi.rb +1 -3
- data/test/test_extras_try_gzip_static.rb +30 -16
- data/test/test_output_buffering.rb +5 -1
- data/test/test_proxy_pass.rb +2 -2
- data/test/test_proxy_pass_no_buffering.rb +170 -0
- data/test/test_reopen_logs.rb +5 -1
- data/test/test_response.rb +42 -0
- data/test/test_server.rb +35 -0
- data/test/test_ssl.rb +0 -6
- data/test/test_tmpio.rb +4 -0
- data/test/test_wbuf.rb +11 -4
- metadata +10 -4
- data/lib/yahns/sendfile_compat.rb +0 -24
@@ -0,0 +1,164 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
# Copyright (C) 2013-2016 all contributors <yahns-public@yhbt.net>
|
3
|
+
# License: GPL-3.0+ (https://www.gnu.org/licenses/gpl-3.0.txt)
|
4
|
+
# frozen_string_literal: true
|
5
|
+
# Only used by Yahns::ProxyPass
|
6
|
+
require 'kcar' # gem install kcar
|
7
|
+
require 'kgio'
|
8
|
+
|
9
|
+
class Yahns::ReqRes < Kgio::Socket # :nodoc:
|
10
|
+
attr_accessor :resbuf
|
11
|
+
attr_accessor :proxy_trailers
|
12
|
+
attr_accessor :alive
|
13
|
+
attr_reader :proxy_pass
|
14
|
+
|
15
|
+
def req_start(c, req, input, chunked, proxy_pass)
|
16
|
+
@hdr = @resbuf = nil
|
17
|
+
@yahns_client = c
|
18
|
+
@rrstate = input ? [ req, input, chunked ] : req
|
19
|
+
@proxy_pass = proxy_pass
|
20
|
+
Thread.current[:yahns_queue].queue_add(self, Yahns::Queue::QEV_WR)
|
21
|
+
end
|
22
|
+
|
23
|
+
def yahns_step # yahns event loop entry point
|
24
|
+
c = @yahns_client
|
25
|
+
case req = @rrstate
|
26
|
+
when Kcar::Parser # reading response...
|
27
|
+
buf = Thread.current[:yahns_rbuf]
|
28
|
+
|
29
|
+
case resbuf = @resbuf # where are we at the response?
|
30
|
+
when nil # common case, catch the response header in a single read
|
31
|
+
|
32
|
+
case rv = kgio_tryread(0x2000, buf)
|
33
|
+
when String
|
34
|
+
if res = req.headers(@hdr = [], rv)
|
35
|
+
return c.proxy_response_start(res, rv, req, self)
|
36
|
+
else # ugh, big headers or tricked response
|
37
|
+
# we must reinitialize the thread-local rbuf if it may
|
38
|
+
# live beyond the current thread
|
39
|
+
buf = Thread.current[:yahns_rbuf] = ''.dup
|
40
|
+
@resbuf = rv
|
41
|
+
end
|
42
|
+
# continue looping in middle "case @resbuf" loop
|
43
|
+
when :wait_readable
|
44
|
+
return rv # spurious wakeup
|
45
|
+
when nil
|
46
|
+
return c.proxy_err_response(502, self, 'upstream EOF (headers)')
|
47
|
+
end # NOT looping here
|
48
|
+
|
49
|
+
when String # continue reading trickled response headers from upstream
|
50
|
+
|
51
|
+
case rv = kgio_tryread(0x2000, buf)
|
52
|
+
when String then res = req.headers(@hdr, resbuf << rv) and break
|
53
|
+
when :wait_readable then return rv
|
54
|
+
when nil
|
55
|
+
return c.proxy_err_response(502, self, 'upstream EOF (big headers)')
|
56
|
+
end while true
|
57
|
+
@resbuf = false
|
58
|
+
|
59
|
+
return c.proxy_response_start(res, resbuf, req, self)
|
60
|
+
|
61
|
+
when Yahns::WbufCommon # streaming/buffering the response body
|
62
|
+
|
63
|
+
return c.proxy_response_finish(req, self)
|
64
|
+
|
65
|
+
end while true # case @resbuf
|
66
|
+
|
67
|
+
when Array # [ (str|vec), rack.input, chunked? ]
|
68
|
+
send_req_body(req) # returns nil or :wait_writable
|
69
|
+
when String # buffered request header
|
70
|
+
send_req_buf(req)
|
71
|
+
end
|
72
|
+
rescue => e
|
73
|
+
# avoid polluting logs with a giant backtrace when the problem isn't
|
74
|
+
# fixable in code.
|
75
|
+
case e
|
76
|
+
when Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::EPIPE
|
77
|
+
e.set_backtrace([])
|
78
|
+
end
|
79
|
+
c.proxy_err_response(502, self, e)
|
80
|
+
end
|
81
|
+
|
82
|
+
def send_req_body_chunk(buf)
|
83
|
+
case rv = String === buf ? kgio_trywrite(buf) : kgio_trywritev(buf)
|
84
|
+
when String, Array
|
85
|
+
buf.replace(rv) # retry loop on partial write
|
86
|
+
when :wait_writable, nil
|
87
|
+
# :wait_writable = upstream is reading slowly and making us wait
|
88
|
+
return rv
|
89
|
+
else
|
90
|
+
abort "BUG: #{rv.inspect} from kgio_trywrite*"
|
91
|
+
end while true
|
92
|
+
end
|
93
|
+
|
94
|
+
# returns :wait_readable if complete, :wait_writable if not
|
95
|
+
def send_req_body(req) # @rrstate == [ (str|vec), rack.input, chunked? ]
|
96
|
+
buf, input, chunked = req
|
97
|
+
|
98
|
+
# send the first buffered chunk or vector
|
99
|
+
rv = send_req_body_chunk(buf) and return rv # :wait_writable
|
100
|
+
|
101
|
+
# yay, sent the first chunk, now read the body!
|
102
|
+
rbuf = buf
|
103
|
+
if chunked
|
104
|
+
if String === buf # initial body
|
105
|
+
req[0] = buf = []
|
106
|
+
else
|
107
|
+
# try to reuse the biggest non-frozen buffer we just wrote;
|
108
|
+
rbuf = buf.max_by(&:size)
|
109
|
+
rbuf = ''.dup if rbuf.frozen? # unlikely...
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# Note: input (env['rack.input']) is fully-buffered by default so
|
114
|
+
# we should not be waiting on a slow network resource when reading
|
115
|
+
# input. However, some weird configs may disable this on LANs
|
116
|
+
# and we may wait indefinitely on input.read here...
|
117
|
+
while input.read(0x2000, rbuf)
|
118
|
+
if chunked
|
119
|
+
buf[0] = "#{rbuf.size.to_s(16)}\r\n".freeze
|
120
|
+
buf[1] = rbuf
|
121
|
+
buf[2] = "\r\n".freeze
|
122
|
+
end
|
123
|
+
rv = send_req_body_chunk(buf) and return rv # :wait_writable
|
124
|
+
end
|
125
|
+
|
126
|
+
rbuf.clear # all done, clear the big buffer
|
127
|
+
|
128
|
+
# we cannot use respond_to?(:close) here since Rack::Lint::InputWrapper
|
129
|
+
# tries to prevent that (and hijack means all Rack specs go out the door)
|
130
|
+
case input
|
131
|
+
when Yahns::TeeInput, IO
|
132
|
+
input.close
|
133
|
+
end
|
134
|
+
|
135
|
+
# note: we do not send any trailer, they are folded into the header
|
136
|
+
# because this relies on full request buffering
|
137
|
+
# prepare_wait_readable is called by send_req_buf
|
138
|
+
chunked ? send_req_buf("0\r\n\r\n".freeze) : prepare_wait_readable
|
139
|
+
rescue Errno::EPIPE, Errno::ECONNRESET, Errno::ENOTCONN
|
140
|
+
# no more reading off the client socket, just prepare to forward
|
141
|
+
# the rejection response from the upstream (if any)
|
142
|
+
@yahns_client.to_io.shutdown(Socket::SHUT_RD)
|
143
|
+
prepare_wait_readable
|
144
|
+
end
|
145
|
+
|
146
|
+
def prepare_wait_readable
|
147
|
+
@rrstate = Kcar::Parser.new
|
148
|
+
:wait_readable # all done sending the request, wait for response
|
149
|
+
end
|
150
|
+
|
151
|
+
# n.b. buf must be a detached string not shared with
|
152
|
+
# Thread.current[:yahns_rbuf] of any thread
|
153
|
+
def send_req_buf(buf)
|
154
|
+
case rv = kgio_trywrite(buf)
|
155
|
+
when String
|
156
|
+
buf = rv # retry inner loop
|
157
|
+
when :wait_writable
|
158
|
+
@rrstate = buf
|
159
|
+
return :wait_writable
|
160
|
+
when nil
|
161
|
+
return prepare_wait_readable
|
162
|
+
end while true
|
163
|
+
end
|
164
|
+
end # class ReqRes
|
data/lib/yahns/server.rb
CHANGED
@@ -496,7 +496,8 @@ class Yahns::Server # :nodoc:
|
|
496
496
|
def dropping(fdmap)
|
497
497
|
if drop_acceptors[0] || fdmap.size > 0
|
498
498
|
timeout = @shutdown_expire < Yahns.now ? -1 : @shutdown_timeout
|
499
|
-
fdmap.desperate_expire(timeout)
|
499
|
+
n = fdmap.desperate_expire(timeout)
|
500
|
+
$0 = "yahns quitting, #{n} FD(s) remain"
|
500
501
|
true
|
501
502
|
else
|
502
503
|
false
|
data/lib/yahns/server_mp.rb
CHANGED
@@ -159,7 +159,7 @@ module Yahns::ServerMP # :nodoc:
|
|
159
159
|
def mp_sig_handle(watch, alive)
|
160
160
|
# not performance critical
|
161
161
|
watch.delete_if { |io| io.to_io.closed? }
|
162
|
-
if r = IO.select(watch, nil, nil, alive ? nil : 0.
|
162
|
+
if r = IO.select(watch, nil, nil, alive ? nil : 0.1)
|
163
163
|
r[0].each(&:yahns_step)
|
164
164
|
end
|
165
165
|
case @sig_queue.shift
|
data/lib/yahns/version.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
Yahns::VERSION = '1.
|
1
|
+
Yahns::VERSION = '1.13.0'.freeze # :nodoc:
|
data/lib/yahns/wbuf.rb
CHANGED
@@ -31,15 +31,13 @@ require_relative 'wbuf_common'
|
|
31
31
|
class Yahns::Wbuf # :nodoc:
|
32
32
|
include Yahns::WbufCommon
|
33
33
|
attr_reader :busy
|
34
|
-
attr_reader :wbuf_persist
|
35
34
|
|
36
|
-
def initialize(body, persist
|
35
|
+
def initialize(body, persist)
|
37
36
|
@tmpio = nil
|
38
|
-
@tmpdir = tmpdir
|
39
37
|
@sf_offset = @sf_count = 0
|
40
38
|
@wbuf_persist = persist # whether or not we keep the connection alive
|
41
|
-
@body = body
|
42
|
-
@busy =
|
39
|
+
@body = body # something we call #close on when done writing
|
40
|
+
@busy = false
|
43
41
|
end
|
44
42
|
|
45
43
|
def wbuf_writev(buf)
|
@@ -59,7 +57,8 @@ class Yahns::Wbuf # :nodoc:
|
|
59
57
|
@busy = rv
|
60
58
|
end until @busy
|
61
59
|
|
62
|
-
@tmpio ||= Yahns::TmpIO.new(
|
60
|
+
@tmpio ||= Yahns::TmpIO.new(c.class.output_buffer_tmpdir)
|
61
|
+
# n.b.: we rely on O_APPEND in TmpIO, here
|
63
62
|
@sf_count += String === buf ? @tmpio.write(buf) : wbuf_writev(buf)
|
64
63
|
|
65
64
|
# we spent some time copying to the FS, try to write to
|
data/lib/yahns/wbuf_common.rb
CHANGED
@@ -2,14 +2,6 @@
|
|
2
2
|
# Copyright (C) 2013-2016 all contributors <yahns-public@yhbt.net>
|
3
3
|
# License: GPL-3.0+ (https://www.gnu.org/licenses/gpl-3.0.txt)
|
4
4
|
# frozen_string_literal: true
|
5
|
-
begin
|
6
|
-
raise LoadError, "SENDFILE_BROKEN env set" if ENV["SENDFILE_BROKEN"]
|
7
|
-
require 'sendfile'
|
8
|
-
rescue LoadError
|
9
|
-
require_relative 'sendfile_compat'
|
10
|
-
IO.__send__ :include, Yahns::SendfileCompat
|
11
|
-
end
|
12
|
-
|
13
5
|
module Yahns::WbufCommon # :nodoc:
|
14
6
|
# returns true / false for persistent/non-persistent connections
|
15
7
|
# returns :wait_*able when blocked
|
@@ -19,7 +11,10 @@ module Yahns::WbufCommon # :nodoc:
|
|
19
11
|
def wbuf_flush(client)
|
20
12
|
case rv = client.trysendfile(@tmpio, @sf_offset, @sf_count)
|
21
13
|
when Integer
|
22
|
-
|
14
|
+
if (@sf_count -= rv) == 0 # all sent!
|
15
|
+
@sf_offset = 0
|
16
|
+
return wbuf_close(client)
|
17
|
+
end
|
23
18
|
|
24
19
|
@sf_offset += rv # keep going otherwise
|
25
20
|
when :wait_writable, :wait_readable
|
@@ -48,7 +43,7 @@ module Yahns::WbufCommon # :nodoc:
|
|
48
43
|
if @wbuf_persist.respond_to?(:call) # hijack
|
49
44
|
client.response_hijacked(@wbuf_persist) # :ignore
|
50
45
|
else
|
51
|
-
@wbuf_persist # true
|
46
|
+
@wbuf_persist # true, false, :ignore, or Yahns::StreamFile
|
52
47
|
end
|
53
48
|
end
|
54
49
|
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
# Copyright (C) 2016 all contributors <yahns-public@yhbt.net>
|
3
|
+
# License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
|
4
|
+
# frozen_string_literal: true
|
5
|
+
require 'stringio'
|
6
|
+
require_relative 'wbuf_common'
|
7
|
+
|
8
|
+
# This is only used for "proxy_buffering: false"
|
9
|
+
class Yahns::WbufLite # :nodoc:
|
10
|
+
include Yahns::WbufCommon
|
11
|
+
attr_reader :busy
|
12
|
+
attr_writer :req_res
|
13
|
+
|
14
|
+
def initialize(req_res)
|
15
|
+
@tmpio = nil
|
16
|
+
@sf_offset = @sf_count = 0
|
17
|
+
@wbuf_persist = :ignore
|
18
|
+
@busy = false
|
19
|
+
@req_res = req_res
|
20
|
+
end
|
21
|
+
|
22
|
+
def wbuf_write(c, buf)
|
23
|
+
buf = buf.join if Array === buf
|
24
|
+
# try to bypass the VFS layer and write directly to the socket
|
25
|
+
# if we're all caught up
|
26
|
+
case rv = c.kgio_trywrite(buf)
|
27
|
+
when String
|
28
|
+
buf = rv # retry in loop
|
29
|
+
when nil
|
30
|
+
return # yay! hopefully we don't have to buffer again
|
31
|
+
when :wait_writable, :wait_readable
|
32
|
+
@busy = rv
|
33
|
+
end until @busy
|
34
|
+
|
35
|
+
@tmpio ||= StringIO.new(''.dup) # relies on encoding: binary above
|
36
|
+
@tmpio.seek(0, 2) # fake O_APPEND behavior
|
37
|
+
@sf_count += @tmpio.write(buf)
|
38
|
+
|
39
|
+
# we spent some time copying to the FS, try to write to
|
40
|
+
# the socket again in case some space opened up...
|
41
|
+
case rv = c.trysendio(@tmpio, @sf_offset, @sf_count)
|
42
|
+
when Integer
|
43
|
+
@sf_count -= rv
|
44
|
+
@sf_offset += rv
|
45
|
+
when :wait_writable, :wait_readable
|
46
|
+
@busy = rv
|
47
|
+
return rv
|
48
|
+
else
|
49
|
+
raise "BUG: #{rv.nil? ? 'EOF' : rv.inspect} on " \
|
50
|
+
"tmpio.size=#{@tmpio.size} " \
|
51
|
+
"sf_offset=#@sf_offset sf_count=#@sf_count"
|
52
|
+
end while @sf_count > 0
|
53
|
+
|
54
|
+
# we're all caught up, try to save some memory if we can help it.
|
55
|
+
wbuf_abort
|
56
|
+
@busy = false
|
57
|
+
nil
|
58
|
+
rescue
|
59
|
+
@req_res = @req_res.close if @req_res
|
60
|
+
raise
|
61
|
+
end
|
62
|
+
|
63
|
+
def wbuf_flush(client)
|
64
|
+
case rv = client.trysendio(@tmpio, @sf_offset, @sf_count)
|
65
|
+
when Integer
|
66
|
+
return wbuf_close(client) if (@sf_count -= rv) == 0 # all sent!
|
67
|
+
@sf_offset += rv # keep going otherwise
|
68
|
+
when :wait_writable, :wait_readable
|
69
|
+
return rv
|
70
|
+
else
|
71
|
+
raise "BUG: #{rv.nil? ? 'EOF' : rv.inspect} on " \
|
72
|
+
"tmpio.size=#{@tmpio.size} " \
|
73
|
+
"sf_offset=#@sf_offset sf_count=#@sf_count"
|
74
|
+
end while @sf_count > 0
|
75
|
+
wbuf_close(client)
|
76
|
+
rescue
|
77
|
+
@wbuf_persist = false # ensure a hijack response is not called
|
78
|
+
@req_res = @req_res.close if @req_res
|
79
|
+
wbuf_close(client)
|
80
|
+
raise
|
81
|
+
end
|
82
|
+
|
83
|
+
# called by Yahns::HttpClient#step_write
|
84
|
+
def wbuf_close(client)
|
85
|
+
wbuf_abort if @tmpio
|
86
|
+
|
87
|
+
# resume the event loop when @blocked is empty
|
88
|
+
# The actual Yahns::ReqRes#yahns_step is actually read/write-event
|
89
|
+
# agnostic, and we should actually watch for writability here since
|
90
|
+
# the req_res socket itself could be completely drained of readable
|
91
|
+
# data and just waiting for another request (which we don't support, yet)
|
92
|
+
if @req_res
|
93
|
+
@busy = false
|
94
|
+
client.hijack_cleanup
|
95
|
+
Thread.current[:yahns_queue].queue_mod(@req_res, Yahns::Queue::QEV_WR)
|
96
|
+
return :ignore
|
97
|
+
end
|
98
|
+
@wbuf_persist
|
99
|
+
rescue
|
100
|
+
@req_res = @req_res.close if @req_res
|
101
|
+
raise
|
102
|
+
end
|
103
|
+
|
104
|
+
def wbuf_abort
|
105
|
+
@sf_offset = @sf_count = 0
|
106
|
+
# we can safely truncate since this is a StringIO, we cannot do this
|
107
|
+
# with a real file because zero-copy with sendfile means truncating
|
108
|
+
# a while could clobber in-flight data
|
109
|
+
@tmpio.truncate(0)
|
110
|
+
end
|
111
|
+
end
|
data/man/yahns-rackup.1
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
.\" Automatically generated by Pod::Man 2.
|
1
|
+
.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.28)
|
2
2
|
.\"
|
3
3
|
.\" Standard preamble:
|
4
4
|
.\" ========================================================================
|
@@ -38,6 +38,8 @@
|
|
38
38
|
. ds PI \(*p
|
39
39
|
. ds L" ``
|
40
40
|
. ds R" ''
|
41
|
+
. ds C`
|
42
|
+
. ds C'
|
41
43
|
'br\}
|
42
44
|
.\"
|
43
45
|
.\" Escape single quotes in literal strings from groff's Unicode transform.
|
@@ -48,17 +50,24 @@
|
|
48
50
|
.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
|
49
51
|
.\" entries marked with X<> in POD. Of course, you'll have to process the
|
50
52
|
.\" output yourself in some meaningful fashion.
|
51
|
-
|
52
|
-
.
|
53
|
-
.
|
53
|
+
.\"
|
54
|
+
.\" Avoid warning from groff about undefined register 'F'.
|
55
|
+
.de IX
|
54
56
|
..
|
55
|
-
.
|
56
|
-
.
|
57
|
-
|
58
|
-
.
|
59
|
-
.
|
57
|
+
.nr rF 0
|
58
|
+
.if \n(.g .if rF .nr rF 1
|
59
|
+
.if (\n(rF:(\n(.g==0)) \{
|
60
|
+
. if \nF \{
|
61
|
+
. de IX
|
62
|
+
. tm Index:\\$1\t\\n%\t"\\$2"
|
60
63
|
..
|
64
|
+
. if !\nF==2 \{
|
65
|
+
. nr % 0
|
66
|
+
. nr F 2
|
67
|
+
. \}
|
68
|
+
. \}
|
61
69
|
.\}
|
70
|
+
.rr rF
|
62
71
|
.\"
|
63
72
|
.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
|
64
73
|
.\" Fear. Run. Save yourself. No user-serviceable parts.
|
@@ -124,7 +133,7 @@
|
|
124
133
|
.\" ========================================================================
|
125
134
|
.\"
|
126
135
|
.IX Title "YAHNS-RACKUP 1"
|
127
|
-
.TH YAHNS-RACKUP 1 "1994-10-02" "yahns 1.12.
|
136
|
+
.TH YAHNS-RACKUP 1 "1994-10-02" "yahns 1.12.5.48.g013d" "yahns user manual"
|
128
137
|
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
|
129
138
|
.\" way too many mistakes in technical documents.
|
130
139
|
.if n .ad l
|
@@ -140,7 +149,7 @@ A \fIrackup\fR\|(1)\-like command to launch Rack applications using yahns.
|
|
140
149
|
It is expected to start in your application root (\s-1APP_ROOT\s0).
|
141
150
|
.SH "RACKUP FILE"
|
142
151
|
.IX Header "RACKUP FILE"
|
143
|
-
This defaults to \*(L"config.ru\*(R" in \s-1APP_ROOT\s0
|
152
|
+
This defaults to \*(L"config.ru\*(R" in \s-1APP_ROOT. \s0 It should be the same
|
144
153
|
file used by \fIrackup\fR\|(1) and other Rack launchers, it uses the
|
145
154
|
*Rack::Builder* \s-1DSL\s0 documented at:
|
146
155
|
.PP
|
@@ -157,8 +166,8 @@ default timeout. Lower this if you run out of FDs.
|
|
157
166
|
Default: 15 (seconds)
|
158
167
|
.IP "\-O listen=ADDRESS[,ADDRESS...]" 4
|
159
168
|
.IX Item "-O listen=ADDRESS[,ADDRESS...]"
|
160
|
-
Listens on a given \s-1ADDRESS
|
161
|
-
\&\s-1HOST:PORT\s0 or \s-1PATH
|
169
|
+
Listens on a given \s-1ADDRESS. ADDRESS\s0 may be in the form of
|
170
|
+
\&\s-1HOST:PORT\s0 or \s-1PATH, HOST:PORT\s0 is taken to mean a \s-1TCP\s0 socket
|
162
171
|
and \s-1PATH\s0 is meant to be a path to a \s-1UNIX\s0 domain socket.
|
163
172
|
Defaults to \*(L"0.0.0.0:9292\*(R" (all addresses on \s-1TCP\s0 port 9292).
|
164
173
|
Multiple addresses may be separated with commas.
|
@@ -204,11 +213,11 @@ Unless specified via stderr_path and stdout_path, stderr and stdout will
|
|
204
213
|
also be redirected to \*(L"/dev/null\*(R".
|
205
214
|
.IP "\-E, \-\-env \s-1RACK_ENV\s0" 4
|
206
215
|
.IX Item "-E, --env RACK_ENV"
|
207
|
-
Run under the given \s-1RACK_ENV\s0
|
216
|
+
Run under the given \s-1RACK_ENV. \s0 See the \*(L"\s-1RACK ENVIRONMENT\*(R"\s0 section
|
208
217
|
for more details.
|
209
218
|
.IP "\-o, \-\-host \s-1HOST\s0" 4
|
210
219
|
.IX Item "-o, --host HOST"
|
211
|
-
Listen on a \s-1TCP\s0 socket belonging to \s-1HOST
|
220
|
+
Listen on a \s-1TCP\s0 socket belonging to \s-1HOST,\s0 default is
|
212
221
|
\&\*(L"0.0.0.0\*(R" (all addresses).
|
213
222
|
If specified multiple times on the command-line, only the
|
214
223
|
last-specified value takes effect.
|
@@ -216,7 +225,7 @@ This option only exists for compatibility with the \fIrackup\fR\|(1) command,
|
|
216
225
|
use of \*(L"\-l\*(R"/\*(L"\-\-listen\*(R" switch is recommended instead.
|
217
226
|
.IP "\-p, \-\-port \s-1PORT\s0" 4
|
218
227
|
.IX Item "-p, --port PORT"
|
219
|
-
Listen on the specified \s-1TCP
|
228
|
+
Listen on the specified \s-1TCP PORT,\s0 default is 9292.
|
220
229
|
If specified multiple times on the command-line, only the last-specified
|
221
230
|
value takes effect.
|
222
231
|
This option only exists for compatibility with the \fIrackup\fR\|(1) command,
|
@@ -256,24 +265,15 @@ See Rack documentation for a description of the rackup file format.
|
|
256
265
|
The \s-1RACK_ENV\s0 variable is set by the aforementioned \-E switch.
|
257
266
|
If \s-1RACK_ENV\s0 is already set, it will be used unless \-E is used.
|
258
267
|
See rackup documentation for more details.
|
259
|
-
.SH "CAVEATS"
|
260
|
-
.IX Header "CAVEATS"
|
261
|
-
yahns is strict about buggy, non-compliant Rack applications.
|
262
|
-
Some existing servers work fine without \*(L"Content-Length\*(R" or
|
263
|
-
\&\*(L"Transfer-Encoding: chunked\*(R" response headers enforced by Rack::Lint.
|
264
|
-
Forgetting these headers with yahns causes clients to stall as they
|
265
|
-
assume more data is coming. Loading the Rack::ContentLength and/or
|
266
|
-
Rack::Chunked middlewares will set the necessary response headers
|
267
|
-
and fix your app.
|
268
268
|
.SH "CONTACT"
|
269
269
|
.IX Header "CONTACT"
|
270
|
-
All feedback welcome via plain-text mail to mailto:yahns\-public@yhbt.net
|
270
|
+
All feedback welcome via plain-text mail to <mailto:yahns\-public@yhbt.net>
|
271
271
|
No subscription is necessary to post to the mailing list.
|
272
|
-
List archives are available at http://yhbt.net/yahns\-public
|
272
|
+
List archives are available at <http://yhbt.net/yahns\-public/>
|
273
273
|
.SH "COPYRIGHT"
|
274
274
|
.IX Header "COPYRIGHT"
|
275
|
-
Copyright (C) 2013\-2016 all contributors mailto:yahns\-public@yhbt.net
|
276
|
-
License: \s-1GPL\-3
|
275
|
+
Copyright (C) 2013\-2016 all contributors <mailto:yahns\-public@yhbt.net>
|
276
|
+
License: \s-1GPL\-3.0+ \s0<http://www.gnu.org/licenses/gpl\-3.0.txt>
|
277
277
|
.SH "SEE ALSO"
|
278
278
|
.IX Header "SEE ALSO"
|
279
279
|
\&\fIyahns\fR\|(1), \fIyahns_config\fR\|(5),
|