thin 1.8.2 → 2.0.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 32913c8b29b57b8f15fcd7cffb49db757989a225794e089ced01e53354c3cd90
4
- data.tar.gz: f232efe452f20785ea8e71422a53147205ffd65ddbba90b8ba12e5b340c3b466
3
+ metadata.gz: 585c9d1004e2b89c83cd2c19eeb6fb2008de2f3d8e60fe716c607831f8ec30d8
4
+ data.tar.gz: 987b113621abee8a809f531668308421bdebd0b2233cfd10a87577ad0ff6e163
5
5
  SHA512:
6
- metadata.gz: 2cf9f7764e73b4086d1a11156bcd1aa67e6e3cabc32076e404971f866e3d4f28b536375773d03bf54e8237d3755cb70399c421044cb7cb577801f2f1deefe4d8
7
- data.tar.gz: ed2643e1bc850bea3bd868150cd5c6b198b440b585a99def2099c35122d7a663c928c508f7441c4d708df6c878296b0e5cafcf9ebcfe70ef6ac6a1ca645111fe
6
+ metadata.gz: 0bd441d790ccf3b1221f8cf3b5076d29d88afb21e44bb3d95a3c189f651ba61fadc2ce7fec4196ab979935ac197cdfa4801f079a30dfe910e5967172e515c9a5
7
+ data.tar.gz: 792072cad2f63070ceca9e44ba5c67ef32aff3400bd2b5d016fdcd2d20f39021b5ad6d87868bab11a03c48e4504a8240002214c85c089381754a1728bf0d0c3a
data/CHANGELOG CHANGED
@@ -1,3 +1,6 @@
1
+ == 2.0.0
2
+ * Partial Rack 3 support. Full bi-directional streaming is not supported due to limitations in the implementation.
3
+
1
4
  == 1.8.2 Ruby Razor
2
5
  * Ruby 3.2 support.
3
6
 
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:
@@ -87,7 +71,9 @@ tag: a-name-to-show-up-in-ps aux
87
71
 
88
72
  ## License
89
73
 
90
- Ruby License, http://www.ruby-lang.org/en/LICENSE.txt.
74
+ Copyright, 2007-2025, by Marc-Andre Cournoyer and other contributors.
75
+
76
+ Released under the Ruby License, the 2-clause BSDL and the GNU General Public License (GPL) version 2 (or later). You can redistribute it and/or modify it under the terms of any of these licenses.
91
77
 
92
78
  ## Credits
93
79
 
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::STRING}"
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
- { 'Content-Type' => 'text/plain' },
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::File.new('.')
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::File.new('.'))
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, {'Content-Type' => 'text/plain'}, body] }
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
@@ -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("Content-Type", "application/x-www-form-urlencoded");
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, {'Content-Type' => 'text/html'}, body]
164
+ renderer.call [200, {'content-type' => 'text/html'}, body]
165
165
  end
166
166
  end
167
167
 
@@ -70,7 +70,7 @@ class AsyncTailer
70
70
 
71
71
  EventMachine::next_tick do
72
72
 
73
- env['async.callback'].call [200, {'Content-Type' => 'text/html'}, body]
73
+ env['async.callback'].call [200, {'content-type' => 'text/html'}, body]
74
74
 
75
75
  body.call ["<h1>Async Tailer</h1><pre>"]
76
76
 
data/example/config.ru CHANGED
@@ -14,7 +14,7 @@ app = proc do |env|
14
14
 
15
15
  [
16
16
  200, # Status code
17
- { 'Content-Type' => 'text/html' }, # Reponse headers
17
+ { 'content-type' => 'text/html' }, # Reponse headers
18
18
  body # Body of the response
19
19
  ]
20
20
  end
@@ -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 %http_version ;
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;
@@ -295,8 +295,8 @@ case 13:
295
295
  tr17:
296
296
  #line 59 "parser.rl"
297
297
  {
298
- if (parser->http_version != NULL) {
299
- parser->http_version(parser->data, PTR_TO(mark), LEN(mark, p));
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;
@@ -33,7 +33,7 @@ typedef struct http_parser {
33
33
  element_cb fragment;
34
34
  element_cb request_path;
35
35
  element_cb query_string;
36
- element_cb http_version;
36
+ element_cb request_http_version;
37
37
  element_cb header_done;
38
38
 
39
39
  } http_parser;
@@ -56,9 +56,9 @@
56
56
  }
57
57
  }
58
58
 
59
- action http_version {
60
- if (parser->http_version != NULL) {
61
- parser->http_version(parser->data, PTR_TO(mark), LEN(mark, fpc));
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
 
@@ -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 global_http_version;
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 http_version(void *data, const char *at, size_t length)
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, global_http_version, val);
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->http_version = http_version;
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(http_version, "HTTP_VERSION");
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");
@@ -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::File.new(options[:chdir])
74
+ return Rack::Files.new(options[:chdir])
68
75
 
69
76
  else
70
77
  raise AdapterNotFound, "Adapter not found: #{name}"
@@ -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::File.new(::File.join(RAILS_ROOT, "public"))
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 }
@@ -1,38 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "thin"
4
- require "thin/server"
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, ::Rack::Handler::Thin
11
+ register :thin, Thin.to_s
37
12
  end
38
13
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rackup/handler'
4
+ require_relative '../../thin/rackup/handler'
5
+
6
+ module Rackup
7
+ module Handler
8
+ class Thin < ::Thin::Rackup::Handler
9
+ end
10
+
11
+ register :thin, Thin
12
+ end
13
+ end
@@ -72,6 +72,10 @@ module Thin
72
72
  if @backend.ssl?
73
73
  @request.env["rack.url_scheme"] = "https"
74
74
 
75
+ if @backend.respond_to?(:port)
76
+ @request.env['SERVER_PORT'] = @backend.port.to_s
77
+ end
78
+
75
79
  if cert = get_peer_cert
76
80
  @request.env['rack.peer_cert'] = cert
77
81
  end
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,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../server"
4
+
5
+ module Thin
6
+ module Rackup
7
+ class Handler
8
+ def self.run(app, **options)
9
+ environment = ENV['RACK_ENV'] || 'development'
10
+ default_host = environment == 'development' ? 'localhost' : '0.0.0.0'
11
+
12
+ host = options.delete(:Host) || default_host
13
+ port = options.delete(:Port) || 8080
14
+ args = [host, port, app, options]
15
+
16
+ server = ::Thin::Server.new(*args)
17
+ yield server if block_given?
18
+
19
+ server.start
20
+ end
21
+
22
+ def self.valid_options
23
+ environment = ENV['RACK_ENV'] || 'development'
24
+ default_host = environment == 'development' ? 'localhost' : '0.0.0.0'
25
+
26
+ {
27
+ "Host=HOST" => "Hostname to listen on (default: #{default_host})",
28
+ "Port=PORT" => "Port to listen on (default: 8080)",
29
+ }
30
+ end
31
+ end
32
+ end
33
+ 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
- HTTP_VERSION = 'HTTP_VERSION'.freeze
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[HTTP_VERSION] == HTTP_1_0
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
- CONNECTION = 'Connection'.freeze
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 = 'Server'.freeze
8
- CONTENT_LENGTH = 'Content-Length'.freeze
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, {'Content-Type' => 'text/plain'}, ['Internal server error']].freeze
14
- PERSISTENT_ERROR = [500, {'Content-Type' => 'text/plain', 'Connection' => 'keep-alive', 'Content-Length' => "21"}, ['Internal server error']].freeze
15
- BAD_REQUEST = [400, {'Content-Type' => 'text/plain'}, ['Bad Request']].freeze
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
- if Thin.ruby_18?
50
-
51
- # Ruby 1.8 implementation.
52
- # Respects Rack specs.
53
- #
54
- # See http://rack.rubyforge.org/doc/files/SPEC.html
55
- def headers=(key_value_pairs)
56
- key_value_pairs.each do |k, vs|
57
- vs.each { |v| @headers[k] = v.chomp } if vs
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
- else
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 Content-Length, or the response
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::STRING} codename #{VERSION::CODENAME})"
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
@@ -43,7 +43,7 @@ module Thin
43
43
 
44
44
  [
45
45
  200,
46
- { 'Content-Type' => 'text/html' },
46
+ { 'content-type' => 'text/html' },
47
47
  [body]
48
48
  ]
49
49
  end
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
- module VERSION #:nodoc:
7
- MAJOR = 1
8
- MINOR = 8
9
- TINY = 2
10
-
11
- STRING = [MAJOR, MINOR, TINY].join('.')
12
-
13
- CODENAME = "Ruby Razor".freeze
14
-
15
- RACK = [1, 0].freeze # Rack protocol version
16
- end
6
+ VERSION = "2.0.1"
7
+ CODENAME = "Thinception".freeze
17
8
 
18
9
  NAME = 'thin'.freeze
19
- SERVER = "#{NAME} #{VERSION::STRING} codename #{VERSION::CODENAME}".freeze
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: 1.8.2
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marc-Andre Cournoyer
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2023-03-31 00:00:00.000000000 Z
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: '3'
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: '3'
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
- description:
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
@@ -129,12 +144,11 @@ files:
129
144
  - lib/thin/version.rb
130
145
  homepage: https://github.com/macournoyer/thin
131
146
  licenses:
132
- - GPL-2.0+
147
+ - GPL-2.0-or-later
133
148
  - Ruby
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: 1.8.5
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.4.7
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: []