thin 1.6.3 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/CHANGELOG +22 -0
- data/README.md +34 -102
- data/example/async_chat.ru +0 -0
- data/example/async_tailer.ru +0 -0
- data/ext/thin_parser/parser.c +0 -5
- data/ext/thin_parser/parser.h +5 -5
- data/ext/thin_parser/parser.rl +0 -5
- data/ext/thin_parser/thin.c +1 -1
- data/lib/rack/handler/thin.rb +38 -0
- data/lib/thin/backends/base.rb +4 -2
- data/lib/thin/backends/tcp_server.rb +10 -5
- data/lib/thin/connection.rb +1 -1
- data/lib/thin/controllers/controller.rb +1 -1
- data/lib/thin/controllers/service.rb +1 -0
- data/lib/thin/daemonizing.rb +26 -7
- data/lib/thin/logging.rb +7 -2
- data/lib/thin/request.rb +6 -4
- data/lib/thin/runner.rb +4 -1
- data/lib/thin/server.rb +15 -15
- data/lib/thin/statuses.rb +8 -4
- data/lib/thin/version.rb +5 -5
- metadata +30 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 285d7efc73ff2e6e29a8789706c605cc2a2b5a1d25313a53d72954dd5a8adbe7
|
4
|
+
data.tar.gz: 24642b42692477ba60cb63cb0ffa49dcf63cc0634708a349d8fac94d08989b74
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ab7de3338f8d8694ed44a04cf785e78a0ce85de874d7bde4d96c6801b1e85190a3cbd33d8fe16a32aedc09eab9f1caad4a37ce51dc5997c32b5550da6d2fcffc
|
7
|
+
data.tar.gz: 19c45bc3a6f403daffe6a6c66b89bca01c597edb5b8c6ada110834c52fac0f639746f9b51ce5a3ca42c8f2fa013c929929b64b3737819ce83e5dff257e8a328a
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,25 @@
|
|
1
|
+
== 1.7.2 Bachmanity
|
2
|
+
* Add config support for ssl_version and ssl_cipher_list [frameworked]
|
3
|
+
|
4
|
+
== 1.7.1 Muffin Mode
|
5
|
+
* Ruby 2.4 support (Fixnum deprecation) [nimish-mehta]
|
6
|
+
* Allow ERB templates in config files [markets]
|
7
|
+
|
8
|
+
== 1.7.0 Dunder Mifflin
|
9
|
+
* Rack 2 support
|
10
|
+
* Ensure Response body.close is called in the same thread
|
11
|
+
Fixes issues with ActiveRecord connection management [#307]
|
12
|
+
* Fix TCP/IP Backend reports incorrect port when asked to bind to 0 [meschbach]
|
13
|
+
* Work with ruby 2.3's --enable-frozen-string-literal [jeremyevans]
|
14
|
+
|
15
|
+
== 1.6.4 Gob Bluth
|
16
|
+
* Increase REQUEST_PATH to 2048 symbols [X2rdas]
|
17
|
+
* Fix warning in logger [tenderlove]
|
18
|
+
* Add :timeout option for Rack::Server.new [sugitak]
|
19
|
+
* When restarting, exit on a next tick so we can send response back to a client [rsamoilov]
|
20
|
+
* Check for empty PID files [z1dane]
|
21
|
+
* Update Event Machine version to 1.0.4, Ruby 2.2.0 fix [freemanoid]
|
22
|
+
|
1
23
|
== 1.6.3 Protein Powder
|
2
24
|
* Add HTTP 422 status code [rajcybage]
|
3
25
|
* Add warning about EM reactor still running when stopping.
|
data/README.md
CHANGED
@@ -1,35 +1,17 @@
|
|
1
|
-
Thin
|
2
|
-
====
|
1
|
+
# Thin
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
Thin is a Ruby web server that glues together 3 of the best Ruby libraries in web history:
|
7
|
-
|
8
|
-
* The Mongrel parser: the root of Mongrel speed and security
|
9
|
-
* Event Machine: a network I/O library with extremely high scalability, performance and stability
|
10
|
-
* Rack: a minimal interface between webservers and Ruby frameworks
|
11
|
-
|
12
|
-
Which makes it, with all humility, the most secure, stable, fast and extensible Ruby web server
|
13
|
-
bundled in an easy to use gem for your own pleasure.
|
14
|
-
|
15
|
-
Site: http://code.macournoyer.com/thin/
|
16
|
-
Group: http://groups.google.com/group/thin-ruby/topics
|
17
|
-
Bugs: http://github.com/macournoyer/thin/issues
|
18
|
-
Code: http://github.com/macournoyer/thin
|
19
|
-
IRC: #thin on freenode
|
3
|
+
A small and fast Ruby web server
|
20
4
|
|
21
5
|
## Installation
|
22
6
|
|
23
|
-
|
24
|
-
|
25
|
-
|
7
|
+
```
|
8
|
+
gem install thin
|
9
|
+
```
|
26
10
|
|
27
|
-
Or
|
11
|
+
Or add `thin` to your `Gemfile`:
|
28
12
|
|
29
|
-
```
|
30
|
-
|
31
|
-
cd thin
|
32
|
-
rake install
|
13
|
+
```ruby
|
14
|
+
gem 'thin'
|
33
15
|
```
|
34
16
|
|
35
17
|
## Usage
|
@@ -37,18 +19,30 @@ rake install
|
|
37
19
|
A +thin+ script offers an easy way to start your Rack application:
|
38
20
|
|
39
21
|
```
|
40
|
-
cd to/your/app
|
41
22
|
thin start
|
42
23
|
```
|
43
24
|
|
44
|
-
|
45
|
-
|
25
|
+
Browse the `example` directory for sample applications.
|
26
|
+
|
27
|
+
## Usage with Rails Action Cable
|
28
|
+
|
29
|
+
To use Thin with Action Cable, add the following to your `Gemfile`:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
gem 'faye-websocket'
|
33
|
+
gem 'thin' # If not already done
|
34
|
+
```
|
35
|
+
|
36
|
+
Create a `config/initializers/thin_action_cable.rb`:
|
46
37
|
|
47
|
-
|
38
|
+
```ruby
|
39
|
+
Rails.application.config.action_cable.use_faye = true
|
40
|
+
Faye::WebSocket.load_adapter 'thin'
|
41
|
+
```
|
48
42
|
|
49
|
-
###
|
43
|
+
### CLI
|
50
44
|
|
51
|
-
Use a rackup file and bind to localhost port 8080:
|
45
|
+
Use a rackup (config.ru) file and bind to localhost port 8080:
|
52
46
|
|
53
47
|
```
|
54
48
|
thin -R config.ru -a 127.0.0.1 -p 8080 start
|
@@ -60,11 +54,15 @@ Store the server process ID, log to a file and daemonize:
|
|
60
54
|
thin -p 9292 -P tmp/pids/thin.pid -l logs/thin.log -d start
|
61
55
|
```
|
62
56
|
|
63
|
-
Thin is quite flexible in that many options can be specified at the command line (see
|
57
|
+
Thin is quite flexible in that many options can be specified at the command line (see `thin -h` for more).
|
64
58
|
|
65
59
|
### Configuration files
|
66
60
|
|
67
|
-
You can create configuration
|
61
|
+
You can create a configuration file using `thin config -C config/thin.yml`.
|
62
|
+
|
63
|
+
You can then use it with all commands, such as: `thin start -C config/thin.yml`.
|
64
|
+
|
65
|
+
Here is an example config file:
|
68
66
|
|
69
67
|
```yaml
|
70
68
|
---
|
@@ -87,79 +85,13 @@ chdir: /path/to/your/apps/root
|
|
87
85
|
tag: a-name-to-show-up-in-ps aux
|
88
86
|
```
|
89
87
|
|
90
|
-
### Command Line Options
|
91
|
-
|
92
|
-
This is the usage for the thin command which can be obtained by running `thin -h` at the command line.
|
93
|
-
|
94
|
-
```sh
|
95
|
-
Usage: thin [options] start|stop|restart|config|install
|
96
|
-
|
97
|
-
Server options:
|
98
|
-
-a, --address HOST bind to HOST address (default: 0.0.0.0)
|
99
|
-
-p, --port PORT use PORT (default: 3000)
|
100
|
-
-S, --socket FILE bind to unix domain socket
|
101
|
-
-y, --swiftiply [KEY] Run using swiftiply
|
102
|
-
-A, --adapter NAME Rack adapter to use (default: autodetect)
|
103
|
-
(rack, rails, ramaze, merb, file)
|
104
|
-
-R, --rackup FILE Load a Rack config file instead of Rack adapter
|
105
|
-
-c, --chdir DIR Change to dir before starting
|
106
|
-
--stats PATH Mount the Stats adapter under PATH
|
107
|
-
|
108
|
-
SSL options:
|
109
|
-
--ssl Enables SSL
|
110
|
-
--ssl-key-file PATH Path to private key
|
111
|
-
--ssl-cert-file PATH Path to certificate
|
112
|
-
--ssl-disable-verify Disables (optional) client cert requests
|
113
|
-
|
114
|
-
Adapter options:
|
115
|
-
-e, --environment ENV Framework environment (default: development)
|
116
|
-
--prefix PATH Mount the app under PATH (start with /)
|
117
|
-
|
118
|
-
Daemon options:
|
119
|
-
-d, --daemonize Run daemonized in the background
|
120
|
-
-l, --log FILE File to redirect output (default: /home/robert/log/thin.log)
|
121
|
-
-P, --pid FILE File to store PID (default: tmp/pids/thin.pid)
|
122
|
-
-u, --user NAME User to run daemon as (use with -g)
|
123
|
-
-g, --group NAME Group to run daemon as (use with -u)
|
124
|
-
--tag NAME Additional text to display in process listing
|
125
|
-
|
126
|
-
Cluster options:
|
127
|
-
-s, --servers NUM Number of servers to start
|
128
|
-
-o, --only NUM Send command to only one server of the cluster
|
129
|
-
-C, --config FILE Load options from config file
|
130
|
-
--all [DIR] Send command to each config files in DIR
|
131
|
-
-O, --onebyone Restart the cluster one by one (only works with restart command)
|
132
|
-
-w, --wait NUM Maximum wait time for server to be started in seconds (use with -O)
|
133
|
-
|
134
|
-
Tuning options:
|
135
|
-
-b, --backend CLASS Backend to use, full classname
|
136
|
-
-t, --timeout SEC Request or command timeout in sec (default: 30)
|
137
|
-
-f, --force Force the execution of the command
|
138
|
-
--max-conns NUM Maximum number of open file descriptors (default: 1024)
|
139
|
-
Might require sudo to set higher than 1024
|
140
|
-
--max-persistent-conns NUM Maximum number of persistent connections
|
141
|
-
(default: 100)
|
142
|
-
--threaded Call the Rack application in threads [experimental]
|
143
|
-
--threadpool-size NUM Sets the size of the EventMachine threadpool.
|
144
|
-
(default: 20)
|
145
|
-
--no-epoll Disable the use of epoll
|
146
|
-
|
147
|
-
Common options:
|
148
|
-
-r, --require FILE require the library
|
149
|
-
-q, --quiet Silence all logging
|
150
|
-
-D, --debug Enable debug logging
|
151
|
-
-V, --trace Set tracing on (log raw request/response)
|
152
|
-
-h, --help Show this message
|
153
|
-
-v, --version Show version
|
154
|
-
```
|
155
|
-
|
156
88
|
## License
|
157
89
|
|
158
90
|
Ruby License, http://www.ruby-lang.org/en/LICENSE.txt.
|
159
91
|
|
160
92
|
## Credits
|
161
93
|
|
162
|
-
The parser was
|
94
|
+
The parser was originally from Mongrel http://mongrel.rubyforge.org by Zed Shaw.
|
163
95
|
Mongrel is copyright 2007 Zed A. Shaw and contributors. It is licensed under
|
164
96
|
the Ruby license and the GPL2.
|
165
97
|
|
@@ -167,4 +99,4 @@ Thin is copyright Marc-Andre Cournoyer <macournoyer@gmail.com>
|
|
167
99
|
|
168
100
|
Get help at http://groups.google.com/group/thin-ruby/
|
169
101
|
Report bugs at https://github.com/macournoyer/thin/issues
|
170
|
-
and major security issues directly to me macournoyer@gmail.com.
|
102
|
+
and major security issues directly to me at macournoyer@gmail.com.
|
data/example/async_chat.ru
CHANGED
File without changes
|
data/example/async_tailer.ru
CHANGED
File without changes
|
data/ext/thin_parser/parser.c
CHANGED
@@ -1437,11 +1437,6 @@ int thin_http_parser_is_finished(http_parser *parser) {
|
|
1437
1437
|
|
1438
1438
|
int thin_http_parser_finish(http_parser *parser)
|
1439
1439
|
{
|
1440
|
-
int cs = parser->cs;
|
1441
|
-
|
1442
|
-
|
1443
|
-
parser->cs = cs;
|
1444
|
-
|
1445
1440
|
if (thin_http_parser_has_error(parser) ) {
|
1446
1441
|
return -1;
|
1447
1442
|
} else if (thin_http_parser_is_finished(parser) ) {
|
data/ext/thin_parser/parser.h
CHANGED
@@ -38,11 +38,11 @@ typedef struct http_parser {
|
|
38
38
|
|
39
39
|
} http_parser;
|
40
40
|
|
41
|
-
int
|
42
|
-
int
|
43
|
-
size_t
|
44
|
-
int
|
45
|
-
int
|
41
|
+
int thin_http_parser_init(http_parser *parser);
|
42
|
+
int thin_http_parser_finish(http_parser *parser);
|
43
|
+
size_t thin_http_parser_execute(http_parser *parser, const char *data, size_t len, size_t off);
|
44
|
+
int thin_http_parser_has_error(http_parser *parser);
|
45
|
+
int thin_http_parser_is_finished(http_parser *parser);
|
46
46
|
|
47
47
|
#define http_parser_nread(parser) (parser)->nread
|
48
48
|
|
data/ext/thin_parser/parser.rl
CHANGED
@@ -142,11 +142,6 @@ int thin_http_parser_is_finished(http_parser *parser) {
|
|
142
142
|
|
143
143
|
int thin_http_parser_finish(http_parser *parser)
|
144
144
|
{
|
145
|
-
int cs = parser->cs;
|
146
|
-
|
147
|
-
|
148
|
-
parser->cs = cs;
|
149
|
-
|
150
145
|
if (thin_http_parser_has_error(parser) ) {
|
151
146
|
return -1;
|
152
147
|
} else if (thin_http_parser_is_finished(parser) ) {
|
data/ext/thin_parser/thin.c
CHANGED
@@ -67,7 +67,7 @@ DEF_MAX_LENGTH(FIELD_NAME, 256);
|
|
67
67
|
DEF_MAX_LENGTH(FIELD_VALUE, 80 * 1024);
|
68
68
|
DEF_MAX_LENGTH(REQUEST_URI, 1024 * 12);
|
69
69
|
DEF_MAX_LENGTH(FRAGMENT, 1024); /* Don't know if this length is specified somewhere or not */
|
70
|
-
DEF_MAX_LENGTH(REQUEST_PATH,
|
70
|
+
DEF_MAX_LENGTH(REQUEST_PATH, 2048);
|
71
71
|
DEF_MAX_LENGTH(QUERY_STRING, (1024 * 10));
|
72
72
|
DEF_MAX_LENGTH(HEADER, (1024 * (80 + 32)));
|
73
73
|
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "thin"
|
4
|
+
require "thin/server"
|
5
|
+
require "thin/logging"
|
6
|
+
require "thin/backends/tcp_server"
|
7
|
+
|
8
|
+
module Rack
|
9
|
+
module Handler
|
10
|
+
class Thin
|
11
|
+
def self.run(app, **options)
|
12
|
+
environment = ENV['RACK_ENV'] || 'development'
|
13
|
+
default_host = environment == 'development' ? 'localhost' : '0.0.0.0'
|
14
|
+
|
15
|
+
host = options.delete(:Host) || default_host
|
16
|
+
port = options.delete(:Port) || 8080
|
17
|
+
args = [host, port, app, options]
|
18
|
+
|
19
|
+
server = ::Thin::Server.new(*args)
|
20
|
+
yield server if block_given?
|
21
|
+
|
22
|
+
server.start
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.valid_options
|
26
|
+
environment = ENV['RACK_ENV'] || 'development'
|
27
|
+
default_host = environment == 'development' ? 'localhost' : '0.0.0.0'
|
28
|
+
|
29
|
+
{
|
30
|
+
"Host=HOST" => "Hostname to listen on (default: #{default_host})",
|
31
|
+
"Port=PORT" => "Port to listen on (default: 8080)",
|
32
|
+
}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
register :thin, ::Rack::Handler::Thin
|
37
|
+
end
|
38
|
+
end
|
data/lib/thin/backends/base.rb
CHANGED
@@ -3,7 +3,7 @@ module Thin
|
|
3
3
|
# A Backend connects the server to the client. It handles:
|
4
4
|
# * connection/disconnection to the server
|
5
5
|
# * initialization of the connections
|
6
|
-
# *
|
6
|
+
# * monitoring of the active connections.
|
7
7
|
#
|
8
8
|
# == Implementing your own backend
|
9
9
|
# You can create your own minimal backend by inheriting this class and
|
@@ -51,9 +51,11 @@ module Thin
|
|
51
51
|
@maximum_connections = Server::DEFAULT_MAXIMUM_CONNECTIONS
|
52
52
|
@maximum_persistent_connections = Server::DEFAULT_MAXIMUM_PERSISTENT_CONNECTIONS
|
53
53
|
@no_epoll = false
|
54
|
+
@running = false
|
54
55
|
@ssl = nil
|
55
|
-
@threaded = nil
|
56
56
|
@started_reactor = false
|
57
|
+
@stopping = false
|
58
|
+
@threaded = nil
|
57
59
|
end
|
58
60
|
|
59
61
|
# Start the backend and connect it.
|
@@ -4,26 +4,31 @@ module Thin
|
|
4
4
|
class TcpServer < Base
|
5
5
|
# Address and port on which the server is listening for connections.
|
6
6
|
attr_accessor :host, :port
|
7
|
-
|
7
|
+
|
8
8
|
def initialize(host, port)
|
9
9
|
@host = host
|
10
10
|
@port = port
|
11
11
|
super()
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
# Connect the server
|
15
15
|
def connect
|
16
16
|
@signature = EventMachine.start_server(@host, @port, Connection, &method(:initialize_connection))
|
17
|
+
binary_name = EventMachine.get_sockname( @signature )
|
18
|
+
port_name = Socket.unpack_sockaddr_in( binary_name )
|
19
|
+
@port = port_name[0]
|
20
|
+
@host = port_name[1]
|
21
|
+
@signature
|
17
22
|
end
|
18
|
-
|
23
|
+
|
19
24
|
# Stops the server
|
20
25
|
def disconnect
|
21
26
|
EventMachine.stop_server(@signature)
|
22
27
|
end
|
23
|
-
|
28
|
+
|
24
29
|
def to_s
|
25
30
|
"#{@host}:#{@port}"
|
26
31
|
end
|
27
32
|
end
|
28
33
|
end
|
29
|
-
end
|
34
|
+
end
|
data/lib/thin/connection.rb
CHANGED
@@ -55,7 +55,7 @@ module Thin
|
|
55
55
|
# ssl support
|
56
56
|
if @options[:ssl]
|
57
57
|
server.ssl = true
|
58
|
-
server.ssl_options = { :private_key_file => @options[:ssl_key_file], :cert_chain_file => @options[:ssl_cert_file], :verify_peer => !@options[:ssl_disable_verify] }
|
58
|
+
server.ssl_options = { :private_key_file => @options[:ssl_key_file], :cert_chain_file => @options[:ssl_cert_file], :verify_peer => !@options[:ssl_disable_verify], :ssl_version => @options[:ssl_version], :cipher_list => @options[:ssl_cipher_list]}
|
59
59
|
end
|
60
60
|
|
61
61
|
# Detach the process, after this line the current process returns
|
data/lib/thin/daemonizing.rb
CHANGED
@@ -30,11 +30,17 @@ module Thin
|
|
30
30
|
def self.included(base)
|
31
31
|
base.extend ClassMethods
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
def pid
|
35
|
-
File.exist?(pid_file) ? open(pid_file).read.to_i : nil
|
35
|
+
File.exist?(pid_file) && !File.zero?(pid_file) ? open(pid_file).read.to_i : nil
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
|
+
def kill(timeout = 60)
|
39
|
+
if File.exist?(@pid_file)
|
40
|
+
self.class.kill(@pid_file, timeout)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
38
44
|
# Turns the current script into a daemon process that detaches from the console.
|
39
45
|
def daemonize
|
40
46
|
raise PlatformNotSupported, 'Daemonizing is not supported on Windows' if Thin.win?
|
@@ -78,6 +84,10 @@ module Thin
|
|
78
84
|
Process.initgroups(user, target_gid)
|
79
85
|
Process::GID.change_privilege(target_gid)
|
80
86
|
Process::UID.change_privilege(target_uid)
|
87
|
+
|
88
|
+
# Correct environment variables
|
89
|
+
ENV.store('USER', user)
|
90
|
+
ENV.store('HOME', File.expand_path("~#{user}"))
|
81
91
|
end
|
82
92
|
rescue Errno::EPERM => e
|
83
93
|
log_info "Couldn't change user and group to #{user}:#{group}: #{e}"
|
@@ -95,7 +105,7 @@ module Thin
|
|
95
105
|
stop
|
96
106
|
remove_pid_file
|
97
107
|
@on_restart.call
|
98
|
-
exit!
|
108
|
+
EM.next_tick { exit! }
|
99
109
|
end
|
100
110
|
end
|
101
111
|
|
@@ -116,14 +126,23 @@ module Thin
|
|
116
126
|
def restart(pid_file)
|
117
127
|
send_signal('HUP', pid_file)
|
118
128
|
end
|
119
|
-
|
129
|
+
|
130
|
+
def monotonic_time
|
131
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
132
|
+
end
|
133
|
+
|
120
134
|
# Send a +signal+ to the process which PID is stored in +pid_file+.
|
121
135
|
def send_signal(signal, pid_file, timeout=60)
|
122
136
|
if pid = read_pid_file(pid_file)
|
123
137
|
Logging.log_info "Sending #{signal} signal to process #{pid} ... "
|
138
|
+
|
124
139
|
Process.kill(signal, pid)
|
125
|
-
|
126
|
-
|
140
|
+
|
141
|
+
# This loop seems kind of racy to me...
|
142
|
+
started_at = monotonic_time
|
143
|
+
while Process.running?(pid)
|
144
|
+
sleep 0.1
|
145
|
+
raise Timeout::Error if (monotonic_time - started_at) > timeout
|
127
146
|
end
|
128
147
|
else
|
129
148
|
raise PidFileNotFound, "Can't stop process, no PID found in #{pid_file}"
|
data/lib/thin/logging.rb
CHANGED
@@ -13,10 +13,12 @@ module Thin
|
|
13
13
|
# Taken from ActiveSupport
|
14
14
|
class SimpleFormatter < Logger::Formatter
|
15
15
|
def call(severity, timestamp, progname, msg)
|
16
|
-
"#{String === msg ? msg : msg.inspect}\n"
|
16
|
+
"#{timestamp} #{String === msg ? msg : msg.inspect}\n"
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
+
@trace_logger = nil
|
21
|
+
|
20
22
|
class << self
|
21
23
|
attr_reader :logger
|
22
24
|
attr_reader :trace_logger
|
@@ -152,7 +154,10 @@ module Thin
|
|
152
154
|
|
153
155
|
# Log a message at ERROR level (and maybe a backtrace)
|
154
156
|
def log_error(msg, e=nil)
|
155
|
-
log_msg = msg
|
157
|
+
log_msg = msg
|
158
|
+
if e
|
159
|
+
log_msg += ": #{e}\n\t" + e.backtrace.join("\n\t") + "\n"
|
160
|
+
end
|
156
161
|
Logging.log_msg(log_msg, Logger::ERROR)
|
157
162
|
end
|
158
163
|
module_function :log_error
|
data/lib/thin/request.rb
CHANGED
@@ -13,9 +13,9 @@ module Thin
|
|
13
13
|
BODY_TMPFILE = 'thin-body'.freeze
|
14
14
|
MAX_HEADER = 1024 * (80 + 32)
|
15
15
|
|
16
|
-
INITIAL_BODY =
|
16
|
+
INITIAL_BODY = String.new
|
17
17
|
# Force external_encoding of request's body to ASCII_8BIT
|
18
|
-
INITIAL_BODY.encode!(Encoding::ASCII_8BIT) if INITIAL_BODY.respond_to?(:encode!)
|
18
|
+
INITIAL_BODY.encode!(Encoding::ASCII_8BIT) if INITIAL_BODY.respond_to?(:encode!) && defined?(Encoding::ASCII_8BIT)
|
19
19
|
|
20
20
|
# Freeze some HTTP header names & values
|
21
21
|
SERVER_SOFTWARE = 'SERVER_SOFTWARE'.freeze
|
@@ -52,7 +52,7 @@ module Thin
|
|
52
52
|
|
53
53
|
def initialize
|
54
54
|
@parser = Thin::HttpParser.new
|
55
|
-
@data =
|
55
|
+
@data = String.new
|
56
56
|
@nparsed = 0
|
57
57
|
@body = StringIO.new(INITIAL_BODY.dup)
|
58
58
|
@env = {
|
@@ -75,7 +75,9 @@ module Thin
|
|
75
75
|
# Raises an +InvalidRequest+ if invalid.
|
76
76
|
# Returns +true+ if the parsing is complete.
|
77
77
|
def parse(data)
|
78
|
-
if
|
78
|
+
if data.size > 0 && finished? # headers and body already fully satisfied. more data is erroneous.
|
79
|
+
raise InvalidRequest, 'Content longer than specified'
|
80
|
+
elsif @parser.finished? # Header finished, can only be some more body
|
79
81
|
@body << data
|
80
82
|
else # Parse more header using the super parser
|
81
83
|
@data << data
|
data/lib/thin/runner.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'logger'
|
2
2
|
require 'optparse'
|
3
3
|
require 'yaml'
|
4
|
+
require 'erb'
|
4
5
|
|
5
6
|
module Thin
|
6
7
|
# CLI runner.
|
@@ -80,6 +81,8 @@ module Thin
|
|
80
81
|
opts.on( "--ssl-key-file PATH", "Path to private key") { |path| @options[:ssl_key_file] = path }
|
81
82
|
opts.on( "--ssl-cert-file PATH", "Path to certificate") { |path| @options[:ssl_cert_file] = path }
|
82
83
|
opts.on( "--ssl-disable-verify", "Disables (optional) client cert requests") { @options[:ssl_disable_verify] = true }
|
84
|
+
opts.on( "--ssl-version VERSION", "TLSv1, TLSv1_1, TLSv1_2") { |version| @options[:ssl_version] = version }
|
85
|
+
opts.on( "--ssl-cipher-list STRING", "Example: HIGH:!ADH:!RC4:-MEDIUM:-LOW:-EXP:-CAMELLIA") { |cipher| @options[:ssl_cipher_list] = cipher }
|
83
86
|
|
84
87
|
opts.separator ""
|
85
88
|
opts.separator "Adapter options:"
|
@@ -219,7 +222,7 @@ module Thin
|
|
219
222
|
private
|
220
223
|
def load_options_from_config_file!
|
221
224
|
if file = @options.delete(:config)
|
222
|
-
YAML.
|
225
|
+
YAML.load(ERB.new(File.read(file)).result).each { |key, value| @options[key.to_sym] = value }
|
223
226
|
end
|
224
227
|
end
|
225
228
|
|
data/lib/thin/server.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
module Thin
|
2
|
-
# The
|
3
|
-
# It
|
4
|
-
# and
|
2
|
+
# The utterly famous Thin HTTP server.
|
3
|
+
# It listens for incoming requests through a given +backend+
|
4
|
+
# and forwards all requests to +app+.
|
5
5
|
#
|
6
6
|
# == TCP server
|
7
|
-
# Create a new TCP server
|
7
|
+
# Create a new TCP server bound to <tt>host:port</tt> by specifiying +host+
|
8
8
|
# and +port+ as the first 2 arguments.
|
9
9
|
#
|
10
10
|
# Thin::Server.start('0.0.0.0', 3000, app)
|
@@ -18,12 +18,12 @@ module Thin
|
|
18
18
|
#
|
19
19
|
# == Using a custom backend
|
20
20
|
# You can implement your own way to connect the server to its client by creating your
|
21
|
-
# own Backend class and
|
21
|
+
# own Backend class and passing it as the :backend option.
|
22
22
|
#
|
23
23
|
# Thin::Server.start('galaxy://faraway', 1345, app, :backend => Thin::Backends::MyFancyBackend)
|
24
24
|
#
|
25
25
|
# == Rack application (+app+)
|
26
|
-
# All requests will be processed through +app
|
26
|
+
# All requests will be processed through +app+, which must be a valid Rack adapter.
|
27
27
|
# A valid Rack adapter (application) must respond to <tt>call(env#Hash)</tt> and
|
28
28
|
# return an array of <tt>[status, headers, body]</tt>.
|
29
29
|
#
|
@@ -76,10 +76,10 @@ module Thin
|
|
76
76
|
# Maximum number of file or socket descriptors that the server may open.
|
77
77
|
def_delegators :backend, :maximum_connections, :maximum_connections=
|
78
78
|
|
79
|
-
# Maximum number of
|
80
|
-
# Most
|
81
|
-
# when the timeout
|
82
|
-
#
|
79
|
+
# Maximum number of connections that can be persistent at the same time.
|
80
|
+
# Most browsers never close the connection so most of the time they are closed
|
81
|
+
# when the timeout occurs. If we don't control the number of persistent connections,
|
82
|
+
# it would be very easy to overflow the server for a DoS attack.
|
83
83
|
def_delegators :backend, :maximum_persistent_connections, :maximum_persistent_connections=
|
84
84
|
|
85
85
|
# Allow using threads in the backend.
|
@@ -104,9 +104,9 @@ module Thin
|
|
104
104
|
# received in any order.
|
105
105
|
args.each do |arg|
|
106
106
|
case arg
|
107
|
-
when
|
108
|
-
when String
|
109
|
-
when Hash
|
107
|
+
when 0.class, /^\d+$/ then port = arg.to_i
|
108
|
+
when String then host = arg
|
109
|
+
when Hash then options = arg
|
110
110
|
else
|
111
111
|
@app = arg if arg.respond_to?(:call)
|
112
112
|
end
|
@@ -125,7 +125,7 @@ module Thin
|
|
125
125
|
# Set defaults
|
126
126
|
@backend.maximum_connections = DEFAULT_MAXIMUM_CONNECTIONS
|
127
127
|
@backend.maximum_persistent_connections = DEFAULT_MAXIMUM_PERSISTENT_CONNECTIONS
|
128
|
-
@backend.timeout = DEFAULT_TIMEOUT
|
128
|
+
@backend.timeout = options[:timeout] || DEFAULT_TIMEOUT
|
129
129
|
|
130
130
|
# Allow using Rack builder as a block
|
131
131
|
@app = Rack::Builder.new(&block).to_app if block
|
@@ -166,7 +166,7 @@ module Thin
|
|
166
166
|
# == Gracefull shutdown
|
167
167
|
# Stops the server after processing all current connections.
|
168
168
|
# As soon as this method is called, the server stops accepting
|
169
|
-
# new requests and
|
169
|
+
# new requests and waits for all current connections to finish.
|
170
170
|
# Calling twice is the equivalent of calling <tt>stop!</tt>.
|
171
171
|
def stop
|
172
172
|
if running?
|
data/lib/thin/statuses.rb
CHANGED
@@ -33,12 +33,16 @@ module Thin
|
|
33
33
|
413 => 'Request Entity Too Large',
|
34
34
|
414 => 'Request-URI Too Large',
|
35
35
|
415 => 'Unsupported Media Type',
|
36
|
-
422 => 'Unprocessable Entity',
|
37
|
-
|
36
|
+
422 => 'Unprocessable Entity',
|
37
|
+
428 => 'Precondition Required',
|
38
|
+
429 => 'Too Many Requests',
|
39
|
+
431 => 'Request Header Fields Too Large',
|
40
|
+
500 => 'Internal Server Error',
|
38
41
|
501 => 'Not Implemented',
|
39
42
|
502 => 'Bad Gateway',
|
40
43
|
503 => 'Service Unavailable',
|
41
44
|
504 => 'Gateway Time-out',
|
42
|
-
505 => 'HTTP Version not supported'
|
45
|
+
505 => 'HTTP Version not supported',
|
46
|
+
511 => 'Network Authentication Required'
|
43
47
|
}
|
44
|
-
end
|
48
|
+
end
|
data/lib/thin/version.rb
CHANGED
@@ -1,22 +1,22 @@
|
|
1
|
-
module Thin
|
1
|
+
module Thin
|
2
2
|
# Raised when a feature is not supported on the
|
3
3
|
# current platform.
|
4
4
|
class PlatformNotSupported < RuntimeError; end
|
5
5
|
|
6
6
|
module VERSION #:nodoc:
|
7
7
|
MAJOR = 1
|
8
|
-
MINOR =
|
9
|
-
TINY =
|
8
|
+
MINOR = 8
|
9
|
+
TINY = 0
|
10
10
|
|
11
11
|
STRING = [MAJOR, MINOR, TINY].join('.')
|
12
12
|
|
13
|
-
CODENAME = "
|
13
|
+
CODENAME = "Possessed Pickle".freeze
|
14
14
|
|
15
15
|
RACK = [1, 0].freeze # Rack protocol version
|
16
16
|
end
|
17
17
|
|
18
18
|
NAME = 'thin'.freeze
|
19
|
-
SERVER = "#{NAME} #{VERSION::STRING} codename #{VERSION::CODENAME}".freeze
|
19
|
+
SERVER = "#{NAME} #{VERSION::STRING} codename #{VERSION::CODENAME}".freeze
|
20
20
|
|
21
21
|
def self.win?
|
22
22
|
RUBY_PLATFORM =~ /mswin|mingw/
|
metadata
CHANGED
@@ -1,29 +1,35 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marc-Andre Cournoyer
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-11-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '1
|
19
|
+
version: '1'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '3'
|
20
23
|
type: :runtime
|
21
24
|
prerelease: false
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
23
26
|
requirements:
|
24
|
-
- - "
|
27
|
+
- - ">="
|
25
28
|
- !ruby/object:Gem::Version
|
26
|
-
version: '1
|
29
|
+
version: '1'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '3'
|
27
33
|
- !ruby/object:Gem::Dependency
|
28
34
|
name: eventmachine
|
29
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -31,6 +37,9 @@ dependencies:
|
|
31
37
|
- - "~>"
|
32
38
|
- !ruby/object:Gem::Version
|
33
39
|
version: '1.0'
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 1.0.4
|
34
43
|
type: :runtime
|
35
44
|
prerelease: false
|
36
45
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -38,6 +47,9 @@ dependencies:
|
|
38
47
|
- - "~>"
|
39
48
|
- !ruby/object:Gem::Version
|
40
49
|
version: '1.0'
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 1.0.4
|
41
53
|
- !ruby/object:Gem::Dependency
|
42
54
|
name: daemons
|
43
55
|
requirement: !ruby/object:Gem::Requirement
|
@@ -58,7 +70,7 @@ dependencies:
|
|
58
70
|
- - ">="
|
59
71
|
- !ruby/object:Gem::Version
|
60
72
|
version: 1.0.9
|
61
|
-
description:
|
73
|
+
description:
|
62
74
|
email: macournoyer@gmail.com
|
63
75
|
executables:
|
64
76
|
- thin
|
@@ -92,6 +104,7 @@ files:
|
|
92
104
|
- ext/thin_parser/thin.c
|
93
105
|
- lib/rack/adapter/loader.rb
|
94
106
|
- lib/rack/adapter/rails.rb
|
107
|
+
- lib/rack/handler/thin.rb
|
95
108
|
- lib/thin.rb
|
96
109
|
- lib/thin/backends/base.rb
|
97
110
|
- lib/thin/backends/swiftiply_client.rb
|
@@ -114,12 +127,14 @@ files:
|
|
114
127
|
- lib/thin/stats.rb
|
115
128
|
- lib/thin/statuses.rb
|
116
129
|
- lib/thin/version.rb
|
117
|
-
homepage:
|
130
|
+
homepage: https://github.com/macournoyer/thin
|
118
131
|
licenses:
|
119
|
-
-
|
120
|
-
- Ruby
|
121
|
-
metadata:
|
122
|
-
|
132
|
+
- GPL-2.0+
|
133
|
+
- Ruby
|
134
|
+
metadata:
|
135
|
+
source_code_uri: https://github.com/macournoyer/thin
|
136
|
+
changelog_uri: https://github.com/macournoyer/thin/blob/master/CHANGELOG
|
137
|
+
post_install_message:
|
123
138
|
rdoc_options: []
|
124
139
|
require_paths:
|
125
140
|
- lib
|
@@ -134,9 +149,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
134
149
|
- !ruby/object:Gem::Version
|
135
150
|
version: '0'
|
136
151
|
requirements: []
|
137
|
-
|
138
|
-
|
139
|
-
signing_key:
|
152
|
+
rubygems_version: 3.1.2
|
153
|
+
signing_key:
|
140
154
|
specification_version: 4
|
141
155
|
summary: A thin and fast web server
|
142
156
|
test_files: []
|