friendlyfashion-thin 1.4.1 → 1.4.1.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.
@@ -13,30 +13,30 @@ module Thin
13
13
  class Base
14
14
  # Server serving the connections throught the backend
15
15
  attr_accessor :server
16
-
16
+
17
17
  # Maximum time for incoming data to arrive
18
18
  attr_accessor :timeout
19
-
19
+
20
20
  # Maximum number of file or socket descriptors that the server may open.
21
21
  attr_accessor :maximum_connections
22
-
22
+
23
23
  # Maximum number of connections that can be persistent
24
24
  attr_accessor :maximum_persistent_connections
25
-
25
+
26
26
  # Allow using threads in the backend.
27
27
  attr_writer :threaded
28
28
  def threaded?; @threaded end
29
-
29
+
30
30
  # Allow using SSL in the backend.
31
31
  attr_writer :ssl, :ssl_options
32
32
  def ssl?; @ssl end
33
-
33
+
34
34
  # Number of persistent connections currently opened
35
35
  attr_accessor :persistent_connection_count
36
-
36
+
37
37
  # Disable the use of epoll under Linux
38
38
  attr_accessor :no_epoll
39
-
39
+
40
40
  def initialize
41
41
  @connections = []
42
42
  @timeout = Server::DEFAULT_TIMEOUT
@@ -47,7 +47,7 @@ module Thin
47
47
  @ssl = nil
48
48
  @threaded = nil
49
49
  end
50
-
50
+
51
51
  # Start the backend and connect it.
52
52
  def start
53
53
  @stopping = false
@@ -55,7 +55,7 @@ module Thin
55
55
  connect
56
56
  @running = true
57
57
  end
58
-
58
+
59
59
  # Allow for early run up of eventmachine.
60
60
  if EventMachine.reactor_running?
61
61
  starter.call
@@ -63,67 +63,72 @@ module Thin
63
63
  EventMachine.run(&starter)
64
64
  end
65
65
  end
66
-
66
+
67
67
  # Stop of the backend from accepting new connections.
68
68
  def stop
69
69
  @running = false
70
70
  @stopping = true
71
-
71
+
72
72
  # Do not accept anymore connection
73
73
  disconnect
74
74
  stop! if @connections.empty?
75
75
  end
76
-
76
+
77
77
  # Force stop of the backend NOW, too bad for the current connections.
78
78
  def stop!
79
79
  @running = false
80
80
  @stopping = false
81
-
81
+
82
82
  EventMachine.stop if EventMachine.reactor_running?
83
83
  @connections.each { |connection| connection.close_connection }
84
84
  close
85
85
  end
86
-
86
+
87
87
  # Configure the backend. This method will be called before droping superuser privileges,
88
88
  # so you can do crazy stuff that require godlike powers here.
89
89
  def config
90
90
  # See http://rubyeventmachine.com/pub/rdoc/files/EPOLL.html
91
91
  EventMachine.epoll unless @no_epoll
92
-
92
+
93
93
  # Set the maximum number of socket descriptors that the server may open.
94
94
  # The process needs to have required privilege to set it higher the 1024 on
95
95
  # some systems.
96
96
  @maximum_connections = EventMachine.set_descriptor_table_size(@maximum_connections) unless Thin.win?
97
97
  end
98
-
98
+
99
99
  # Free up resources used by the backend.
100
100
  def close
101
101
  end
102
-
102
+
103
103
  # Returns +true+ if the backend is connected and running.
104
104
  def running?
105
105
  @running
106
106
  end
107
-
107
+
108
108
  # Called by a connection when it's unbinded.
109
109
  def connection_finished(connection)
110
110
  @persistent_connection_count -= 1 if connection.can_persist?
111
111
  @connections.delete(connection)
112
-
112
+
113
113
  # Finalize gracefull stop if there's no more active connection.
114
114
  stop! if @stopping && @connections.empty?
115
115
  end
116
-
116
+
117
117
  # Returns +true+ if no active connection.
118
118
  def empty?
119
119
  @connections.empty?
120
120
  end
121
-
121
+
122
122
  # Number of active connections.
123
123
  def size
124
124
  @connections.size
125
125
  end
126
-
126
+
127
+ # connection list.
128
+ def connections_list
129
+ @connections
130
+ end
131
+
127
132
  protected
128
133
  # Initialize a new connection to a client.
129
134
  def initialize_connection(connection)
@@ -131,7 +136,7 @@ module Thin
131
136
  connection.app = @server.app
132
137
  connection.comm_inactivity_timeout = @timeout
133
138
  connection.threaded = @threaded
134
-
139
+
135
140
  if @ssl
136
141
  connection.start_tls(@ssl_options)
137
142
  end
@@ -145,7 +150,7 @@ module Thin
145
150
 
146
151
  @connections << connection
147
152
  end
148
-
153
+
149
154
  end
150
155
  end
151
156
  end
@@ -3,7 +3,7 @@ require 'socket'
3
3
  module Thin
4
4
  # An exception class to handle the event that server didn't start on time
5
5
  class RestartTimeout < RuntimeError; end
6
-
6
+
7
7
  module Controllers
8
8
  # Control a set of servers.
9
9
  # * Generate start and stop commands and run them.
@@ -13,17 +13,17 @@ module Thin
13
13
  # Cluster only options that should not be passed in the command sent
14
14
  # to the indiviual servers.
15
15
  CLUSTER_OPTIONS = [:servers, :only, :onebyone, :wait]
16
-
16
+
17
17
  # Maximum wait time for the server to be restarted
18
18
  DEFAULT_WAIT_TIME = 30 # seconds
19
-
19
+
20
20
  # Create a new cluster of servers launched using +options+.
21
21
  def initialize(options)
22
22
  super
23
23
  # Cluster can only contain daemonized servers
24
24
  @options.merge!(:daemonize => true)
25
25
  end
26
-
26
+
27
27
  def first_port; @options[:port] end
28
28
  def address; @options[:address] end
29
29
  def socket; @options[:socket] end
@@ -33,35 +33,35 @@ module Thin
33
33
  def only; @options[:only] end
34
34
  def onebyone; @options[:onebyone] end
35
35
  def wait; @options[:wait] end
36
-
36
+
37
37
  def swiftiply?
38
38
  @options.has_key?(:swiftiply)
39
39
  end
40
-
40
+
41
41
  # Start the servers
42
42
  def start
43
43
  with_each_server { |n| start_server n }
44
44
  end
45
-
45
+
46
46
  # Start a single server
47
47
  def start_server(number)
48
48
  log "Starting server on #{server_id(number)} ... "
49
-
49
+
50
50
  run :start, number
51
51
  end
52
-
52
+
53
53
  # Stop the servers
54
54
  def stop
55
55
  with_each_server { |n| stop_server n }
56
56
  end
57
-
57
+
58
58
  # Stop a single server
59
59
  def stop_server(number)
60
60
  log "Stopping server on #{server_id(number)} ... "
61
-
61
+
62
62
  run :stop, number
63
63
  end
64
-
64
+
65
65
  # Stop and start the servers.
66
66
  def restart
67
67
  unless onebyone
@@ -70,7 +70,7 @@ module Thin
70
70
  sleep 0.1 # Let's breath a bit shall we ?
71
71
  start
72
72
  else
73
- with_each_server do |n|
73
+ with_each_server do |n|
74
74
  stop_server(n)
75
75
  sleep 0.1 # Let's breath a bit shall we ?
76
76
  start_server(n)
@@ -78,7 +78,7 @@ module Thin
78
78
  end
79
79
  end
80
80
  end
81
-
81
+
82
82
  def test_socket(number)
83
83
  if socket
84
84
  UNIXSocket.new(socket_for(number))
@@ -88,12 +88,12 @@ module Thin
88
88
  rescue
89
89
  nil
90
90
  end
91
-
91
+
92
92
  # Make sure the server is running before moving on to the next one.
93
93
  def wait_until_server_started(number)
94
94
  log "Waiting for server to start ..."
95
95
  STDOUT.flush # Need this to make sure user got the message
96
-
96
+
97
97
  tries = 0
98
98
  loop do
99
99
  if test_socket = test_socket(number)
@@ -109,7 +109,7 @@ module Thin
109
109
  end
110
110
  end
111
111
  end
112
-
112
+
113
113
  def server_id(number)
114
114
  if socket
115
115
  socket_for(number)
@@ -119,23 +119,23 @@ module Thin
119
119
  [address, number].join(':')
120
120
  end
121
121
  end
122
-
122
+
123
123
  def log_file_for(number)
124
124
  include_server_number log_file, number
125
125
  end
126
-
126
+
127
127
  def pid_file_for(number)
128
128
  include_server_number pid_file, number
129
129
  end
130
-
130
+
131
131
  def socket_for(number)
132
132
  include_server_number socket, number
133
133
  end
134
-
134
+
135
135
  def pid_for(number)
136
136
  File.read(pid_file_for(number)).chomp.to_i
137
137
  end
138
-
138
+
139
139
  private
140
140
  # Send the command to the +thin+ script
141
141
  def run(cmd, number)
@@ -150,10 +150,10 @@ module Thin
150
150
  end
151
151
  Command.run(cmd, cmd_options)
152
152
  end
153
-
153
+
154
154
  def with_each_server
155
155
  if only
156
- if first_port && only < 80
156
+ if first_port && only < 1024
157
157
  # interpret +only+ as a sequence number
158
158
  yield first_port + only
159
159
  else
@@ -166,7 +166,7 @@ module Thin
166
166
  size.times { |n| yield first_port + n }
167
167
  end
168
168
  end
169
-
169
+
170
170
  # Add the server port or number in the filename
171
171
  # so each instance get its own file
172
172
  def include_server_number(path, number)
@@ -16,7 +16,7 @@ end
16
16
  module Thin
17
17
  # Raised when the pid file already exist starting as a daemon.
18
18
  class PidFileExist < RuntimeError; end
19
-
19
+
20
20
  # Module included in classes that can be turned into a daemon.
21
21
  # Handle stuff like:
22
22
  # * storing the PID in a file
@@ -25,37 +25,37 @@ module Thin
25
25
  # * killing the process gracefully
26
26
  module Daemonizable
27
27
  attr_accessor :pid_file, :log_file
28
-
28
+
29
29
  def self.included(base)
30
30
  base.extend ClassMethods
31
31
  end
32
-
32
+
33
33
  def pid
34
- File.exist?(pid_file) ? open(pid_file).read.to_i : nil
34
+ File.exist?(pid_file) && !File.zero?(pid_file) ? open(pid_file).read.to_i : nil
35
35
  end
36
-
36
+
37
37
  # Turns the current script into a daemon process that detaches from the console.
38
38
  def daemonize
39
39
  raise PlatformNotSupported, 'Daemonizing is not supported on Windows' if Thin.win?
40
40
  raise ArgumentError, 'You must specify a pid_file to daemonize' unless @pid_file
41
-
41
+
42
42
  remove_stale_pid_file
43
-
43
+
44
44
  pwd = Dir.pwd # Current directory is changed during daemonization, so store it
45
-
45
+
46
46
  # HACK we need to create the directory before daemonization to prevent a bug under 1.9
47
47
  # ignoring all signals when the directory is created after daemonization.
48
48
  FileUtils.mkdir_p File.dirname(@pid_file)
49
49
  FileUtils.mkdir_p File.dirname(@log_file)
50
-
50
+
51
51
  Daemonize.daemonize(File.expand_path(@log_file), name)
52
-
52
+
53
53
  Dir.chdir(pwd)
54
-
54
+
55
55
  write_pid_file
56
56
 
57
57
  self.after_daemonize if self.respond_to? :after_daemonize
58
-
58
+
59
59
  at_exit do
60
60
  log ">> Exiting!"
61
61
  remove_pid_file
@@ -66,7 +66,7 @@ module Thin
66
66
  # to the specified user and group.
67
67
  def change_privilege(user, group=user)
68
68
  log ">> Changing process privilege to #{user}:#{group}"
69
-
69
+
70
70
  uid, gid = Process.euid, Process.egid
71
71
  target_uid = Etc.getpwnam(user).uid
72
72
  target_gid = Etc.getgrnam(group).gid
@@ -83,12 +83,12 @@ module Thin
83
83
  rescue Errno::EPERM => e
84
84
  log "Couldn't change user and group to #{user}:#{group}: #{e}"
85
85
  end
86
-
86
+
87
87
  # Register a proc to be called to restart the server.
88
88
  def on_restart(&block)
89
89
  @on_restart = block
90
90
  end
91
-
91
+
92
92
  # Restart the server.
93
93
  def restart
94
94
  if @on_restart
@@ -99,7 +99,7 @@ module Thin
99
99
  exit!
100
100
  end
101
101
  end
102
-
102
+
103
103
  module ClassMethods
104
104
  # Send a QUIT or INT (if timeout is +0+) signal the process which
105
105
  # PID is stored in +pid_file+.
@@ -112,12 +112,12 @@ module Thin
112
112
  send_signal('QUIT', pid_file, timeout)
113
113
  end
114
114
  end
115
-
115
+
116
116
  # Restart the server by sending HUP signal.
117
117
  def restart(pid_file)
118
118
  send_signal('HUP', pid_file)
119
119
  end
120
-
120
+
121
121
  # Send a +signal+ to the process which PID is stored in +pid_file+.
122
122
  def send_signal(signal, pid_file, timeout=60)
123
123
  if pid = read_pid_file(pid_file)
@@ -138,7 +138,7 @@ module Thin
138
138
  Logging.log "process not found!"
139
139
  force_kill pid_file
140
140
  end
141
-
141
+
142
142
  def force_kill(pid_file)
143
143
  if pid = read_pid_file(pid_file)
144
144
  Logging.log "Sending KILL signal to process #{pid} ... "
@@ -148,7 +148,7 @@ module Thin
148
148
  Logging.log "Can't stop process, no PID found in #{pid_file}"
149
149
  end
150
150
  end
151
-
151
+
152
152
  def read_pid_file(file)
153
153
  if File.file?(file) && pid = File.read(file)
154
154
  pid.to_i
@@ -157,18 +157,18 @@ module Thin
157
157
  end
158
158
  end
159
159
  end
160
-
160
+
161
161
  protected
162
162
  def remove_pid_file
163
163
  File.delete(@pid_file) if @pid_file && File.exists?(@pid_file)
164
164
  end
165
-
165
+
166
166
  def write_pid_file
167
167
  log ">> Writing PID to #{@pid_file}"
168
168
  open(@pid_file,"w") { |f| f.write(Process.pid) }
169
169
  File.chmod(0644, @pid_file)
170
170
  end
171
-
171
+
172
172
  # If PID file is stale, remove it.
173
173
  def remove_stale_pid_file
174
174
  if File.exist?(@pid_file)
data/lib/thin/server.rb CHANGED
@@ -12,7 +12,7 @@ module Thin
12
12
  # == UNIX domain server
13
13
  # Create a new UNIX domain socket bound to +socket+ file by specifiying a filename
14
14
  # as the first argument. Eg.: /tmp/thin.sock. If the first argument contains a <tt>/</tt>
15
- # it will be assumed to be a UNIX socket.
15
+ # it will be assumed to be a UNIX socket.
16
16
  #
17
17
  # Thin::Server.start('/tmp/thin.sock', app)
18
18
  #
@@ -30,7 +30,7 @@ module Thin
30
30
  # == Building an app in place
31
31
  # If a block is passed, a <tt>Rack::Builder</tt> instance
32
32
  # will be passed to build the +app+. So you can do cool stuff like this:
33
- #
33
+ #
34
34
  # Thin::Server.start('0.0.0.0', 3000) do
35
35
  # use Rack::CommonLogger
36
36
  # use Rack::ShowExceptions
@@ -44,19 +44,19 @@ module Thin
44
44
  # * QUIT: Gracefull shutdown (see Server#stop)
45
45
  # * INT and TERM: Force shutdown (see Server#stop!)
46
46
  # Disable signals by passing <tt>:signals => false</tt>
47
- #
47
+ #
48
48
  class Server
49
49
  include Logging
50
50
  include Daemonizable
51
51
  extend Forwardable
52
-
52
+
53
53
  # Default values
54
54
  DEFAULT_TIMEOUT = 30 #sec
55
55
  DEFAULT_HOST = '0.0.0.0'
56
56
  DEFAULT_PORT = 3000
57
57
  DEFAULT_MAXIMUM_CONNECTIONS = 1024
58
58
  DEFAULT_MAXIMUM_PERSISTENT_CONNECTIONS = 100
59
-
59
+
60
60
  # Application (Rack adapter) called with the request that produces the response.
61
61
  attr_accessor :app
62
62
 
@@ -65,38 +65,38 @@ module Thin
65
65
 
66
66
  # Backend handling the connections to the clients.
67
67
  attr_accessor :backend
68
-
68
+
69
69
  # Maximum number of seconds for incoming data to arrive before the connection
70
70
  # is dropped.
71
71
  def_delegators :backend, :timeout, :timeout=
72
-
72
+
73
73
  # Maximum number of file or socket descriptors that the server may open.
74
74
  def_delegators :backend, :maximum_connections, :maximum_connections=
75
-
75
+
76
76
  # Maximum number of connection that can be persistent at the same time.
77
77
  # Most browser never close the connection so most of the time they are closed
78
78
  # when the timeout occur. If we don't control the number of persistent connection,
79
79
  # if would be very easy to overflow the server for a DoS attack.
80
80
  def_delegators :backend, :maximum_persistent_connections, :maximum_persistent_connections=
81
-
81
+
82
82
  # Allow using threads in the backend.
83
83
  def_delegators :backend, :threaded?, :threaded=
84
-
84
+
85
85
  # Allow using SSL in the backend.
86
86
  def_delegators :backend, :ssl?, :ssl=, :ssl_options=
87
-
87
+
88
88
  # Address and port on which the server is listening for connections.
89
89
  def_delegators :backend, :host, :port
90
-
90
+
91
91
  # UNIX domain socket on which the server is listening for connections.
92
92
  def_delegator :backend, :socket
93
-
93
+
94
94
  # Disable the use of epoll under Linux
95
95
  def_delegators :backend, :no_epoll, :no_epoll=
96
-
96
+
97
97
  def initialize(*args, &block)
98
98
  host, port, options = DEFAULT_HOST, DEFAULT_PORT, {}
99
-
99
+
100
100
  # Guess each parameter by its type so they can be
101
101
  # received in any order.
102
102
  args.each do |arg|
@@ -108,58 +108,58 @@ module Thin
108
108
  @app = arg if arg.respond_to?(:call)
109
109
  end
110
110
  end
111
-
111
+
112
112
  # Set tag if needed
113
113
  self.tag = options[:tag]
114
114
 
115
115
  # Try to intelligently select which backend to use.
116
116
  @backend = select_backend(host, port, options)
117
-
117
+
118
118
  load_cgi_multipart_eof_fix
119
-
119
+
120
120
  @backend.server = self
121
-
121
+
122
122
  # Set defaults
123
123
  @backend.maximum_connections = DEFAULT_MAXIMUM_CONNECTIONS
124
124
  @backend.maximum_persistent_connections = DEFAULT_MAXIMUM_PERSISTENT_CONNECTIONS
125
125
  @backend.timeout = DEFAULT_TIMEOUT
126
-
126
+
127
127
  # Allow using Rack builder as a block
128
128
  @app = Rack::Builder.new(&block).to_app if block
129
-
129
+
130
130
  # If in debug mode, wrap in logger adapter
131
131
  @app = Rack::CommonLogger.new(@app) if Logging.debug?
132
-
132
+
133
133
  setup_signals unless options[:signals].class == FalseClass
134
134
  end
135
-
135
+
136
136
  # Lil' shortcut to turn this:
137
- #
137
+ #
138
138
  # Server.new(...).start
139
- #
139
+ #
140
140
  # into this:
141
- #
141
+ #
142
142
  # Server.start(...)
143
- #
143
+ #
144
144
  def self.start(*args, &block)
145
145
  new(*args, &block).start!
146
146
  end
147
-
147
+
148
148
  # Start the server and listen for connections.
149
149
  def start
150
150
  raise ArgumentError, 'app required' unless @app
151
-
151
+
152
152
  log ">> Thin web server (v#{VERSION::STRING} codename #{VERSION::CODENAME})"
153
153
  debug ">> Debugging ON"
154
154
  trace ">> Tracing ON"
155
-
155
+
156
156
  log ">> Maximum connections set to #{@backend.maximum_connections}"
157
157
  log ">> Listening on #{@backend}, CTRL+C to stop"
158
-
158
+
159
159
  @backend.start
160
160
  end
161
161
  alias :start! :start
162
-
162
+
163
163
  # == Gracefull shutdown
164
164
  # Stops the server after processing all current connections.
165
165
  # As soon as this method is called, the server stops accepting
@@ -176,7 +176,7 @@ module Thin
176
176
  stop!
177
177
  end
178
178
  end
179
-
179
+
180
180
  # == Force shutdown
181
181
  # Stops the server closing all current connections right away.
182
182
  # This doesn't wait for connection to finish their work and send data.
@@ -186,7 +186,7 @@ module Thin
186
186
 
187
187
  @backend.stop!
188
188
  end
189
-
189
+
190
190
  # == Reopen log file.
191
191
  # Reopen the log file and redirect STDOUT and STDERR to it.
192
192
  def reopen_log
@@ -195,39 +195,47 @@ module Thin
195
195
  log ">> Reopening log file: #{file}"
196
196
  Daemonize.redirect_io(file)
197
197
  end
198
-
198
+
199
199
  # == Configure the server
200
200
  # The process might need to have superuser privilege to configure
201
201
  # server with optimal options.
202
202
  def config
203
203
  @backend.config
204
204
  end
205
-
205
+
206
206
  # Name of the server and type of backend used.
207
207
  # This is also the name of the process in which Thin is running as a daemon.
208
208
  def name
209
209
  "thin server (#{@backend})" + (tag ? " [#{tag}]" : "")
210
210
  end
211
211
  alias :to_s :name
212
-
212
+
213
213
  # Return +true+ if the server is running and ready to receive requests.
214
214
  # Note that the server might still be running and return +false+ when
215
215
  # shuting down and waiting for active connections to complete.
216
216
  def running?
217
217
  @backend.running?
218
218
  end
219
-
219
+
220
220
  # deamonizing kills our HUP signal, so we set them again
221
221
  def after_daemonize
222
222
  setup_signals
223
223
  end
224
224
 
225
+ def print_status
226
+ puts "THIN_STATUS - '#{DateTime.now.to_s}' - '#{@backend.size}' - '#{@backend}' "
227
+ @backend.connections_list.each do |c|
228
+ puts "THIN_CONNECTION: #{c.request.env['REQUEST_METHOD']} #{c.request.env['REQUEST_URI']}" unless c.request.env['REQUEST_METHOD'].nil? || c.request.env['REQUEST_URI'].nil?
229
+ end
230
+ end
231
+
225
232
  protected
226
233
  # Register signals:
227
234
  # * TERM & QUIT calls +stop+ to shutdown gracefully.
228
235
  # * INT calls <tt>stop!</tt> to force shutdown.
229
236
  # * HUP calls <tt>restart</tt> to ... surprise, restart!
230
237
  # * USR1 reopen log files.
238
+ # * USR2 print status.
231
239
  def setup_signals
232
240
  trap('INT') { stop! }
233
241
  trap('TERM') { stop }
@@ -235,9 +243,10 @@ module Thin
235
243
  trap('QUIT') { stop }
236
244
  trap('HUP') { restart }
237
245
  trap('USR1') { reopen_log }
246
+ trap('USR2') { print_status }
238
247
  end
239
248
  end
240
-
249
+
241
250
  def select_backend(host, port, options)
242
251
  case
243
252
  when options.has_key?(:backend)
@@ -251,12 +260,12 @@ module Thin
251
260
  Backends::TcpServer.new(host, port)
252
261
  end
253
262
  end
254
-
263
+
255
264
  # Taken from Mongrel cgi_multipart_eof_fix
256
265
  # Ruby 1.8.5 has a security bug in cgi.rb, we need to patch it.
257
266
  def load_cgi_multipart_eof_fix
258
267
  version = RUBY_VERSION.split('.').map { |i| i.to_i }
259
-
268
+
260
269
  if version[0] <= 1 && version[1] <= 8 && version[2] <= 5 && RUBY_PLATFORM !~ /java/
261
270
  begin
262
271
  require 'cgi_multipart_eof_fix'
data/lib/thin/version.rb CHANGED
@@ -7,8 +7,9 @@ module Thin
7
7
  MAJOR = 1
8
8
  MINOR = 4
9
9
  TINY = 1
10
+ PATCH = 1
10
11
 
11
- STRING = [MAJOR, MINOR, TINY].join('.')
12
+ STRING = [MAJOR, MINOR, TINY, PATCH].join('.')
12
13
 
13
14
  CODENAME = "Chromeo".freeze
14
15
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: friendlyfashion-thin
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.1
4
+ version: 1.4.1.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2012-09-05 00:00:00.000000000 Z
15
+ date: 2012-10-24 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: rack
@@ -122,7 +122,7 @@ files:
122
122
  - ext/thin_parser/extconf.rb
123
123
  - ext/thin_parser/parser.rl
124
124
  - ext/thin_parser/common.rl
125
- homepage: http://code.macournoyer.com/thin/
125
+ homepage: https://github.com/friendlyfashion/thin
126
126
  licenses:
127
127
  - Ruby
128
128
  post_install_message: