thin 1.8.1 → 2.0.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 +4 -4
- data/CHANGELOG +6 -0
- data/README.md +0 -16
- data/Rakefile +1 -4
- data/example/adapter.rb +3 -3
- data/example/async_app.ru +1 -1
- data/example/async_chat.ru +2 -2
- data/example/async_tailer.ru +1 -1
- data/example/config.ru +1 -1
- data/ext/thin_parser/common.rl +1 -1
- data/ext/thin_parser/parser.c +2 -2
- data/ext/thin_parser/parser.h +1 -1
- data/ext/thin_parser/parser.rl +3 -3
- data/ext/thin_parser/thin.c +6 -6
- data/lib/rack/adapter/loader.rb +8 -1
- data/lib/rack/adapter/rails.rb +2 -8
- data/lib/rack/handler/thin.rb +4 -29
- data/lib/rackup/handler/thin.rb +13 -0
- data/lib/thin/backends/swiftiply_client.rb +11 -1
- data/lib/thin/connection.rb +4 -0
- data/lib/thin/daemonizing.rb +2 -2
- data/lib/thin/env.rb +35 -0
- data/lib/thin/rackup/handler.rb +31 -0
- data/lib/thin/request.rb +5 -10
- data/lib/thin/response.rb +66 -39
- data/lib/thin/server.rb +1 -1
- data/lib/thin/stats.rb +1 -1
- data/lib/thin/version.rb +3 -16
- metadata +23 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6dcf6eaa16df95d8f4d44a6643a70b83dee8c02e04329d8ba545401893cea29c
|
4
|
+
data.tar.gz: 6bd95facde96eb0d1e773ac19921198c41420380f0842f10e78cf638159e05e5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c0c25ff5dceaafb07385cd6b145efe34dbd2998bfeade8332cc2f52b3e066a690542f2d915b9cad2c56f30d8ead216278605e30de7aef11ffec6a59488925d3
|
7
|
+
data.tar.gz: 35ef7752930404686039ee18d896418f963b53bc8a1908d30c54c4222722f92fbb70cfc5865933b6237316c0dcd94913b6bf9e799c5208ccb095659a42fdcc80
|
data/CHANGELOG
CHANGED
data/README.md
CHANGED
@@ -24,22 +24,6 @@ thin start
|
|
24
24
|
|
25
25
|
Browse the `example` directory for sample applications.
|
26
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`:
|
37
|
-
|
38
|
-
```ruby
|
39
|
-
Rails.application.config.action_cable.use_faye = true
|
40
|
-
Faye::WebSocket.load_adapter 'thin'
|
41
|
-
```
|
42
|
-
|
43
27
|
### CLI
|
44
28
|
|
45
29
|
Use a rackup (config.ru) file and bind to localhost port 8080:
|
data/Rakefile
CHANGED
@@ -2,9 +2,6 @@ require 'rake'
|
|
2
2
|
require 'rake/clean'
|
3
3
|
load 'thin.gemspec'
|
4
4
|
|
5
|
-
# Load tasks in tasks/
|
6
|
-
Dir['tasks/**/*.rake'].each { |rake| load rake }
|
7
|
-
|
8
5
|
task :default => :spec
|
9
6
|
|
10
7
|
desc "Build gem packages"
|
@@ -21,5 +18,5 @@ task :install => :build do
|
|
21
18
|
sh "gem install thin-*.gem"
|
22
19
|
end
|
23
20
|
|
24
|
-
desc "Release version #{Thin::VERSION
|
21
|
+
desc "Release version #{Thin::VERSION}"
|
25
22
|
task :release => [:tag, :push]
|
data/example/adapter.rb
CHANGED
@@ -8,7 +8,7 @@ class SimpleAdapter
|
|
8
8
|
body = ["hello!"]
|
9
9
|
[
|
10
10
|
200,
|
11
|
-
{ '
|
11
|
+
{ 'content-type' => 'text/plain' },
|
12
12
|
body
|
13
13
|
]
|
14
14
|
end
|
@@ -20,13 +20,13 @@ Thin::Server.start('0.0.0.0', 3000) do
|
|
20
20
|
run SimpleAdapter.new
|
21
21
|
end
|
22
22
|
map '/files' do
|
23
|
-
run Rack::
|
23
|
+
run Rack::Files.new('.')
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
27
|
# You could also start the server like this:
|
28
28
|
#
|
29
29
|
# app = Rack::URLMap.new('/test' => SimpleAdapter.new,
|
30
|
-
# '/files' => Rack::
|
30
|
+
# '/files' => Rack::Files.new('.'))
|
31
31
|
# Thin::Server.start('0.0.0.0', 3000, app)
|
32
32
|
#
|
data/example/async_app.ru
CHANGED
@@ -87,7 +87,7 @@ class AsyncApp
|
|
87
87
|
body = DeferrableBody.new
|
88
88
|
|
89
89
|
# Get the headers out there asap, let the client know we're alive...
|
90
|
-
EventMachine::next_tick { env['async.callback'].call [200, {'
|
90
|
+
EventMachine::next_tick { env['async.callback'].call [200, {'content-type' => 'text/plain'}, body] }
|
91
91
|
|
92
92
|
# Semi-emulate a long db request, instead of a timer, in reality we'd be
|
93
93
|
# waiting for the response data. Whilst this happens, other connections
|
data/example/async_chat.ru
CHANGED
@@ -118,7 +118,7 @@ class Chat
|
|
118
118
|
send_message = function(message_box) {
|
119
119
|
xhr = XHR();
|
120
120
|
xhr.open("POST", "/", true);
|
121
|
-
xhr.setRequestHeader("
|
121
|
+
xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded");
|
122
122
|
xhr.setRequestHeader("X_REQUESTED_WITH", "XMLHttpRequest");
|
123
123
|
xhr.send("message="+escape(message_box.value));
|
124
124
|
scroll();
|
@@ -161,7 +161,7 @@ class Chat
|
|
161
161
|
body.callback { delete_user user_id }
|
162
162
|
|
163
163
|
EventMachine::next_tick do
|
164
|
-
renderer.call [200, {'
|
164
|
+
renderer.call [200, {'content-type' => 'text/html'}, body]
|
165
165
|
end
|
166
166
|
end
|
167
167
|
|
data/example/async_tailer.ru
CHANGED
data/example/config.ru
CHANGED
data/ext/thin_parser/common.rl
CHANGED
@@ -43,7 +43,7 @@
|
|
43
43
|
Method = ( upper | digit | safe ){1,20} >mark %request_method;
|
44
44
|
|
45
45
|
http_number = ( digit+ "." digit+ ) ;
|
46
|
-
HTTP_Version = ( "HTTP/" http_number ) >mark %
|
46
|
+
HTTP_Version = ( "HTTP/" http_number ) >mark %request_http_version ;
|
47
47
|
Request_Line = ( Method " " Request_URI ("#" Fragment){0,1} " " HTTP_Version CRLF ) ;
|
48
48
|
|
49
49
|
field_name = ( token -- ":" )+ >start_field %write_field;
|
data/ext/thin_parser/parser.c
CHANGED
@@ -295,8 +295,8 @@ case 13:
|
|
295
295
|
tr17:
|
296
296
|
#line 59 "parser.rl"
|
297
297
|
{
|
298
|
-
if (parser->
|
299
|
-
parser->
|
298
|
+
if (parser->request_http_version != NULL) {
|
299
|
+
parser->request_http_version(parser->data, PTR_TO(mark), LEN(mark, p));
|
300
300
|
}
|
301
301
|
}
|
302
302
|
goto st14;
|
data/ext/thin_parser/parser.h
CHANGED
data/ext/thin_parser/parser.rl
CHANGED
@@ -56,9 +56,9 @@
|
|
56
56
|
}
|
57
57
|
}
|
58
58
|
|
59
|
-
action
|
60
|
-
if (parser->
|
61
|
-
parser->
|
59
|
+
action request_http_version {
|
60
|
+
if (parser->request_http_version != NULL) {
|
61
|
+
parser->request_http_version(parser->data, PTR_TO(mark), LEN(mark, fpc));
|
62
62
|
}
|
63
63
|
}
|
64
64
|
|
data/ext/thin_parser/thin.c
CHANGED
@@ -21,7 +21,7 @@ static VALUE global_request_method;
|
|
21
21
|
static VALUE global_request_uri;
|
22
22
|
static VALUE global_fragment;
|
23
23
|
static VALUE global_query_string;
|
24
|
-
static VALUE
|
24
|
+
static VALUE global_request_http_version;
|
25
25
|
static VALUE global_content_length;
|
26
26
|
static VALUE global_http_content_length;
|
27
27
|
static VALUE global_request_path;
|
@@ -150,11 +150,12 @@ static void query_string(void *data, const char *at, size_t length)
|
|
150
150
|
rb_hash_aset(req, global_query_string, val);
|
151
151
|
}
|
152
152
|
|
153
|
-
static void
|
153
|
+
static void request_http_version(void *data, const char *at, size_t length)
|
154
154
|
{
|
155
155
|
VALUE req = (VALUE)data;
|
156
156
|
VALUE val = rb_str_new(at, length);
|
157
|
-
rb_hash_aset(req,
|
157
|
+
rb_hash_aset(req, global_request_http_version, val);
|
158
|
+
rb_hash_aset(req, global_server_protocol, val);
|
158
159
|
}
|
159
160
|
|
160
161
|
/** Finalizes the request header to have a bunch of stuff that's
|
@@ -211,7 +212,6 @@ static void header_done(void *data, const char *at, size_t length)
|
|
211
212
|
}
|
212
213
|
|
213
214
|
/* set some constants */
|
214
|
-
rb_hash_aset(req, global_server_protocol, global_server_protocol_value);
|
215
215
|
rb_hash_aset(req, global_url_scheme, global_url_scheme_value);
|
216
216
|
rb_hash_aset(req, global_script_name, global_empty);
|
217
217
|
}
|
@@ -237,7 +237,7 @@ VALUE Thin_HttpParser_alloc(VALUE klass)
|
|
237
237
|
hp->fragment = fragment;
|
238
238
|
hp->request_path = request_path;
|
239
239
|
hp->query_string = query_string;
|
240
|
-
hp->
|
240
|
+
hp->request_http_version = request_http_version;
|
241
241
|
hp->header_done = header_done;
|
242
242
|
thin_http_parser_init(hp);
|
243
243
|
|
@@ -401,7 +401,7 @@ void Init_thin_parser()
|
|
401
401
|
DEF_GLOBAL(request_uri, "REQUEST_URI");
|
402
402
|
DEF_GLOBAL(fragment, "FRAGMENT");
|
403
403
|
DEF_GLOBAL(query_string, "QUERY_STRING");
|
404
|
-
DEF_GLOBAL(
|
404
|
+
DEF_GLOBAL(request_http_version, "thin.request_http_version");
|
405
405
|
DEF_GLOBAL(request_path, "REQUEST_PATH");
|
406
406
|
DEF_GLOBAL(content_length, "CONTENT_LENGTH");
|
407
407
|
DEF_GLOBAL(http_content_length, "HTTP_CONTENT_LENGTH");
|
data/lib/rack/adapter/loader.rb
CHANGED
@@ -15,6 +15,13 @@ module Rack
|
|
15
15
|
[:file, nil]
|
16
16
|
]
|
17
17
|
|
18
|
+
# Rack v1 compatibility...
|
19
|
+
unless const_defined?(:Files)
|
20
|
+
require 'rack/file'
|
21
|
+
|
22
|
+
Files = File
|
23
|
+
end
|
24
|
+
|
18
25
|
module Adapter
|
19
26
|
# Guess which adapter to use based on the directory structure
|
20
27
|
# or file content.
|
@@ -64,7 +71,7 @@ module Rack
|
|
64
71
|
return Merb::Rack::Application.new
|
65
72
|
|
66
73
|
when :file
|
67
|
-
return Rack::
|
74
|
+
return Rack::Files.new(options[:chdir])
|
68
75
|
|
69
76
|
else
|
70
77
|
raise AdapterNotFound, "Adapter not found: #{name}"
|
data/lib/rack/adapter/rails.rb
CHANGED
@@ -23,7 +23,7 @@ module Rack
|
|
23
23
|
load_application
|
24
24
|
|
25
25
|
@rails_app = self.class.rack_based? ? ActionController::Dispatcher.new : CgiApp.new
|
26
|
-
@file_app = Rack::
|
26
|
+
@file_app = Rack::Files.new(::File.join(RAILS_ROOT, "public"))
|
27
27
|
end
|
28
28
|
|
29
29
|
def load_application
|
@@ -126,13 +126,7 @@ module Rack
|
|
126
126
|
|
127
127
|
@output_cookies.each { |c| cookies << c.to_s } if @output_cookies
|
128
128
|
|
129
|
-
@response['Set-Cookie'] = [@response['Set-Cookie'], cookies].compact
|
130
|
-
# See http://groups.google.com/group/rack-devel/browse_thread/thread/e8759b91a82c5a10/a8dbd4574fe97d69?#a8dbd4574fe97d69
|
131
|
-
if Thin.ruby_18?
|
132
|
-
@response['Set-Cookie'].flatten!
|
133
|
-
else
|
134
|
-
@response['Set-Cookie'] = @response['Set-Cookie'].join("\n")
|
135
|
-
end
|
129
|
+
@response['Set-Cookie'] = [@response['Set-Cookie'], cookies].compact.join("\n")
|
136
130
|
end
|
137
131
|
|
138
132
|
options.each { |k, v| @response[k] = v }
|
data/lib/rack/handler/thin.rb
CHANGED
@@ -1,38 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
|
5
|
-
require "thin/logging"
|
6
|
-
require "thin/backends/tcp_server"
|
3
|
+
require 'rack/handler'
|
4
|
+
require_relative '../../thin/rackup/handler'
|
7
5
|
|
8
6
|
module Rack
|
9
7
|
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
|
8
|
+
class Thin < ::Thin::Rackup::Handler
|
34
9
|
end
|
35
10
|
|
36
|
-
register :thin,
|
11
|
+
register :thin, Thin.to_s
|
37
12
|
end
|
38
13
|
end
|
@@ -50,7 +50,17 @@ module Thin
|
|
50
50
|
|
51
51
|
# For some reason Swiftiply request the current host
|
52
52
|
def host_ip
|
53
|
-
|
53
|
+
begin
|
54
|
+
if defined?(Addrinfo)
|
55
|
+
# ruby 2.0+
|
56
|
+
# TODO: ipv6 support here?
|
57
|
+
Addrinfo.getaddrinfo(@backend.host, @backend.port, :PF_INET, :STREAM).first.ip_address.split('.').map(&:to_i)
|
58
|
+
else
|
59
|
+
Socket.gethostbyname(@backend.host)[3].unpack('CCCC')
|
60
|
+
end
|
61
|
+
rescue
|
62
|
+
[0, 0, 0, 0]
|
63
|
+
end
|
54
64
|
end
|
55
65
|
end
|
56
66
|
end
|
data/lib/thin/connection.rb
CHANGED
data/lib/thin/daemonizing.rb
CHANGED
@@ -78,7 +78,7 @@ module Thin
|
|
78
78
|
|
79
79
|
if uid != target_uid || gid != target_gid
|
80
80
|
# Change PID file ownership
|
81
|
-
File.chown(target_uid, target_gid, @pid_file) if File.
|
81
|
+
File.chown(target_uid, target_gid, @pid_file) if File.exist?(@pid_file)
|
82
82
|
|
83
83
|
# Change process ownership
|
84
84
|
Process.initgroups(user, target_gid)
|
@@ -174,7 +174,7 @@ module Thin
|
|
174
174
|
|
175
175
|
protected
|
176
176
|
def remove_pid_file
|
177
|
-
File.delete(@pid_file) if @pid_file && File.
|
177
|
+
File.delete(@pid_file) if @pid_file && File.exist?(@pid_file)
|
178
178
|
end
|
179
179
|
|
180
180
|
def write_pid_file
|
data/lib/thin/env.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
|
2
|
+
module Thin
|
3
|
+
module Env
|
4
|
+
def self.with_defaults(env)
|
5
|
+
if ::Rack.release >= "3"
|
6
|
+
rack_env_class = Rack3
|
7
|
+
else
|
8
|
+
rack_env_class = Rack2
|
9
|
+
end
|
10
|
+
|
11
|
+
rack_env_class.env.merge(env)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
class Rack2
|
18
|
+
RACK_VERSION = [1, 0].freeze
|
19
|
+
|
20
|
+
def self.env
|
21
|
+
{
|
22
|
+
::Thin::Request::RACK_VERSION => RACK_VERSION,
|
23
|
+
::Thin::Request::RACK_MULTITHREAD => false,
|
24
|
+
::Thin::Request::RACK_MULTIPROCESS => false,
|
25
|
+
::Thin::Request::RACK_RUN_ONCE => false
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class Rack3
|
31
|
+
def self.env
|
32
|
+
{}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Thin
|
4
|
+
module Rackup
|
5
|
+
class Handler
|
6
|
+
def self.run(app, **options)
|
7
|
+
environment = ENV['RACK_ENV'] || 'development'
|
8
|
+
default_host = environment == 'development' ? 'localhost' : '0.0.0.0'
|
9
|
+
|
10
|
+
host = options.delete(:Host) || default_host
|
11
|
+
port = options.delete(:Port) || 8080
|
12
|
+
args = [host, port, app, options]
|
13
|
+
|
14
|
+
server = ::Thin::Server.new(*args)
|
15
|
+
yield server if block_given?
|
16
|
+
|
17
|
+
server.start
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.valid_options
|
21
|
+
environment = ENV['RACK_ENV'] || 'development'
|
22
|
+
default_host = environment == 'development' ? 'localhost' : '0.0.0.0'
|
23
|
+
|
24
|
+
{
|
25
|
+
"Host=HOST" => "Hostname to listen on (default: #{default_host})",
|
26
|
+
"Port=PORT" => "Port to listen on (default: 8080)",
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/thin/request.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'tempfile'
|
2
|
+
require_relative './env'
|
2
3
|
|
3
4
|
module Thin
|
4
5
|
# Raised when an incoming request is not valid
|
@@ -22,7 +23,7 @@ module Thin
|
|
22
23
|
SERVER_NAME = 'SERVER_NAME'.freeze
|
23
24
|
REQUEST_METHOD = 'REQUEST_METHOD'.freeze
|
24
25
|
LOCALHOST = 'localhost'.freeze
|
25
|
-
|
26
|
+
REQUEST_HTTP_VERSION = 'thin.request_http_version'.freeze
|
26
27
|
HTTP_1_0 = 'HTTP/1.0'.freeze
|
27
28
|
REMOTE_ADDR = 'REMOTE_ADDR'.freeze
|
28
29
|
CONTENT_LENGTH = 'CONTENT_LENGTH'.freeze
|
@@ -55,20 +56,14 @@ module Thin
|
|
55
56
|
@data = String.new
|
56
57
|
@nparsed = 0
|
57
58
|
@body = StringIO.new(INITIAL_BODY.dup)
|
58
|
-
@env = {
|
59
|
+
@env = Env.with_defaults({
|
59
60
|
SERVER_SOFTWARE => SERVER,
|
60
61
|
SERVER_NAME => LOCALHOST,
|
61
62
|
|
62
63
|
# Rack stuff
|
63
64
|
RACK_INPUT => @body,
|
64
|
-
|
65
|
-
RACK_VERSION => VERSION::RACK,
|
66
65
|
RACK_ERRORS => STDERR,
|
67
|
-
|
68
|
-
RACK_MULTITHREAD => false,
|
69
|
-
RACK_MULTIPROCESS => false,
|
70
|
-
RACK_RUN_ONCE => false
|
71
|
-
}
|
66
|
+
})
|
72
67
|
end
|
73
68
|
|
74
69
|
# Parse a chunk of data into the request environment
|
@@ -114,7 +109,7 @@ module Thin
|
|
114
109
|
# Clients and servers SHOULD NOT assume that a persistent connection
|
115
110
|
# is maintained for HTTP versions less than 1.1 unless it is explicitly
|
116
111
|
# signaled. (http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html)
|
117
|
-
if @env[
|
112
|
+
if @env[REQUEST_HTTP_VERSION] == HTTP_1_0
|
118
113
|
@env[CONNECTION] =~ KEEP_ALIVE_REGEXP
|
119
114
|
|
120
115
|
# HTTP/1.1 client intends to maintain a persistent connection unless
|
data/lib/thin/response.rb
CHANGED
@@ -1,18 +1,64 @@
|
|
1
1
|
module Thin
|
2
2
|
# A response sent to the client.
|
3
3
|
class Response
|
4
|
-
|
4
|
+
class Stream
|
5
|
+
def initialize(writer)
|
6
|
+
@read_closed = true
|
7
|
+
@write_closed = false
|
8
|
+
@writer = writer
|
9
|
+
end
|
10
|
+
|
11
|
+
def read(length = nil, outbuf = nil)
|
12
|
+
raise ::IOError, 'not opened for reading' if @read_closed
|
13
|
+
end
|
14
|
+
|
15
|
+
def write(chunk)
|
16
|
+
raise ::IOError, 'not opened for writing' if @write_closed
|
17
|
+
|
18
|
+
@writer.call(chunk)
|
19
|
+
end
|
20
|
+
|
21
|
+
alias :<< :write
|
22
|
+
|
23
|
+
def close
|
24
|
+
@read_closed = @write_closed = true
|
25
|
+
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def closed?
|
30
|
+
@read_closed && @write_closed
|
31
|
+
end
|
32
|
+
|
33
|
+
def close_read
|
34
|
+
@read_closed = true
|
35
|
+
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
|
39
|
+
def close_write
|
40
|
+
@write_closed = true
|
41
|
+
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
|
45
|
+
def flush
|
46
|
+
self
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
CONNECTION = 'connection'.freeze
|
5
51
|
CLOSE = 'close'.freeze
|
6
52
|
KEEP_ALIVE = 'keep-alive'.freeze
|
7
|
-
SERVER = '
|
8
|
-
CONTENT_LENGTH = '
|
53
|
+
SERVER = 'server'.freeze
|
54
|
+
CONTENT_LENGTH = 'content-length'.freeze
|
9
55
|
|
10
56
|
PERSISTENT_STATUSES = [100, 101].freeze
|
11
57
|
|
12
58
|
#Error Responses
|
13
|
-
ERROR = [500, {'
|
14
|
-
PERSISTENT_ERROR = [500, {'
|
15
|
-
BAD_REQUEST = [400, {'
|
59
|
+
ERROR = [500, {'content-type' => 'text/plain'}, ['Internal server error']].freeze
|
60
|
+
PERSISTENT_ERROR = [500, {'content-type' => 'text/plain', 'connection' => 'keep-alive', 'content-length' => "21"}, ['Internal server error']].freeze
|
61
|
+
BAD_REQUEST = [400, {'content-type' => 'text/plain'}, ['Bad Request']].freeze
|
16
62
|
|
17
63
|
# Status code
|
18
64
|
attr_accessor :status
|
@@ -46,36 +92,15 @@ module Thin
|
|
46
92
|
"HTTP/1.1 #{@status} #{HTTP_STATUS_CODES[@status.to_i]}\r\n#{headers_output}\r\n"
|
47
93
|
end
|
48
94
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
end if key_value_pairs
|
59
|
-
end
|
60
|
-
|
61
|
-
else
|
62
|
-
|
63
|
-
# Ruby 1.9 doesn't have a String#each anymore.
|
64
|
-
# Rack spec doesn't take care of that yet, for now we just use
|
65
|
-
# +each+ but fallback to +each_line+ on strings.
|
66
|
-
# I wish we could remove that condition.
|
67
|
-
# To be reviewed when a new Rack spec comes out.
|
68
|
-
def headers=(key_value_pairs)
|
69
|
-
key_value_pairs.each do |k, vs|
|
70
|
-
next unless vs
|
71
|
-
if vs.is_a?(String)
|
72
|
-
vs.each_line { |v| @headers[k] = v.chomp }
|
73
|
-
else
|
74
|
-
vs.each { |v| @headers[k] = v.chomp }
|
75
|
-
end
|
76
|
-
end if key_value_pairs
|
77
|
-
end
|
78
|
-
|
95
|
+
def headers=(key_value_pairs)
|
96
|
+
key_value_pairs.each do |k, vs|
|
97
|
+
next unless vs
|
98
|
+
if vs.is_a?(String)
|
99
|
+
vs.each_line { |v| @headers[k] = v.chomp }
|
100
|
+
else
|
101
|
+
vs.each { |v| @headers[k] = v.chomp }
|
102
|
+
end
|
103
|
+
end if key_value_pairs
|
79
104
|
end
|
80
105
|
|
81
106
|
# Close any resource used by the response
|
@@ -86,14 +111,16 @@ module Thin
|
|
86
111
|
# Yields each chunk of the response.
|
87
112
|
# To control the size of each chunk
|
88
113
|
# define your own +each+ method on +body+.
|
89
|
-
def each
|
114
|
+
def each(&block)
|
90
115
|
yield head
|
91
116
|
|
92
117
|
unless @skip_body
|
93
118
|
if @body.is_a?(String)
|
94
119
|
yield @body
|
95
|
-
|
120
|
+
elsif @body.respond_to?(:each)
|
96
121
|
@body.each { |chunk| yield chunk }
|
122
|
+
else
|
123
|
+
@body.call(Stream.new(block))
|
97
124
|
end
|
98
125
|
end
|
99
126
|
end
|
@@ -104,7 +131,7 @@ module Thin
|
|
104
131
|
end
|
105
132
|
|
106
133
|
# Persistent connection must be requested as keep-alive
|
107
|
-
# from the server and have a
|
134
|
+
# from the server and have a content-length, or the response
|
108
135
|
# status must require that the connection remain open.
|
109
136
|
def persistent?
|
110
137
|
(@persistent && @headers.has_key?(CONTENT_LENGTH)) || PERSISTENT_STATUSES.include?(@status)
|
data/lib/thin/server.rb
CHANGED
@@ -152,7 +152,7 @@ module Thin
|
|
152
152
|
def start
|
153
153
|
raise ArgumentError, 'app required' unless @app
|
154
154
|
|
155
|
-
log_info "Thin web server (v#{VERSION
|
155
|
+
log_info "Thin web server (v#{VERSION} codename #{CODENAME})"
|
156
156
|
log_debug "Debugging ON"
|
157
157
|
trace "Tracing ON"
|
158
158
|
|
data/lib/thin/stats.rb
CHANGED
data/lib/thin/version.rb
CHANGED
@@ -3,20 +3,11 @@ module Thin
|
|
3
3
|
# current platform.
|
4
4
|
class PlatformNotSupported < RuntimeError; end
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
MINOR = 8
|
9
|
-
TINY = 1
|
10
|
-
|
11
|
-
STRING = [MAJOR, MINOR, TINY].join('.')
|
12
|
-
|
13
|
-
CODENAME = "Infinite Smoothie".freeze
|
14
|
-
|
15
|
-
RACK = [1, 0].freeze # Rack protocol version
|
16
|
-
end
|
6
|
+
VERSION = "2.0.0"
|
7
|
+
CODENAME = "Thinception".freeze
|
17
8
|
|
18
9
|
NAME = 'thin'.freeze
|
19
|
-
SERVER = "#{NAME} #{VERSION
|
10
|
+
SERVER = "#{NAME} #{VERSION} codename #{CODENAME}".freeze
|
20
11
|
|
21
12
|
def self.win?
|
22
13
|
RUBY_PLATFORM =~ /mswin|mingw/
|
@@ -25,8 +16,4 @@ module Thin
|
|
25
16
|
def self.linux?
|
26
17
|
RUBY_PLATFORM =~ /linux/
|
27
18
|
end
|
28
|
-
|
29
|
-
def self.ruby_18?
|
30
|
-
RUBY_VERSION =~ /^1\.8/
|
31
|
-
end
|
32
19
|
end
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marc-Andre Cournoyer
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: rack
|
@@ -19,7 +18,7 @@ dependencies:
|
|
19
18
|
version: '1'
|
20
19
|
- - "<"
|
21
20
|
- !ruby/object:Gem::Version
|
22
|
-
version: '
|
21
|
+
version: '4'
|
23
22
|
type: :runtime
|
24
23
|
prerelease: false
|
25
24
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -29,7 +28,7 @@ dependencies:
|
|
29
28
|
version: '1'
|
30
29
|
- - "<"
|
31
30
|
- !ruby/object:Gem::Version
|
32
|
-
version: '
|
31
|
+
version: '4'
|
33
32
|
- !ruby/object:Gem::Dependency
|
34
33
|
name: eventmachine
|
35
34
|
requirement: !ruby/object:Gem::Requirement
|
@@ -70,7 +69,20 @@ dependencies:
|
|
70
69
|
- - ">="
|
71
70
|
- !ruby/object:Gem::Version
|
72
71
|
version: 1.0.9
|
73
|
-
|
72
|
+
- !ruby/object:Gem::Dependency
|
73
|
+
name: logger
|
74
|
+
requirement: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
type: :runtime
|
80
|
+
prerelease: false
|
81
|
+
version_requirements: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
74
86
|
email: macournoyer@gmail.com
|
75
87
|
executables:
|
76
88
|
- thin
|
@@ -105,6 +117,7 @@ files:
|
|
105
117
|
- lib/rack/adapter/loader.rb
|
106
118
|
- lib/rack/adapter/rails.rb
|
107
119
|
- lib/rack/handler/thin.rb
|
120
|
+
- lib/rackup/handler/thin.rb
|
108
121
|
- lib/thin.rb
|
109
122
|
- lib/thin/backends/base.rb
|
110
123
|
- lib/thin/backends/swiftiply_client.rb
|
@@ -117,8 +130,10 @@ files:
|
|
117
130
|
- lib/thin/controllers/service.rb
|
118
131
|
- lib/thin/controllers/service.sh.erb
|
119
132
|
- lib/thin/daemonizing.rb
|
133
|
+
- lib/thin/env.rb
|
120
134
|
- lib/thin/headers.rb
|
121
135
|
- lib/thin/logging.rb
|
136
|
+
- lib/thin/rackup/handler.rb
|
122
137
|
- lib/thin/request.rb
|
123
138
|
- lib/thin/response.rb
|
124
139
|
- lib/thin/runner.rb
|
@@ -134,7 +149,6 @@ licenses:
|
|
134
149
|
metadata:
|
135
150
|
source_code_uri: https://github.com/macournoyer/thin
|
136
151
|
changelog_uri: https://github.com/macournoyer/thin/blob/master/CHANGELOG
|
137
|
-
post_install_message:
|
138
152
|
rdoc_options: []
|
139
153
|
require_paths:
|
140
154
|
- lib
|
@@ -142,15 +156,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
142
156
|
requirements:
|
143
157
|
- - ">="
|
144
158
|
- !ruby/object:Gem::Version
|
145
|
-
version:
|
159
|
+
version: '2.6'
|
146
160
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
147
161
|
requirements:
|
148
162
|
- - ">="
|
149
163
|
- !ruby/object:Gem::Version
|
150
164
|
version: '0'
|
151
165
|
requirements: []
|
152
|
-
rubygems_version: 3.
|
153
|
-
signing_key:
|
166
|
+
rubygems_version: 3.6.7
|
154
167
|
specification_version: 4
|
155
168
|
summary: A thin and fast web server
|
156
169
|
test_files: []
|