merb 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/README +22 -4
- data/Rakefile +15 -3
- data/TODO +2 -3
- data/bin/merb +61 -36
- data/examples/sample_app/dist/app/controllers/files.rb +31 -0
- data/examples/sample_app/dist/app/controllers/posts.rb +26 -2
- data/examples/sample_app/dist/app/controllers/test.rb +7 -1
- data/examples/sample_app/dist/app/views/files/progress.jerb +3 -0
- data/examples/sample_app/dist/app/views/files/start.herb +62 -0
- data/examples/sample_app/dist/app/views/files/upload.herb +6 -0
- data/examples/sample_app/dist/app/views/layout/{application.rhtml → application.herb} +2 -3
- data/examples/sample_app/dist/app/views/layout/{foo.rhtml → foo.herb} +0 -0
- data/examples/sample_app/dist/app/views/posts/{_comments.rhtml → _comments.herb} +0 -0
- data/examples/sample_app/dist/app/views/posts/comment.jerb +1 -0
- data/examples/sample_app/dist/app/views/posts/{list.rhtml → list.herb} +0 -0
- data/examples/sample_app/dist/app/views/posts/{new.rhtml → new.herb} +0 -0
- data/examples/sample_app/dist/app/views/posts/{show.rhtml → show.herb} +0 -0
- data/examples/sample_app/dist/app/views/posts/xml_test.xerb +3 -0
- data/examples/sample_app/dist/app/views/test/{foo.rhtml → foo.herb} +0 -0
- data/examples/sample_app/dist/app/views/test/{hello.rhtml → hello.herb} +0 -0
- data/examples/sample_app/dist/app/views/test/json.jerb +1 -0
- data/examples/sample_app/dist/conf/merb.yml +11 -0
- data/examples/sample_app/dist/conf/merb_init.rb +1 -1
- data/examples/sample_app/dist/conf/mup.conf +11 -0
- data/examples/sample_app/dist/public/javascripts/mup.js +113 -0
- data/examples/sample_app/script/merb_stop +7 -3
- data/examples/sample_app/script/startdrb +8 -0
- data/lib/merb.rb +37 -2
- data/lib/merb/merb_class_extensions.rb +21 -22
- data/lib/merb/merb_controller.rb +101 -33
- data/lib/merb/merb_handler.rb +26 -25
- data/lib/merb/merb_router.rb +1 -1
- data/lib/merb/merb_utils.rb +35 -37
- data/lib/merb/mixins/basic_authentication_mixin.rb +39 -0
- data/lib/merb/mixins/controller_mixin.rb +119 -115
- data/lib/merb/mixins/javascript_mixin.rb +63 -0
- data/lib/merb/mixins/render_mixin.rb +85 -69
- data/lib/merb/mixins/responder_mixin.rb +38 -0
- data/lib/merb/session/merb_drb_server.rb +107 -0
- data/lib/merb/session/merb_drb_session.rb +71 -0
- data/lib/merb/session/merb_session.rb +1 -0
- data/lib/merb/vendor/paginator/README.txt +84 -0
- data/lib/merb/vendor/paginator/paginator.rb +121 -0
- data/lib/mutex_hotfix.rb +34 -0
- metadata +41 -63
- data/doc/rdoc/classes/ControllerMixin.html +0 -676
- data/doc/rdoc/classes/Hash.html +0 -148
- data/doc/rdoc/classes/Merb.html +0 -140
- data/doc/rdoc/classes/Merb/Controller.html +0 -338
- data/doc/rdoc/classes/Merb/RouteMatcher.html +0 -388
- data/doc/rdoc/classes/Merb/Server.html +0 -148
- data/doc/rdoc/classes/Merb/Session.html +0 -201
- data/doc/rdoc/classes/Merb/SessionMixin.html +0 -199
- data/doc/rdoc/classes/MerbControllerError.html +0 -111
- data/doc/rdoc/classes/MerbHandler.html +0 -430
- data/doc/rdoc/classes/MerbHash.html +0 -469
- data/doc/rdoc/classes/MerbHash/Mutex.html +0 -198
- data/doc/rdoc/classes/Noroutefound.html +0 -153
- data/doc/rdoc/classes/Object.html +0 -149
- data/doc/rdoc/classes/RenderMixin.html +0 -362
- data/doc/rdoc/classes/String.html +0 -212
- data/doc/rdoc/classes/Symbol.html +0 -179
- data/doc/rdoc/created.rid +0 -1
- data/doc/rdoc/files/LICENSE.html +0 -129
- data/doc/rdoc/files/README.html +0 -417
- data/doc/rdoc/files/TODO.html +0 -151
- data/doc/rdoc/files/lib/merb/merb_class_extensions_rb.html +0 -101
- data/doc/rdoc/files/lib/merb/merb_controller_rb.html +0 -101
- data/doc/rdoc/files/lib/merb/merb_handler_rb.html +0 -101
- data/doc/rdoc/files/lib/merb/merb_router_rb.html +0 -101
- data/doc/rdoc/files/lib/merb/merb_utils_rb.html +0 -108
- data/doc/rdoc/files/lib/merb/mixins/controller_mixin_rb.html +0 -101
- data/doc/rdoc/files/lib/merb/mixins/render_mixin_rb.html +0 -101
- data/doc/rdoc/files/lib/merb/session/merb_session_rb.html +0 -101
- data/doc/rdoc/files/lib/merb_rb.html +0 -140
- data/doc/rdoc/files/lib/merb_tasks_rb.html +0 -101
- data/doc/rdoc/fr_class_index.html +0 -43
- data/doc/rdoc/fr_file_index.html +0 -40
- data/doc/rdoc/fr_method_index.html +0 -104
- data/doc/rdoc/index.html +0 -24
- data/doc/rdoc/rdoc-style.css +0 -208
- data/examples/sample_app/dist/app/controllers/upload.rb +0 -29
- data/examples/sample_app/dist/app/views/posts/comment.merbjs +0 -1
- data/examples/sample_app/dist/app/views/upload/start.rhtml +0 -15
- data/examples/sample_app/dist/app/views/upload/upload.rhtml +0 -4
- data/examples/sample_app/dist/public/files/README +0 -35
- data/examples/sample_app/dist/public/files/setup.rb +0 -1346
- data/examples/sample_app/log/merb.log +0 -778
data/lib/merb/merb_handler.rb
CHANGED
@@ -25,6 +25,8 @@ class MerbHandler < Mongrel::HttpHandler
|
|
25
25
|
# and your controller can go on processing other requests.
|
26
26
|
def process(request, response)
|
27
27
|
|
28
|
+
start = Time.now
|
29
|
+
|
28
30
|
if response.socket.closed?
|
29
31
|
return
|
30
32
|
end
|
@@ -41,11 +43,10 @@ class MerbHandler < Mongrel::HttpHandler
|
|
41
43
|
if get_or_head and @files.can_serve(path_info)
|
42
44
|
# File exists as-is so serve it up
|
43
45
|
MERB_LOGGER.info("Serving static file: #{path_info}")
|
44
|
-
|
45
46
|
@files.process(request,response)
|
46
47
|
elsif get_or_head and @files.can_serve(page_cached)
|
47
48
|
# Possible cached page, serve it up
|
48
|
-
MERB_LOGGER.info("Serving static file: #{
|
49
|
+
MERB_LOGGER.info("Serving static file: #{page_cached}")
|
49
50
|
request.params[Mongrel::Const::PATH_INFO] = page_cached
|
50
51
|
@files.process(request,response)
|
51
52
|
else
|
@@ -53,14 +54,22 @@ class MerbHandler < Mongrel::HttpHandler
|
|
53
54
|
# This handles parsing the query string and post/file upload
|
54
55
|
# params and is outside of the synchronize call so that
|
55
56
|
# multiple file uploads can be done at once.
|
57
|
+
controller = nil
|
56
58
|
controller, action = handle(request)
|
57
|
-
MERB_LOGGER.info("Routing to controller: #{controller.class} action: #{action}")
|
58
|
-
|
59
|
-
#
|
60
|
-
#
|
61
|
-
|
62
|
-
|
63
|
-
|
59
|
+
MERB_LOGGER.info("Routing to controller: #{controller.class} action: #{action}\nParsing HTTP Input took: #{Time.now - start} seconds")
|
60
|
+
|
61
|
+
# special case allows the progress action of a Files controller
|
62
|
+
# to be handled without locking since no db access is required.
|
63
|
+
# but we do need to synchronize whenever you use ActiveRecord
|
64
|
+
# in your controllers.
|
65
|
+
if (action == 'progress') && (Files === controller)
|
66
|
+
puts 'skip mutex'
|
67
|
+
controller.dispatch(action)
|
68
|
+
else
|
69
|
+
@guard.synchronize {
|
70
|
+
controller.dispatch(action)
|
71
|
+
}
|
72
|
+
end
|
64
73
|
rescue Exception => e
|
65
74
|
response.start(500) do |head,out|
|
66
75
|
head["Content-Type"] = "text/html"
|
@@ -87,20 +96,18 @@ class MerbHandler < Mongrel::HttpHandler
|
|
87
96
|
end
|
88
97
|
end
|
89
98
|
|
90
|
-
controller = nil
|
91
|
-
|
92
99
|
if sendfile
|
93
|
-
MERB_LOGGER.info("X-SENDFILE: #{sendfile}")
|
100
|
+
MERB_LOGGER.info("X-SENDFILE: #{sendfile}\nComplete Request took: #{Time.now - start} seconds")
|
94
101
|
# send X-SENDFILE header to mongrel
|
95
102
|
response.send_status(File.size(sendfile))
|
96
103
|
response.send_header
|
97
104
|
response.send_file(sendfile)
|
98
105
|
else
|
99
|
-
MERB_LOGGER.info("Response status: #{response.status}\n\n")
|
106
|
+
MERB_LOGGER.info("Response status: #{response.status}\nComplete Request took: #{Time.now - start} seconds\n\n")
|
100
107
|
# render response from successful controller
|
101
|
-
response.send_status((
|
108
|
+
response.send_status((controller.body||='').length)
|
102
109
|
response.send_header
|
103
|
-
response.write(
|
110
|
+
response.write(controller.body)
|
104
111
|
end
|
105
112
|
end
|
106
113
|
end
|
@@ -114,14 +121,8 @@ class MerbHandler < Mongrel::HttpHandler
|
|
114
121
|
path = request.params[Mongrel::Const::PATH_INFO].sub(/\/+/, '/')
|
115
122
|
path = path[0..-2] if (path[-1] == ?/)
|
116
123
|
route = Merb::RouteMatcher.new.route_request(path)
|
117
|
-
|
118
|
-
|
119
|
-
[ instantiate_controller(route[:controller], request.body, request.params, route),
|
120
|
-
route[:action] ]
|
121
|
-
else
|
122
|
-
MERB_LOGGER.info("No Matching Route!")
|
123
|
-
["<html><body>Error: no route matches!</body></html>", nil]
|
124
|
-
end
|
124
|
+
[ instantiate_controller(route[:controller], request.body, request.params, route),
|
125
|
+
route[:action] ]
|
125
126
|
end
|
126
127
|
|
127
128
|
# take a controller class name string and reload or require
|
@@ -143,8 +144,8 @@ class MerbHandler < Mongrel::HttpHandler
|
|
143
144
|
|
144
145
|
# format exception message for browser display
|
145
146
|
def html_exception(e)
|
146
|
-
"<html><h2>Merb Error!</h2><p>#{ e.message } - (#{ e.class })\n" <<
|
147
|
-
"#{(e.backtrace or []).join('<br />')}</p></html>"
|
147
|
+
"<html><body><h2>Merb Error!</h2><p>#{ e.message } - (#{ e.class })\n" <<
|
148
|
+
"#{(e.backtrace or []).join('<br />')}</p></body></html>"
|
148
149
|
end
|
149
150
|
|
150
151
|
def exception(e)
|
data/lib/merb/merb_router.rb
CHANGED
@@ -59,7 +59,7 @@ module Merb
|
|
59
59
|
|
60
60
|
# compile each individual route into a when /.../
|
61
61
|
# component of the case statement. Takes /:sections
|
62
|
-
#
|
62
|
+
# of the route def that start with : and turns them
|
63
63
|
# into placeholders for whatever urls match against
|
64
64
|
# the route in question. Special case for the default
|
65
65
|
# /:controller/:action/:id route.
|
data/lib/merb/merb_utils.rb
CHANGED
@@ -4,7 +4,12 @@ class String
|
|
4
4
|
# :allow_reloading is set to true in the config
|
5
5
|
# file or command line options.
|
6
6
|
def import
|
7
|
-
Merb::Server.config[:allow_reloading]
|
7
|
+
if Merb::Server.config[:allow_reloading]
|
8
|
+
Object.send(:remove_const, self.camel_case.intern) rescue nil
|
9
|
+
load(self.snake_case + '.rb')
|
10
|
+
else
|
11
|
+
require(self.snake_case)
|
12
|
+
end
|
8
13
|
end
|
9
14
|
|
10
15
|
# "FooBar".snake_case #=> "foo_bar"
|
@@ -20,14 +25,40 @@ class String
|
|
20
25
|
words.map!{|w| w.downcase.sub(%r/^./){|c| c.upcase}}
|
21
26
|
words.join
|
22
27
|
end
|
28
|
+
|
29
|
+
# Concatenates a path
|
30
|
+
def /(o)
|
31
|
+
File.join(self, o.to_s)
|
32
|
+
end
|
23
33
|
|
24
34
|
end
|
25
35
|
|
36
|
+
|
37
|
+
module Enumerable
|
38
|
+
def injecting(s)
|
39
|
+
inject(s) do |k, i|
|
40
|
+
yield(k, i); k
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class Numeric
|
46
|
+
def to_currency( pre_symbol='$', thousands=',', decimal='.',
|
47
|
+
post_symbol=nil )
|
48
|
+
"#{pre_symbol}#{
|
49
|
+
( "%.2f" % self ).gsub(
|
50
|
+
/(\d)(?=(?:\d{3})+(?:$|\.))/,
|
51
|
+
"\\1#{thousands}"
|
52
|
+
)
|
53
|
+
}#{post_symbol}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
26
57
|
class Symbol
|
27
58
|
|
28
59
|
# faster Symbol#to_s to speed up routing.
|
29
60
|
def to_s
|
30
|
-
@str_rep
|
61
|
+
@str_rep ||= id2name.freeze
|
31
62
|
end
|
32
63
|
|
33
64
|
# ["foo", "bar"].map &:reverse #=> ['oof', 'rab']
|
@@ -107,8 +138,9 @@ class MerbHash < Hash
|
|
107
138
|
super(convert_key(key))
|
108
139
|
end
|
109
140
|
|
141
|
+
# allow merbhash.key to work the same as merbhash[key]
|
110
142
|
def method_missing(m,*a)
|
111
|
-
m.to_s
|
143
|
+
m.to_s =~ /=$/?self[$`]=a[0]:a==[]?self[m]:raise(NoMethodError,"#{m}")
|
112
144
|
end
|
113
145
|
|
114
146
|
protected
|
@@ -120,37 +152,3 @@ class MerbHash < Hash
|
|
120
152
|
end
|
121
153
|
end
|
122
154
|
|
123
|
-
require 'thread'
|
124
|
-
|
125
|
-
# monkey patch Mutex so it does not leak memory.
|
126
|
-
class Mutex
|
127
|
-
|
128
|
-
def lock
|
129
|
-
while (Thread.critical = true; @locked)
|
130
|
-
@waiting.unshift Thread.current
|
131
|
-
Thread.stop
|
132
|
-
end
|
133
|
-
@locked = true
|
134
|
-
Thread.critical = false
|
135
|
-
self
|
136
|
-
end
|
137
|
-
|
138
|
-
def unlock
|
139
|
-
return unless @locked
|
140
|
-
Thread.critical = true
|
141
|
-
@locked = false
|
142
|
-
begin
|
143
|
-
t = @waiting.pop
|
144
|
-
t.wakeup if t
|
145
|
-
rescue ThreadError
|
146
|
-
retry
|
147
|
-
end
|
148
|
-
Thread.critical = false
|
149
|
-
begin
|
150
|
-
t.run if t
|
151
|
-
rescue ThreadError
|
152
|
-
end
|
153
|
-
self
|
154
|
-
end
|
155
|
-
|
156
|
-
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Merb
|
2
|
+
|
3
|
+
module Authentication
|
4
|
+
require 'base64'
|
5
|
+
|
6
|
+
def credentials
|
7
|
+
if d = %w{REDIRECT_X_HTTP_AUTHORIZATION
|
8
|
+
X-HTTP_AUTHORIZATION HTTP_AUTHORIZATION}.
|
9
|
+
inject([]) { |d,h| @env.has_key?(h) ? @env[h].to_s.split : d }
|
10
|
+
return Base64.decode64(d[1]).split(':')[0..1] if d[0] == 'Basic'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def authenticated?
|
15
|
+
username, password = *credentials
|
16
|
+
username == Merb::Server.config[:basic_auth][:username] and password == Merb::Server.config[:basic_auth][:password]
|
17
|
+
end
|
18
|
+
|
19
|
+
def authenticate
|
20
|
+
if !authenticated?
|
21
|
+
throw :halt
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.included(base)
|
26
|
+
base.class_eval do
|
27
|
+
def filters_halted
|
28
|
+
@status = 401
|
29
|
+
@headers['Content-type'] = 'text/plain'
|
30
|
+
@headers['Status'] = 'Unauthorized'
|
31
|
+
@headers['WWW-Authenticate'] = "Basic realm=\"#{Merb::Server.config[:basic_auth][:domain]}\""
|
32
|
+
return 'Unauthorized'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -1,129 +1,133 @@
|
|
1
|
-
module
|
2
|
-
|
3
|
-
# redirect to another url It can be like /foo/bar
|
4
|
-
# for redirecting within your same app. Or it can
|
5
|
-
# be a fully qualified url to another site.
|
6
|
-
def redirect(url)
|
7
|
-
MERB_LOGGER.info("Redirecting to: #{url}")
|
8
|
-
@status = 302
|
9
|
-
@headers.merge!({'Location'=> url})
|
10
|
-
return ''
|
11
|
-
end
|
12
|
-
|
13
|
-
# pass in a path to a file and this will set the
|
14
|
-
# right headers and let mongrel do its thang and
|
15
|
-
# serve the static file directly.
|
16
|
-
def send_file(file)
|
17
|
-
headers['X-SENDFILE'] = file
|
18
|
-
return
|
19
|
-
end
|
1
|
+
module Merb
|
2
|
+
module ControllerMixin
|
20
3
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
# parses a query string or the payload of a POST
|
30
|
-
# request into the params hash. So for example:
|
31
|
-
# /foo?bar=nik&post[title]=heya&post[body]=whatever
|
32
|
-
# parses into:
|
33
|
-
# {:bar => 'nik', :post => {:title => 'heya', :body => 'whatever}}
|
34
|
-
def query_parse(qs, d = '&;')
|
35
|
-
m = proc {|_,o,n|o.u(n,&m)rescue([*o]<<n)}
|
36
|
-
(qs||'').split(/[#{d}] */n).inject(MerbHash[]) { |h,p|
|
37
|
-
k, v=unescape(p).split('=',2)
|
38
|
-
h.u(k.split(/[\]\[]+/).reverse.
|
39
|
-
inject(v) { |x,i| MerbHash[i,x] },&m)
|
40
|
-
}
|
41
|
-
end
|
42
|
-
|
43
|
-
# does url escaping
|
44
|
-
def escape(s)
|
45
|
-
Mongrel::HttpRequest.escape(s)
|
46
|
-
end
|
47
|
-
|
48
|
-
# does url unescaping
|
49
|
-
def unescape(s)
|
50
|
-
Mongrel::HttpRequest.unescape(s)
|
51
|
-
end
|
52
|
-
|
53
|
-
# escape text for javascript.
|
54
|
-
def escape_js(javascript)
|
55
|
-
(javascript || '').gsub('\\','\0\0').gsub(/\r\n|\n|\r/, "\\n").gsub(/["']/) { |m| "\\#{m}" }
|
56
|
-
end
|
57
|
-
alias js :escape_js
|
58
|
-
|
59
|
-
def xml_http_request?
|
60
|
-
not /XMLHttpRequest/i.match(@headers['HTTP_X_REQUESTED_WITH']).nil?
|
61
|
-
end
|
62
|
-
alias xhr? :xml_http_request?
|
63
|
-
alias ajax? :xml_http_request?
|
64
|
-
|
65
|
-
def remote_ip
|
66
|
-
return @headers['HTTP_CLIENT_IP'] if @headers.include?('HTTP_CLIENT_IP')
|
67
|
-
|
68
|
-
if @headers.include?('HTTP_X_FORWARDED_FOR') then
|
69
|
-
remote_ips = @headers['HTTP_X_FORWARDED_FOR'].split(',').reject do |ip|
|
70
|
-
ip =~ /^unknown$|^(127|10|172\.16|192\.168)\./i
|
71
|
-
end
|
72
|
-
|
73
|
-
return remote_ips.first.strip unless remote_ips.empty?
|
4
|
+
# redirect to another url It can be like /foo/bar
|
5
|
+
# for redirecting within your same app. Or it can
|
6
|
+
# be a fully qualified url to another site.
|
7
|
+
def redirect(url)
|
8
|
+
MERB_LOGGER.info("Redirecting to: #{url}")
|
9
|
+
@status = 302
|
10
|
+
headers.merge!({'Location'=> url})
|
11
|
+
return ''
|
74
12
|
end
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
13
|
+
|
14
|
+
# pass in a path to a file and this will set the
|
15
|
+
# right headers and let mongrel do its thang and
|
16
|
+
# serve the static file directly.
|
17
|
+
def send_file(file)
|
18
|
+
headers['X-SENDFILE'] = file
|
19
|
+
return
|
20
|
+
end
|
21
|
+
|
22
|
+
# This uses nginx X-Accel-Redirect header to send
|
23
|
+
# a file directly from nginx. See the nginx wiki:
|
24
|
+
# http://wiki.codemongers.com/NginxXSendfile
|
25
|
+
def nginx_send_file(file)
|
26
|
+
headers['X-Accel-Redirect'] = file
|
27
|
+
return
|
28
|
+
end
|
82
29
|
|
83
|
-
|
84
|
-
|
85
|
-
|
30
|
+
# parses a query string or the payload of a POST
|
31
|
+
# request into the params hash. So for example:
|
32
|
+
# /foo?bar=nik&post[title]=heya&post[body]=whatever
|
33
|
+
# parses into:
|
34
|
+
# {:bar => 'nik', :post => {:title => 'heya', :body => 'whatever}}
|
35
|
+
def query_parse(qs, d = '&;')
|
36
|
+
m = proc {|_,o,n|o.u(n,&m)rescue([*o]<<n)}
|
37
|
+
(qs||'').split(/[#{d}] */n).inject(MerbHash[]) { |h,p|
|
38
|
+
k, v=unescape(p).split('=',2)
|
39
|
+
h.u(k.split(/[\]\[]+/).reverse.
|
40
|
+
inject(v) { |x,i| MerbHash[i,x] },&m)
|
41
|
+
}
|
42
|
+
end
|
86
43
|
|
87
|
-
|
44
|
+
def make_token
|
45
|
+
require 'digest/md5'
|
46
|
+
Digest::MD5.hexdigest("#{inspect}#{Time.now}#{rand}")
|
47
|
+
end
|
88
48
|
|
89
|
-
|
90
|
-
|
91
|
-
|
49
|
+
# does url escaping
|
50
|
+
def escape(s)
|
51
|
+
Mongrel::HttpRequest.escape(s)
|
52
|
+
end
|
92
53
|
|
93
|
-
|
54
|
+
# does url unescaping
|
55
|
+
def unescape(s)
|
56
|
+
Mongrel::HttpRequest.unescape(s)
|
57
|
+
end
|
94
58
|
|
95
|
-
|
96
|
-
|
97
|
-
|
59
|
+
# returns true if the request is an ajax request.
|
60
|
+
def xml_http_request?
|
61
|
+
not /XMLHttpRequest/i.match(@env['HTTP_X_REQUESTED_WITH']).nil?
|
62
|
+
end
|
63
|
+
alias xhr? :xml_http_request?
|
64
|
+
alias ajax? :xml_http_request?
|
98
65
|
|
99
|
-
|
100
|
-
|
101
|
-
|
66
|
+
# returns the remote IP address if it can find it.
|
67
|
+
def remote_ip
|
68
|
+
return @env['HTTP_CLIENT_IP'] if @env.include?('HTTP_CLIENT_IP')
|
102
69
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
def host
|
108
|
-
@headers['HTTP_X_FORWARDED_HOST'] || @headers['HTTP_HOST']
|
109
|
-
end
|
70
|
+
if @env.include?(Mongrel::Const::HTTP_X_FORWARDED_FOR) then
|
71
|
+
remote_ips = @env[Mongrel::Const::HTTP_X_FORWARDED_FOR].split(',').reject do |ip|
|
72
|
+
ip =~ /^unknown$|^(127|10|172\.16|192\.168)\./i
|
73
|
+
end
|
110
74
|
|
111
|
-
|
112
|
-
|
113
|
-
parts[0..-(tld_length+2)]
|
114
|
-
end
|
75
|
+
return remote_ips.first.strip unless remote_ips.empty?
|
76
|
+
end
|
115
77
|
|
116
|
-
|
117
|
-
|
118
|
-
|
78
|
+
return @env[Mongrel::Const::REMOTE_ADDR]
|
79
|
+
end
|
80
|
+
|
81
|
+
# returns either 'https://' or 'http://' depending on
|
82
|
+
# the HTTPS header
|
83
|
+
def protocol
|
84
|
+
@env['HTTPS'] == 'on' ? 'https://' : 'http://'
|
85
|
+
end
|
86
|
+
|
87
|
+
# returns true if the request is an SSL request
|
88
|
+
def ssl?
|
89
|
+
@env['HTTPS'] == 'on'
|
90
|
+
end
|
91
|
+
|
92
|
+
# The request uri.
|
93
|
+
def uri
|
94
|
+
@env['REQUEST_URI']
|
95
|
+
end
|
96
|
+
|
97
|
+
# The path is the uri without the query string.
|
98
|
+
def path
|
99
|
+
uri ? uri.split('?').first : ''
|
100
|
+
end
|
119
101
|
|
120
|
-
|
121
|
-
|
122
|
-
|
102
|
+
def path_info
|
103
|
+
@env['PATH_INFO']
|
104
|
+
end
|
105
|
+
|
106
|
+
def port
|
107
|
+
@env['SERVER_PORT'].to_i
|
108
|
+
end
|
123
109
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
110
|
+
def host
|
111
|
+
@env['HTTP_X_FORWARDED_HOST'] || @env['HTTP_HOST']
|
112
|
+
end
|
113
|
+
|
114
|
+
def subdomains(tld_length = 1)
|
115
|
+
parts = host.split('.')
|
116
|
+
parts[0..-(tld_length+2)]
|
117
|
+
end
|
118
|
+
|
119
|
+
def domain(tld_length = 1)
|
120
|
+
host.split('.').last(1 + tld_length).join('.')
|
121
|
+
end
|
122
|
+
|
123
|
+
def method
|
124
|
+
@method ||= @env['REQUEST_METHOD']
|
125
|
+
end
|
126
|
+
|
127
|
+
[:get, :post, :put, :delete, :head].each do |m|
|
128
|
+
eval %{
|
129
|
+
def #{m}?; method == :#{m}; end
|
130
|
+
}
|
131
|
+
end
|
128
132
|
end
|
129
|
-
end
|
133
|
+
end
|