racknga 0.9.2 → 0.9.4
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 +7 -0
- data/Gemfile +3 -12
- data/README.textile +9 -8
- data/Rakefile +19 -272
- data/doc/text/news.textile +20 -0
- data/lib/racknga/access_log_parser.rb +147 -0
- data/lib/racknga/api-keys.rb +40 -0
- data/lib/racknga/cache_database.rb +15 -5
- data/lib/racknga/exception_mail_notifier.rb +6 -6
- data/lib/racknga/log_database.rb +2 -1
- data/lib/racknga/log_entry.rb +85 -0
- data/lib/racknga/middleware/auth/api-key.rb +95 -0
- data/lib/racknga/middleware/cache.rb +22 -8
- data/lib/racknga/middleware/deflater.rb +13 -3
- data/lib/racknga/middleware/exception_notifier.rb +1 -2
- data/lib/racknga/middleware/instance_name.rb +92 -9
- data/lib/racknga/middleware/jsonp.rb +25 -5
- data/lib/racknga/middleware/log.rb +8 -3
- data/lib/racknga/middleware/nginx_raw_uri.rb +65 -0
- data/lib/racknga/middleware/range.rb +1 -1
- data/lib/racknga/reverse_line_reader.rb +1 -1
- data/lib/racknga/utils.rb +1 -1
- data/lib/racknga/version.rb +2 -2
- data/lib/racknga.rb +4 -2
- data/munin/plugins/passenger_application_ +61 -47
- data/munin/plugins/passenger_status +64 -33
- data/test/racknga-test-utils.rb +2 -1
- data/test/run-test.rb +1 -3
- data/test/{test-nginx-log-parser.rb → test-access-log-parser.rb} +115 -26
- data/test/test-api-keys.rb +80 -0
- data/test/test-middleware-auth-api-key.rb +144 -0
- data/test/test-middleware-cache.rb +1 -1
- data/test/test-middleware-instance-name.rb +50 -16
- data/test/test-middleware-jsonp.rb +14 -2
- data/test/test-middleware-nginx-raw-uri.rb +70 -0
- data/test/test-middleware-range.rb +1 -1
- metadata +159 -155
- data/lib/racknga/nginx_access_log_parser.rb +0 -139
- data/lib/racknga/will_paginate.rb +0 -48
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: cd550e89e845e0e90ccac2ef34bf3823e03639b0d61e71fe75ee02bb9ad63e2a
|
4
|
+
data.tar.gz: 4365f32450b7b0a9fc95b77cfbe3403119b8f2623824f3b4be199ec594255011
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a1d84e5281d56bd2f520d0483f1a9ba6cdd1dafbc363268e466b4fea860dd832892d7b5d84ec9ba6d38ebc74d5d356603e7857543ea21029a512fa0b1cd438ae
|
7
|
+
data.tar.gz: f983eab4c092d7d2215d2d52310ff51dc3568be0fb197444f4a5f0a8a7c36ef806cb45a2451b38636994d9fac6d53cda6ca07008d91f0d18557cf5f2d8ff0fc9
|
data/Gemfile
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# -*- mode: ruby; coding: utf-8 -*-
|
2
2
|
#
|
3
3
|
# Copyright (C) 2011 Kouhei Sutou <kou@clear-code.com>
|
4
|
+
# Copyright (C) 2013 Haruka Yoshihara <yoshihara@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
|
@@ -13,18 +14,8 @@
|
|
13
14
|
#
|
14
15
|
# You should have received a copy of the GNU Lesser General Public
|
15
16
|
# License along with this library; if not, write to the Free Software
|
16
|
-
# Foundation, Inc.,
|
17
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
17
18
|
|
18
19
|
source "http://rubygems.org/"
|
19
20
|
|
20
|
-
|
21
|
-
gem "rack"
|
22
|
-
|
23
|
-
group :development, :test do
|
24
|
-
gem "test-unit"
|
25
|
-
gem "test-unit-notify"
|
26
|
-
gem "test-unit-capybara"
|
27
|
-
gem "rake"
|
28
|
-
gem "jeweler"
|
29
|
-
gem "yard"
|
30
|
-
end
|
21
|
+
gemspec
|
data/README.textile
CHANGED
@@ -2,15 +2,15 @@ h1. README
|
|
2
2
|
|
3
3
|
h2. Name
|
4
4
|
|
5
|
-
|
5
|
+
Racknga
|
6
6
|
|
7
7
|
h2. Description
|
8
8
|
|
9
|
-
Rack middlewares that use
|
10
|
-
middlewares/utilities that don't use
|
9
|
+
Rack middlewares that use Rroonga features and
|
10
|
+
middlewares/utilities that don't use Rroonga features.
|
11
11
|
|
12
|
-
* "
|
13
|
-
* "Rack":http://rack.
|
12
|
+
* "Rroonga":http://ranguba.org/
|
13
|
+
* "Rack":http://rack.github.io/
|
14
14
|
|
15
15
|
h2. Authors
|
16
16
|
|
@@ -26,7 +26,7 @@ including contributed patches.)
|
|
26
26
|
h2. Dependencies
|
27
27
|
|
28
28
|
* Ruby >= 1.9.1
|
29
|
-
*
|
29
|
+
* Rroonga
|
30
30
|
* Rack
|
31
31
|
|
32
32
|
h2. Suggested libraries
|
@@ -41,11 +41,12 @@ h2. Install
|
|
41
41
|
|
42
42
|
h2. Documents
|
43
43
|
|
44
|
-
http://
|
44
|
+
http://ranguba.org/racknga/en/
|
45
45
|
|
46
46
|
h2. Mailing list
|
47
47
|
|
48
|
-
http://
|
48
|
+
* English: "groonga-talk":http://lists.sourceforge.net/mailman/listinfo/groonga-talk
|
49
|
+
* Japanese: "groonga-dev":http://lists.sourceforge.jp/mailman/listinfo/groonga-dev
|
49
50
|
|
50
51
|
h2. Thanks
|
51
52
|
|
data/Rakefile
CHANGED
@@ -13,7 +13,7 @@
|
|
13
13
|
#
|
14
14
|
# You should have received a copy of the GNU Lesser General Public
|
15
15
|
# License along with this library; if not, write to the Free Software
|
16
|
-
# Foundation, Inc.,
|
16
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
17
17
|
|
18
18
|
require 'English'
|
19
19
|
|
@@ -21,289 +21,36 @@ require 'fileutils'
|
|
21
21
|
require 'pathname'
|
22
22
|
require 'erb'
|
23
23
|
require 'rubygems'
|
24
|
-
require '
|
25
|
-
require
|
26
|
-
require "
|
24
|
+
require 'rubygems/package_task'
|
25
|
+
require 'bundler/gem_helper'
|
26
|
+
require "packnga"
|
27
27
|
|
28
28
|
base_dir = Pathname.new(__FILE__).dirname
|
29
29
|
racknga_lib_dir = base_dir + 'lib'
|
30
30
|
$LOAD_PATH.unshift(racknga_lib_dir.to_s)
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
32
|
+
helper = Bundler::GemHelper.new(base_dir)
|
33
|
+
def helper.version_tag
|
34
|
+
version
|
35
35
|
end
|
36
|
+
helper.install
|
37
|
+
spec = helper.gemspec
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
-
project = nil
|
40
|
-
spec = nil
|
41
|
-
Jeweler::Tasks.new do |_spec|
|
42
|
-
spec = _spec
|
43
|
-
spec.name = 'racknga'
|
44
|
-
spec.version = version
|
45
|
-
spec.rubyforge_project = 'groonga'
|
46
|
-
spec.homepage = "http://groonga.rubyforge.org/"
|
47
|
-
authors_file = File.join(base_dir, "AUTHORS")
|
48
|
-
authors = []
|
49
|
-
emails = []
|
50
|
-
File.readlines(authors_file).each do |line|
|
51
|
-
if /\s*<([^<>]*)>$/ =~ line
|
52
|
-
authors << $PREMATCH
|
53
|
-
emails << $1
|
54
|
-
end
|
55
|
-
end
|
56
|
-
spec.authors = authors
|
57
|
-
spec.email = emails
|
58
|
-
spec.summary = "A Rack middleware collection for rroonga features."
|
59
|
-
spec.description = <<-EOD.gsub(/\n/, ' ').strip
|
60
|
-
Racknga is a Rack middlewares that uses rroonga features.
|
61
|
-
EOD
|
62
|
-
spec.license = "LGPLv2.1 or later"
|
63
|
-
spec.files = FileList["lib/**/*.rb",
|
64
|
-
"{license,munin,doc/text/}/**/*",
|
65
|
-
"example/*.rb",
|
66
|
-
"AUTHORS",
|
67
|
-
"Rakefile",
|
68
|
-
"Gemfile",
|
69
|
-
"README*"]
|
70
|
-
spec.test_files = FileList["test/**/*.rb"]
|
39
|
+
Gem::PackageTask.new(spec) do |pkg|
|
40
|
+
pkg.need_tar_gz = true
|
71
41
|
end
|
72
42
|
|
73
|
-
|
74
|
-
|
43
|
+
Packnga::DocumentTask.new(spec) do |task|
|
44
|
+
task.original_language = "en"
|
45
|
+
task.translate_languages = ["ja"]
|
75
46
|
end
|
76
47
|
|
77
|
-
|
78
|
-
doc_en_dir = reference_base_dir + "en"
|
79
|
-
html_base_dir = Pathname.new("doc/html")
|
80
|
-
html_reference_dir = html_base_dir + spec.name
|
81
|
-
YARD::Rake::YardocTask.new do |task|
|
82
|
-
task.options += ["--title", spec.name]
|
83
|
-
task.options += ["--readme", "README.textile"]
|
84
|
-
task.options += ["--files", "doc/text/**/*"]
|
85
|
-
task.options += ["--output-dir", doc_en_dir.to_s]
|
86
|
-
task.options += ["--charset", "utf-8"]
|
48
|
+
Packnga::ReleaseTask.new(spec) do
|
87
49
|
end
|
88
50
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
html = path.read
|
93
|
-
html = html.gsub(/<div id="footer">.+<\/div>/m,
|
94
|
-
"<div id=\"footer\"></div>")
|
95
|
-
path.open("w") do |html_file|
|
96
|
-
html_file.print(html)
|
97
|
-
end
|
98
|
-
end
|
51
|
+
desc "Run test"
|
52
|
+
task :test do
|
53
|
+
ruby("-rubygems", "test/run-test.rb")
|
99
54
|
end
|
100
55
|
|
101
|
-
|
102
|
-
|
103
|
-
def apply_template(content, paths, templates, language)
|
104
|
-
content = content.sub(/lang="en"/, "lang=\"#{language}\"")
|
105
|
-
|
106
|
-
title = nil
|
107
|
-
content = content.sub(/<title>(.+?)<\/title>/m) do
|
108
|
-
title = $1
|
109
|
-
templates[:head].result(binding)
|
110
|
-
end
|
111
|
-
|
112
|
-
content = content.sub(/<body(?:.*?)>/) do |body_start|
|
113
|
-
"#{body_start}\n#{templates[:header].result(binding)}\n"
|
114
|
-
end
|
115
|
-
|
116
|
-
content = content.sub(/<\/body/) do |body_end|
|
117
|
-
"\n#{templates[:footer].result(binding)}\n#{body_end}"
|
118
|
-
end
|
119
|
-
|
120
|
-
content
|
121
|
-
end
|
122
|
-
|
123
|
-
def erb_template(name)
|
124
|
-
file = File.join("doc/templates", "#{name}.html.erb")
|
125
|
-
template = File.read(file)
|
126
|
-
erb = ERB.new(template, nil, "-")
|
127
|
-
erb.filename = file
|
128
|
-
erb
|
129
|
-
end
|
130
|
-
|
131
|
-
def rsync_to_rubyforge(spec, source, destination, options={})
|
132
|
-
config = YAML.load(File.read(File.expand_path("~/.rubyforge/user-config.yml")))
|
133
|
-
host = "#{config["username"]}@rubyforge.org"
|
134
|
-
|
135
|
-
rsync_args = "-av --exclude '*.erb' --chmod=ug+w"
|
136
|
-
rsync_args << " --delete" if options[:delete]
|
137
|
-
remote_dir = "/var/www/gforge-projects/#{spec.rubyforge_project}/"
|
138
|
-
sh("rsync #{rsync_args} #{source} #{host}:#{remote_dir}#{destination}")
|
139
|
-
end
|
140
|
-
|
141
|
-
def rake(*arguments)
|
142
|
-
ruby($0, *arguments)
|
143
|
-
end
|
144
|
-
|
145
|
-
namespace :reference do
|
146
|
-
translate_languages = [:ja]
|
147
|
-
supported_languages = [:en, *translate_languages]
|
148
|
-
html_files = FileList[doc_en_dir + "**/*.html"].to_a
|
149
|
-
|
150
|
-
directory reference_base_dir.to_s
|
151
|
-
CLOBBER.include(reference_base_dir.to_s)
|
152
|
-
|
153
|
-
po_dir = "doc/po"
|
154
|
-
pot_file = "#{po_dir}/#{spec.name}.pot"
|
155
|
-
namespace :pot do
|
156
|
-
directory po_dir
|
157
|
-
file pot_file => [po_dir, *html_files] do |t|
|
158
|
-
sh("xml2po", "--keep-entities", "--output", t.name, *html_files)
|
159
|
-
end
|
160
|
-
|
161
|
-
desc "Generates pot file."
|
162
|
-
task :generate => pot_file
|
163
|
-
end
|
164
|
-
|
165
|
-
namespace :po do
|
166
|
-
translate_languages.each do |language|
|
167
|
-
namespace language do
|
168
|
-
po_file = "#{po_dir}/#{language}.po"
|
169
|
-
|
170
|
-
if File.exist?(po_file)
|
171
|
-
file po_file => html_files do |t|
|
172
|
-
sh("xml2po", "--keep-entities", "--update", t.name, *html_files)
|
173
|
-
end
|
174
|
-
else
|
175
|
-
file po_file => pot_file do |t|
|
176
|
-
sh("msginit",
|
177
|
-
"--input=#{pot_file}",
|
178
|
-
"--output=#{t.name}",
|
179
|
-
"--locale=#{language}")
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
desc "Updates po file for #{language}."
|
184
|
-
task :update => po_file
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
desc "Updates po files."
|
189
|
-
task :update do
|
190
|
-
rake("clobber")
|
191
|
-
rake("yard")
|
192
|
-
translate_languages.each do |language|
|
193
|
-
rake("reference:po:#{language}:update")
|
194
|
-
end
|
195
|
-
end
|
196
|
-
end
|
197
|
-
|
198
|
-
namespace :translate do
|
199
|
-
translate_languages.each do |language|
|
200
|
-
po_file = "#{po_dir}/#{language}.po"
|
201
|
-
translate_doc_dir = "#{reference_base_dir}/#{language}"
|
202
|
-
|
203
|
-
desc "Translates documents to #{language}."
|
204
|
-
task language => [po_file, reference_base_dir, *html_files] do
|
205
|
-
doc_en_dir.find do |path|
|
206
|
-
base_path = path.relative_path_from(doc_en_dir)
|
207
|
-
translated_path = "#{translate_doc_dir}/#{base_path}"
|
208
|
-
if path.directory?
|
209
|
-
mkdir_p(translated_path)
|
210
|
-
next
|
211
|
-
end
|
212
|
-
case path.extname
|
213
|
-
when ".html"
|
214
|
-
sh("xml2po --keep-entities " +
|
215
|
-
"--po-file #{po_file} --language #{language} " +
|
216
|
-
"#{path} > #{translated_path}")
|
217
|
-
else
|
218
|
-
cp(path.to_s, translated_path, :preserve => true)
|
219
|
-
end
|
220
|
-
end
|
221
|
-
end
|
222
|
-
end
|
223
|
-
end
|
224
|
-
|
225
|
-
translate_task_names = translate_languages.collect do |language|
|
226
|
-
"reference:translate:#{language}"
|
227
|
-
end
|
228
|
-
desc "Translates references."
|
229
|
-
task :translate => translate_task_names
|
230
|
-
|
231
|
-
desc "Generates references."
|
232
|
-
task :generate => [:yard, :translate]
|
233
|
-
|
234
|
-
namespace :publication do
|
235
|
-
task :prepare do
|
236
|
-
supported_languages.each do |language|
|
237
|
-
raw_reference_dir = reference_base_dir + language.to_s
|
238
|
-
prepared_reference_dir = html_reference_dir + language.to_s
|
239
|
-
rm_rf(prepared_reference_dir.to_s)
|
240
|
-
head = erb_template("head.#{language}")
|
241
|
-
header = erb_template("header.#{language}")
|
242
|
-
footer = erb_template("footer.#{language}")
|
243
|
-
raw_reference_dir.find do |path|
|
244
|
-
relative_path = path.relative_path_from(raw_reference_dir)
|
245
|
-
prepared_path = prepared_reference_dir + relative_path
|
246
|
-
if path.directory?
|
247
|
-
mkdir_p(prepared_path.to_s)
|
248
|
-
else
|
249
|
-
case path.basename.to_s
|
250
|
-
when /(?:file|method|class)_list\.html\z/
|
251
|
-
cp(path.to_s, prepared_path.to_s)
|
252
|
-
when /\.html\z/
|
253
|
-
relative_dir_path = relative_path.dirname
|
254
|
-
current_path = relative_dir_path + path.basename
|
255
|
-
if current_path.basename.to_s == "index.html"
|
256
|
-
current_path = current_path.dirname
|
257
|
-
end
|
258
|
-
top_path = html_base_dir.relative_path_from(prepared_path.dirname)
|
259
|
-
package_path = top_path + spec.name
|
260
|
-
paths = {
|
261
|
-
:top => top_path,
|
262
|
-
:current => current_path,
|
263
|
-
:package => package_path,
|
264
|
-
}
|
265
|
-
templates = {
|
266
|
-
:head => head,
|
267
|
-
:header => header,
|
268
|
-
:footer => footer
|
269
|
-
}
|
270
|
-
content = apply_template(File.read(path.to_s),
|
271
|
-
paths,
|
272
|
-
templates,
|
273
|
-
language)
|
274
|
-
File.open(prepared_path.to_s, "w") do |file|
|
275
|
-
file.print(content)
|
276
|
-
end
|
277
|
-
else
|
278
|
-
cp(path.to_s, prepared_path.to_s)
|
279
|
-
end
|
280
|
-
end
|
281
|
-
end
|
282
|
-
end
|
283
|
-
File.open("#{html_reference_dir}/.htaccess", "w") do |file|
|
284
|
-
file.puts("RedirectMatch permanent ^/#{spec.name}/$ " +
|
285
|
-
"#{spec.homepage}#{spec.name}/en/")
|
286
|
-
end
|
287
|
-
end
|
288
|
-
end
|
289
|
-
|
290
|
-
desc "Upload document to rubyforge."
|
291
|
-
task :publish => [:generate, "reference:publication:prepare"] do
|
292
|
-
rsync_to_rubyforge(spec, "#{html_reference_dir}/", spec.name)
|
293
|
-
end
|
294
|
-
end
|
295
|
-
|
296
|
-
namespace :html do
|
297
|
-
desc "Publish HTML to Web site."
|
298
|
-
task :publish do
|
299
|
-
rsync_to_rubyforge(spec, "#{html_base_dir}/", "")
|
300
|
-
end
|
301
|
-
end
|
302
|
-
|
303
|
-
desc "Upload document to rubyforge."
|
304
|
-
task :publish => ["reference:publish"]
|
305
|
-
|
306
|
-
desc "Tag the current revision."
|
307
|
-
task :tag do
|
308
|
-
sh("git tag -a #{version} -m 'release #{version}!!!'")
|
309
|
-
end
|
56
|
+
task :default => :test
|
data/doc/text/news.textile
CHANGED
@@ -1,5 +1,25 @@
|
|
1
1
|
h1. NEWS
|
2
2
|
|
3
|
+
h2. 0.9.4: 2023-09-03
|
4
|
+
|
5
|
+
h3. Improvments
|
6
|
+
|
7
|
+
* [cache] Made Rroonga dependency optional. Users must add Rroonga
|
8
|
+
dependency explicitly.
|
9
|
+
* And more improvements...
|
10
|
+
|
11
|
+
h2. 0.9.3: 2011-11-12
|
12
|
+
|
13
|
+
h3. Improvments
|
14
|
+
|
15
|
+
* [access-log-parser] Supported Apache log.
|
16
|
+
* [cache] Fixed unknown name errors.
|
17
|
+
* [cache] Fixed max age.
|
18
|
+
* [nginx] Added NginxRawURI middleware.
|
19
|
+
* [instance-name] Added branch name and Ruby version.
|
20
|
+
* [exception-mail-notifier] Used #message instead of #to_s.
|
21
|
+
* [logger] Logged also X-Runtime.
|
22
|
+
|
3
23
|
h2. 0.9.2: 2011-08-07
|
4
24
|
|
5
25
|
h3. Improvments
|
@@ -0,0 +1,147 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Copyright (C) 2011 Ryo Onodera <onodera@clear-code.com>
|
4
|
+
# Copyright (C) 2011 Kouhei Sutou <kou@clear-code.com>
|
5
|
+
#
|
6
|
+
# This library is free software; you can redistribute it and/or
|
7
|
+
# modify it under the terms of the GNU Lesser General Public
|
8
|
+
# License as published by the Free Software Foundation; either
|
9
|
+
# version 2.1 of the License, or (at your option) any later version.
|
10
|
+
#
|
11
|
+
# This library is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14
|
+
# Lesser General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Lesser General Public
|
17
|
+
# License along with this library; if not, write to the Free Software
|
18
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
19
|
+
|
20
|
+
require "racknga/log_entry"
|
21
|
+
require "racknga/reverse_line_reader"
|
22
|
+
|
23
|
+
module Racknga
|
24
|
+
# Supported formats:
|
25
|
+
# * combined (nginx's default format)
|
26
|
+
# * combined (Apache's predefined format)
|
27
|
+
# * combined_with_time_nginx (custom format with runtime)
|
28
|
+
# * combined_with_time_apache (custom format with runtime)
|
29
|
+
#
|
30
|
+
# Configurations:
|
31
|
+
# * combined
|
32
|
+
# * nginx
|
33
|
+
# log_format combined '$remote_addr - $remote_user [$time_local] '
|
34
|
+
# '"$request" $status $body_bytes_sent '
|
35
|
+
# '"$http_referer" "$http_user_agent"';
|
36
|
+
# access_log log/access.log combined
|
37
|
+
# * Apache
|
38
|
+
# CustomLog ${APACHE_LOG_DIR}/access.log combined
|
39
|
+
#
|
40
|
+
# * combined_with_time_nginx
|
41
|
+
# * nginx
|
42
|
+
# log_format combined_with_time '$remote_addr - $remote_user '
|
43
|
+
# '[$time_local, $upstream_http_x_runtime, $request_time] '
|
44
|
+
# '"$request" $status $body_bytes_sent '
|
45
|
+
# '"$http_referer" "$http_user_agent"';
|
46
|
+
# access_log log/access.log combined_with_time
|
47
|
+
#
|
48
|
+
# * combined_with_time_apache
|
49
|
+
# * Apache
|
50
|
+
# LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\" %{X-Runtime}o %D" combined_with_time
|
51
|
+
# CustomLog ${APACHE_LOG_DIR}/access.log combined_with_time
|
52
|
+
class AccessLogParser
|
53
|
+
include Enumerable
|
54
|
+
|
55
|
+
class FormatError < StandardError
|
56
|
+
end
|
57
|
+
|
58
|
+
def initialize(line_reader)
|
59
|
+
@line_reader = line_reader
|
60
|
+
end
|
61
|
+
|
62
|
+
def each
|
63
|
+
@line_reader.each do |line|
|
64
|
+
line.force_encoding("UTF-8")
|
65
|
+
yield(parse_line(line)) if line.valid_encoding?
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
REMOTE_ADDRESS = "[^\\x20]+"
|
71
|
+
REMOTE_USER = "[^\\x20]+"
|
72
|
+
TIME_LOCAL = "[^\\x20]+\\x20\\+\\d{4}"
|
73
|
+
RUNTIME = "(?:[\\d.]+|-)"
|
74
|
+
REQUEST_TIME = "[\\d.]+"
|
75
|
+
REQUEST = ".*?"
|
76
|
+
STATUS = "\\d{3}"
|
77
|
+
BODY_BYTES_SENT = "(?:\\d+|-)"
|
78
|
+
HTTP_REFERER = ".*?"
|
79
|
+
HTTP_USER_AGENT = "(?:\\\"|[^\"])*?"
|
80
|
+
COMBINED_FORMAT =
|
81
|
+
/^(#{REMOTE_ADDRESS})\x20
|
82
|
+
-\x20
|
83
|
+
(#{REMOTE_USER})\x20
|
84
|
+
\[(#{TIME_LOCAL})(?:,\x20(.+))?\]\x20+
|
85
|
+
"(#{REQUEST})"\x20
|
86
|
+
(#{STATUS})\x20
|
87
|
+
(#{BODY_BYTES_SENT})\x20
|
88
|
+
"(#{HTTP_REFERER})"\x20
|
89
|
+
"(#{HTTP_USER_AGENT})"
|
90
|
+
(?:\x20(.+))?$/x
|
91
|
+
def parse_line(line)
|
92
|
+
case line
|
93
|
+
when COMBINED_FORMAT
|
94
|
+
last_match = Regexp.last_match
|
95
|
+
options = {}
|
96
|
+
options[:remote_address] = last_match[1]
|
97
|
+
options[:remote_user] = last_match[2]
|
98
|
+
options[:time_local] = parse_local_time(last_match[3])
|
99
|
+
if last_match[4]
|
100
|
+
if /\A(#{RUNTIME}), (#{REQUEST_TIME})\z/ =~ last_match[4]
|
101
|
+
time_match = Regexp.last_match
|
102
|
+
options[:runtime] = time_match[1]
|
103
|
+
options[:request_time] = time_match[2]
|
104
|
+
else
|
105
|
+
message = "expected 'RUNTIME, REQUEST_TIME' time format: " +
|
106
|
+
"<#{last_match[4]}>: <#{line}>"
|
107
|
+
raise FormatError.new(message)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
options[:request] = last_match[5]
|
111
|
+
options[:status] = last_match[6].to_i
|
112
|
+
options[:body_bytes_sent] = last_match[7]
|
113
|
+
options[:http_referer] = last_match[8]
|
114
|
+
options[:http_user_agent] = last_match[9]
|
115
|
+
if last_match[10]
|
116
|
+
if /\A(#{RUNTIME}) (#{REQUEST_TIME})\z/ =~ last_match[10]
|
117
|
+
time_match = Regexp.last_match
|
118
|
+
runtime = time_match[1]
|
119
|
+
request_time = time_match[2]
|
120
|
+
request_time = request_time.to_i * 0.000_001 if request_time
|
121
|
+
options[:runtime] = runtime
|
122
|
+
options[:request_time] = request_time
|
123
|
+
else
|
124
|
+
message = "expected 'RUNTIME REQUEST_TIME' time format: " +
|
125
|
+
"<#{last_match[10]}>: <#{line}>"
|
126
|
+
raise FormatError.new(message)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
LogEntry.new(options)
|
130
|
+
else
|
131
|
+
raise FormatError.new("unsupported format log entry: <#{line}>")
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def parse_local_time(token)
|
136
|
+
day, month, year, hour, minute, second, _time_zone = token.split(/[\/: ]/)
|
137
|
+
_ = _time_zone # FIXME: suppress a warning. :<
|
138
|
+
Time.local(year, month, day, hour, minute, second)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
class ReversedAccessLogParser < AccessLogParser
|
143
|
+
def initialize(line_reader)
|
144
|
+
@line_reader = ReverseLineReader.new(line_reader)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
@@ -0,0 +1,40 @@
|
|
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
|
+
# This is a store for API keys. It is used with
|
21
|
+
# Racknga::Middleware::Auth::APIKeys.
|
22
|
+
class APIKeys
|
23
|
+
# @param [String] query_parameter query parameter to specify an API key.
|
24
|
+
# @param [Array] api_keys stored API keys.
|
25
|
+
def initialize(query_parameter, api_keys)
|
26
|
+
@query_parameter = query_parameter
|
27
|
+
@api_keys = api_keys
|
28
|
+
end
|
29
|
+
|
30
|
+
# Checks whether stored API keys includes an API key in a request.
|
31
|
+
# @param [Hash] environment an environment for Rack.
|
32
|
+
# @return [Boolean] true if an API key is included, or false if not.
|
33
|
+
def include?(environment)
|
34
|
+
request = Rack::Request.new(environment)
|
35
|
+
key = request[@query_parameter]
|
36
|
+
|
37
|
+
@api_keys.include?(key)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
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.,
|
17
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
18
18
|
|
19
19
|
require 'fileutils'
|
20
20
|
|
@@ -53,17 +53,27 @@ module Racknga
|
|
53
53
|
# process from your Rack application
|
54
54
|
# process. (e.g. cron.) It's multi process safe.
|
55
55
|
def purge_old_responses
|
56
|
-
age_modulo = 2 **
|
56
|
+
age_modulo = 2 ** 31 - 1
|
57
57
|
age = configuration.age
|
58
58
|
previous_age = (age - 1).modulo(age_modulo)
|
59
|
-
|
59
|
+
next_age = (age + 1).modulo(age_modulo)
|
60
60
|
|
61
61
|
target_responses = responses.select do |record|
|
62
|
-
record.age ==
|
62
|
+
record.age == next_age
|
63
63
|
end
|
64
64
|
target_responses.each do |response|
|
65
65
|
response.key.delete
|
66
66
|
end
|
67
|
+
configuration.age = next_age
|
68
|
+
|
69
|
+
target_responses = responses.select do |record|
|
70
|
+
record.age <= previous_age
|
71
|
+
end
|
72
|
+
target_responses.each do |response|
|
73
|
+
response.key.delete
|
74
|
+
end
|
75
|
+
|
76
|
+
responses.defrag if responses.respond_to?(:defrag)
|
67
77
|
end
|
68
78
|
|
69
79
|
def ensure_database
|
@@ -88,7 +98,7 @@ module Racknga
|
|
88
98
|
:key_type => "ShortText") do |table|
|
89
99
|
table.uint32("status")
|
90
100
|
table.short_text("headers")
|
91
|
-
table.text("body"
|
101
|
+
table.text("body")
|
92
102
|
table.short_text("checksum")
|
93
103
|
table.uint32("age")
|
94
104
|
table.time("created_at")
|