racknga 0.9.3 → 0.9.5

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.
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'