racknga 0.9.3 → 0.9.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +3 -12
  3. data/README.md +44 -0
  4. data/Rakefile +19 -272
  5. data/doc/text/{news.textile → news.md} +24 -7
  6. data/lib/racknga/access_log_parser.rb +1 -1
  7. data/lib/racknga/api-keys.rb +39 -0
  8. data/lib/racknga/cache_database.rb +2 -2
  9. data/lib/racknga/exception_mail_notifier.rb +18 -17
  10. data/lib/racknga/log_database.rb +1 -1
  11. data/lib/racknga/log_entry.rb +1 -1
  12. data/lib/racknga/middleware/auth/api-key.rb +95 -0
  13. data/lib/racknga/middleware/cache.rb +23 -11
  14. data/lib/racknga/middleware/deflater.rb +1 -1
  15. data/lib/racknga/middleware/exception_notifier.rb +1 -1
  16. data/lib/racknga/middleware/instance_name.rb +65 -12
  17. data/lib/racknga/middleware/jsonp.rb +26 -9
  18. data/lib/racknga/middleware/log.rb +1 -1
  19. data/lib/racknga/middleware/nginx_raw_uri.rb +1 -1
  20. data/lib/racknga/middleware/range.rb +4 -6
  21. data/lib/racknga/reverse_line_reader.rb +1 -1
  22. data/lib/racknga/utils.rb +1 -1
  23. data/lib/racknga/version.rb +3 -5
  24. data/lib/racknga.rb +2 -1
  25. data/munin/plugins/passenger_application_ +61 -47
  26. data/munin/plugins/passenger_status +64 -33
  27. data/test/racknga-test-utils.rb +2 -6
  28. data/test/run-test.rb +2 -5
  29. data/test/test-access-log-parser.rb +1 -1
  30. data/test/test-api-keys.rb +80 -0
  31. data/test/test-middleware-auth-api-key.rb +144 -0
  32. data/test/test-middleware-cache.rb +1 -1
  33. data/test/test-middleware-instance-name.rb +32 -10
  34. data/test/test-middleware-jsonp.rb +14 -2
  35. data/test/test-middleware-nginx-raw-uri.rb +1 -1
  36. data/test/test-middleware-range.rb +1 -1
  37. metadata +182 -157
  38. data/README.textile +0 -52
  39. data/lib/racknga/will_paginate.rb +0 -48
@@ -0,0 +1,95 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2012 Haruka Yoshihara <yoshihara@clear-code.com>
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License as published by the Free Software Foundation; either
8
+ # version 2.1 of the License, or (at your option) any later version.
9
+ #
10
+ # This library is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ # Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public
16
+ # License along with this library; if not, write to the Free Software
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+
19
+ module Racknga
20
+ module Middleware
21
+ module Auth
22
+ # This is a middleware that provides an authentication of API key.
23
+ # This middleware checks whether a URL requests API and
24
+ # whether API key in its request is authorized.
25
+ # When a URL requests API with unauthorized API key,
26
+ # this middleware returns json response with :error_message.
27
+ # Racknga::APIKeys is used as authorized API keys.
28
+ # Usage:
29
+ # require 'racknga'
30
+ #
31
+ # authorized_api_keys =
32
+ # Racknga::APIKeys.new("api-query-parameter", ["key1", "key2"])
33
+ # error_response =
34
+ # api_key_options = {
35
+ # :api_url_prefixes => ["/api"],
36
+ # :authorized_api_keys => authorized_api_keys,
37
+ # :error_response => {"error" => "this api key is not authorized"}
38
+ # }
39
+ # use Racknga::Middleware::Auth::APIKey, api_key_options
40
+ # run YourApplication
41
+ class APIKey
42
+ def initialize(application, options={})
43
+ @application = application
44
+ @authorized_api_keys = options[:authorized_api_keys]
45
+ url_prefixes_option = options[:api_url_prefixes]
46
+ @api_url_prefixes = url_prefixes_option.collect do |url|
47
+ /\A#{Regexp.escape(url)}/
48
+ end
49
+ @error_response = options[:error_response].to_json
50
+ @disable_authorization = options[:disable_authorization]
51
+ end
52
+
53
+ # For Rack.
54
+ def call(environment)
55
+ if api_url?(environment) and not authorized?(environment)
56
+ unauthorized_access_response
57
+ else
58
+ @application.call(environment)
59
+ end
60
+ end
61
+
62
+ private
63
+ def api_url?(environment)
64
+ @api_url_prefixes.any? do |prefix|
65
+ environment["PATH_INFO"] =~ prefix
66
+ end
67
+ end
68
+
69
+ def authorized?(environment)
70
+ if disable_authorization?
71
+ true
72
+ else
73
+ if @authorized_api_keys
74
+ @authorized_api_keys.include?(environment)
75
+ else
76
+ false
77
+ end
78
+ end
79
+ end
80
+
81
+ def disable_authorization?
82
+ @disable_authorization
83
+ end
84
+
85
+ def unauthorized_access_response
86
+ [
87
+ 401,
88
+ {"Content-Type" => "application/json; charset=utf-8"},
89
+ [@error_response],
90
+ ]
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -1,6 +1,4 @@
1
- # -*- coding: utf-8 -*-
2
- #
3
- # Copyright (C) 2010 Kouhei Sutou <kou@clear-code.com>
1
+ # Copyright (C) 2010-2024 Sutou Kouhei <kou@clear-code.com>
4
2
  #
5
3
  # This library is free software; you can redistribute it and/or
6
4
  # modify it under the terms of the GNU Lesser General Public
@@ -14,10 +12,11 @@
14
12
  #
15
13
  # You should have received a copy of the GNU Lesser General Public
16
14
  # License along with this library; if not, write to the Free Software
17
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
16
 
19
17
  require 'digest'
20
18
  require 'yaml'
19
+ require 'zlib'
21
20
  require 'racknga/cache_database'
22
21
 
23
22
  module Racknga
@@ -137,7 +136,7 @@ module Racknga
137
136
  def skip_caching_response?(status, headers, body)
138
137
  return true if status != 200
139
138
 
140
- headers = Rack::Utils::HeaderHash.new(headers)
139
+ headers = Rack::Headers[headers]
141
140
  content_type = headers["Content-Type"]
142
141
  if /\A(\w+)\/([\w.+\-]+)\b/ =~ content_type
143
142
  media_type = $1
@@ -166,15 +165,17 @@ module Racknga
166
165
  end
167
166
 
168
167
  now = Time.now
169
- headers = Rack::Utils::HeaderHash.new(headers)
168
+ headers = Rack::Headers[headers]
170
169
  headers["Last-Modified"] ||= now.httpdate
171
- stringified_body = ''
170
+ encoded_body = ''.force_encoding("ASCII-8BIT")
171
+ deflater = ::Zlib::Deflate.new
172
172
  body.each do |data|
173
- stringified_body << data
173
+ encoded_body << deflater.deflate(data)
174
174
  end
175
+ body.close if body.respond_to?(:close)
176
+ encoded_body << deflater.finish
175
177
  headers = headers.to_hash
176
178
  encoded_headers = headers.to_yaml
177
- encoded_body = stringified_body.force_encoding("ASCII-8BIT")
178
179
  cache[key] = {
179
180
  :status => status,
180
181
  :headers => encoded_headers,
@@ -183,7 +184,7 @@ module Racknga
183
184
  :age => age,
184
185
  :created_at => now,
185
186
  }
186
- body = [stringified_body]
187
+ body = Inflater.new(encoded_body)
187
188
  log("store", request)
188
189
  [status, headers, body]
189
190
  end
@@ -199,7 +200,7 @@ module Racknga
199
200
  end
200
201
 
201
202
  log("hit", request)
202
- [status, YAML.load(headers), [body]]
203
+ [status, YAML.load(headers), Inflater.new(body)]
203
204
  end
204
205
 
205
206
  def compute_checksum(status, encoded_headers, encoded_body)
@@ -227,6 +228,17 @@ module Racknga
227
228
  runtime = Time.now - start_time
228
229
  logger.log("cache-#{tag}", request.fullpath, :runtime => runtime)
229
230
  end
231
+
232
+ # @private
233
+ class Inflater
234
+ def initialize(deflated_string)
235
+ @deflated_string = deflated_string
236
+ end
237
+
238
+ def each
239
+ yield ::Zlib::Inflate.inflate(@deflated_string)
240
+ end
241
+ end
230
242
  end
231
243
  end
232
244
  end
@@ -14,7 +14,7 @@
14
14
  #
15
15
  # You should have received a copy of the GNU Lesser General Public
16
16
  # License along with this library; if not, write to the Free Software
17
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
18
 
19
19
  module Racknga
20
20
  module Middleware
@@ -14,7 +14,7 @@
14
14
  #
15
15
  # You should have received a copy of the GNU Lesser General Public
16
16
  # License along with this library; if not, write to the Free Software
17
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
18
 
19
19
  require 'racknga/exception_mail_notifier'
20
20
 
@@ -1,6 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  #
3
3
  # Copyright (C) 2011 Ryo Onodera <onodera@clear-code.com>
4
+ # Copyright (C) 2012 Kouhei Sutou <kou@clear-code.com>
4
5
  #
5
6
  # This library is free software; you can redistribute it and/or
6
7
  # modify it under the terms of the GNU Lesser General Public
@@ -14,7 +15,7 @@
14
15
  #
15
16
  # You should have received a copy of the GNU Lesser General Public
16
17
  # License along with this library; if not, write to the Free Software
17
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19
 
19
20
  module Racknga
20
21
  module Middleware
@@ -23,12 +24,18 @@ module Racknga
23
24
  # server when your Rack applications are deployed behind
24
25
  # load balancers.
25
26
  #
26
- # Usage:
27
+ # @example A simple usage
27
28
  # require "racknga"
28
29
  # use Racknga::Middleware::InstanceName
29
30
  # run YourApplication
30
31
  class InstanceName
31
32
  attr_reader :header
33
+ # @param [application] application rack application.
34
+ # @param [Hash] options options to create header.
35
+ # @option options [String] :header_name ("Responsed-By") header name.
36
+ # @option options [String] :application_name (application.class.name)
37
+ # application name.
38
+ # @option options [Integer] :version application version.
32
39
  def initialize(application, options={})
33
40
  @application = application
34
41
  @options = options
@@ -57,7 +64,14 @@ module Racknga
57
64
  end
58
65
 
59
66
  def revision
60
- `git describe --abbrev=7 HEAD`.strip # XXX be SCM-agonostic
67
+ case using_scm_name
68
+ when :git
69
+ `git describe --abbrev=7 HEAD`.strip
70
+ when :subversion
71
+ `LANG=C svn info | grep Revision`.strip
72
+ else
73
+ nil
74
+ end
61
75
  end
62
76
 
63
77
  def server
@@ -68,17 +82,15 @@ module Racknga
68
82
  `id --user --name`.strip
69
83
  end
70
84
 
71
- CURRENT_BRANCH_MARKER = /\A\* /
72
85
  def branch
73
- current_branch = nil
74
- `git branch -a`.each_line do |line|
75
- case line
76
- when CURRENT_BRANCH_MARKER
77
- current_branch = line.sub(CURRENT_BRANCH_MARKER, "").strip
78
- break
79
- end
86
+ case using_scm_name
87
+ when :git
88
+ git_branch_name
89
+ when :subversion
90
+ subversion_branch_name
91
+ else
92
+ nil
80
93
  end
81
- current_branch
82
94
  end
83
95
 
84
96
  def ruby
@@ -159,6 +171,47 @@ module Racknga
159
171
  nil
160
172
  end
161
173
  end
174
+
175
+ SVN_URL_KEY = /\AURL:.*/
176
+ SVN_REPOSITORY_ROOT_KEY = /\ARepository Root:.*/
177
+ SVN_KEY = /\A.*:/
178
+ SVN_BRANCHES_NAME = /\A\/branches\//
179
+ def subversion_branch_name
180
+ url = ""
181
+ repository_root = ""
182
+
183
+ `LANG=C svn info`.each_line do |line|
184
+ case line
185
+ when SVN_URL_KEY
186
+ url = line.sub(SVN_KEY, "").strip
187
+ when SVN_REPOSITORY_ROOT_KEY
188
+ repository_root = line.sub(SVN_KEY, "").strip
189
+ end
190
+ end
191
+ base_path = url.sub(/#{Regexp.escape(repository_root)}/, "")
192
+ base_path.sub(SVN_BRANCHES_NAME, "")
193
+ end
194
+
195
+ GIT_CURRENT_BRANCH_MARKER = /\A\* /
196
+ def git_branch_name
197
+ `git branch -a`.each_line do |line|
198
+ case line
199
+ when GIT_CURRENT_BRANCH_MARKER
200
+ return line.sub(GIT_CURRENT_BRANCH_MARKER, "").strip
201
+ end
202
+ end
203
+ nil
204
+ end
205
+
206
+ def using_scm_name
207
+ if File.exist?(".git")
208
+ :git
209
+ elsif File.exist?(".svn")
210
+ :subversion
211
+ else
212
+ nil
213
+ end
214
+ end
162
215
  end
163
216
  end
164
217
  end
@@ -1,6 +1,4 @@
1
- # -*- coding: utf-8 -*-
2
- #
3
- # Copyright (C) 2010 Kouhei Sutou <kou@clear-code.com>
1
+ # Copyright (C) 2010-2024 Sutou Kouhei <kou@clear-code.com>
4
2
  #
5
3
  # This library is free software; you can redistribute it and/or
6
4
  # modify it under the terms of the GNU Lesser General Public
@@ -14,7 +12,7 @@
14
12
  #
15
13
  # You should have received a copy of the GNU Lesser General Public
16
14
  # License along with this library; if not, write to the Free Software
17
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
16
 
19
17
  module Racknga
20
18
  module Middleware
@@ -84,14 +82,14 @@ module Racknga
84
82
  # For Rack.
85
83
  def call(environment)
86
84
  request = Rack::Request.new(environment)
87
- callback = request["callback"]
85
+ callback = request.params["callback"]
88
86
  update_cache_key(request) if callback
89
87
  status, headers, body = @application.call(environment)
90
88
  return [status, headers, body] unless callback
91
- header_hash = Rack::Utils::HeaderHash.new(headers)
89
+ header_hash = Rack::Headers[headers]
92
90
  return [status, headers, body] unless json_response?(header_hash)
93
91
  body = Writer.new(callback, body)
94
- update_content_type(header_hash)
92
+ update_header_hash(header_hash, body)
95
93
  [status, header_hash, body]
96
94
  end
97
95
 
@@ -122,6 +120,11 @@ module Racknga
122
120
  media_type == "text/javascript"
123
121
  end
124
122
 
123
+ def update_header_hash(header_hash, body)
124
+ update_content_type(header_hash)
125
+ update_content_length(header_hash, body)
126
+ end
127
+
125
128
  def update_content_type(header_hash)
126
129
  content_type = header_hash["Content-Type"]
127
130
  media_type, parameters = content_type.split(/\s*;\s*/, 2)
@@ -132,17 +135,31 @@ module Racknga
132
135
  header_hash["Content-Type"] = updated_content_type
133
136
  end
134
137
 
138
+ def update_content_length(header_hash, body)
139
+ return unless header_hash["Content-Length"]
140
+
141
+ content_length = header_hash["Content-Length"].to_i
142
+ updated_content_length = content_length + body.additional_content_length
143
+ header_hash["Content-Length"] = updated_content_length.to_s
144
+ end
145
+
135
146
  # @private
136
147
  class Writer
137
148
  def initialize(callback, body)
138
149
  @callback = callback
139
150
  @body = body
151
+ @header = "#{@callback}("
152
+ @footer = ");"
140
153
  end
141
154
 
142
155
  def each(&block)
143
- block.call("#{@callback}(")
156
+ block.call(@header)
144
157
  @body.each(&block)
145
- block.call(");")
158
+ block.call(@footer)
159
+ end
160
+
161
+ def additional_content_length
162
+ @header.bytesize + @footer.bytesize
146
163
  end
147
164
  end
148
165
  end
@@ -14,7 +14,7 @@
14
14
  #
15
15
  # You should have received a copy of the GNU Lesser General Public
16
16
  # License along with this library; if not, write to the Free Software
17
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
18
 
19
19
  require 'racknga/log_database'
20
20
 
@@ -14,7 +14,7 @@
14
14
  #
15
15
  # You should have received a copy of the GNU Lesser General Public
16
16
  # License along with this library; if not, write to the Free Software
17
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
18
 
19
19
  module Racknga
20
20
  module Middleware
@@ -1,6 +1,4 @@
1
- # -*- coding: utf-8 -*-
2
- #
3
- # Copyright (C) 2010 Kouhei Sutou <kou@clear-code.com>
1
+ # Copyright (C) 2010-2024 Sutou Kouhei <kou@clear-code.com>
4
2
  #
5
3
  # This library is free software; you can redistribute it and/or
6
4
  # modify it under the terms of the GNU Lesser General Public
@@ -14,7 +12,7 @@
14
12
  #
15
13
  # You should have received a copy of the GNU Lesser General Public
16
14
  # License along with this library; if not, write to the Free Software
17
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
16
 
19
17
  require 'time'
20
18
 
@@ -38,7 +36,7 @@ module Racknga
38
36
  status, headers, body = @application.call(environment)
39
37
  return [status, headers, body] if status != 200
40
38
 
41
- headers = Rack::Utils::HeaderHash.new(headers)
39
+ headers = Rack::Headers[headers]
42
40
  headers["Accept-Ranges"] = "bytes"
43
41
  request = Rack::Request.new(environment)
44
42
  range = request.env["HTTP_RANGE"]
@@ -60,7 +58,7 @@ module Racknga
60
58
 
61
59
  if first_byte.empty? and last_byte.empty?
62
60
  headers["Content-Length"] = "0"
63
- return [Rack::Utils.status_code(:requested_range_not_satisfiable),
61
+ return [Rack::Utils.status_code(:range_not_satisfiable),
64
62
  headers,
65
63
  []]
66
64
  end
@@ -14,7 +14,7 @@
14
14
  #
15
15
  # You should have received a copy of the GNU Lesser General Public
16
16
  # License along with this library; if not, write to the Free Software
17
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
18
 
19
19
  module Racknga
20
20
  class ReverseLineReader
data/lib/racknga/utils.rb CHANGED
@@ -14,7 +14,7 @@
14
14
  #
15
15
  # You should have received a copy of the GNU Lesser General Public
16
16
  # License along with this library; if not, write to the Free Software
17
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
18
 
19
19
  module Racknga
20
20
  module Utils
@@ -1,6 +1,4 @@
1
- # -*- coding: utf-8 -*-
2
- #
3
- # Copyright (C) 2010-2011 Kouhei Sutou <kou@clear-code.com>
1
+ # Copyright (C) 2010-2023 Sutou Kouhei <kou@clear-code.com>
4
2
  #
5
3
  # This library is free software; you can redistribute it and/or
6
4
  # modify it under the terms of the GNU Lesser General Public
@@ -14,8 +12,8 @@
14
12
  #
15
13
  # You should have received a copy of the GNU Lesser General Public
16
14
  # License along with this library; if not, write to the Free Software
17
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
16
 
19
17
  module Racknga
20
- VERSION = '0.9.3'
18
+ VERSION = "0.9.5"
21
19
  end
data/lib/racknga.rb CHANGED
@@ -14,13 +14,14 @@
14
14
  #
15
15
  # You should have received a copy of the GNU Lesser General Public
16
16
  # License along with this library; if not, write to the Free Software
17
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
18
 
19
19
  require 'rack'
20
20
 
21
21
  require 'racknga/version'
22
22
  require 'racknga/utils'
23
23
  require "racknga/access_log_parser"
24
+ require 'racknga/api-keys'
24
25
  require 'racknga/middleware/deflater'
25
26
  require 'racknga/middleware/exception_notifier'
26
27
  require 'racknga/middleware/jsonp'