Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
张重言
rails
提交
19208e74
R
rails
项目概览
张重言
/
rails
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
rails
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
19208e74
编写于
12月 29, 2008
作者:
M
Michael S. Klishin
浏览文件
操作
浏览文件
下载
差异文件
Pull up some other changes from rails/rails/master
上级
bdba0b9a
45dee384
变更
7
隐藏空白更改
内联
并排
Showing
7 changed file
with
476 addition
and
11 deletion
+476
-11
actionpack/lib/action_controller/http_authentication.rb
actionpack/lib/action_controller/http_authentication.rb
+189
-2
actionpack/lib/action_controller/integration.rb
actionpack/lib/action_controller/integration.rb
+82
-0
actionpack/test/controller/http_digest_authentication_test.rb
...onpack/test/controller/http_digest_authentication_test.rb
+73
-0
actionpack/test/controller/integration_test.rb
actionpack/test/controller/integration_test.rb
+88
-0
activesupport/lib/active_support/callbacks.rb
activesupport/lib/active_support/callbacks.rb
+2
-7
activesupport/test/callbacks_test.rb
activesupport/test/callbacks_test.rb
+41
-1
railties/lib/rails_generator/commands.rb
railties/lib/rails_generator/commands.rb
+1
-1
未找到文件。
actionpack/lib/action_controller/http_authentication.rb
浏览文件 @
19208e74
...
...
@@ -55,7 +55,31 @@ module HttpAuthentication
# end
# end
#
#
# Simple Digest example. Note the block must return the user's password so the framework
# can appropriately hash it to check the user's credentials. Returning nil will cause authentication to fail.
#
# class PostsController < ApplicationController
# Users = {"dhh" => "secret"}
#
# before_filter :authenticate, :except => [ :index ]
#
# def index
# render :text => "Everyone can see me!"
# end
#
# def edit
# render :text => "I'm only accessible if you know the password"
# end
#
# private
# def authenticate
# authenticate_or_request_with_http_digest(realm) do |user_name|
# Users[user_name]
# end
# end
# end
#
#
# In your integration tests, you can do something like this:
#
# def test_access_granted_from_xml
...
...
@@ -108,7 +132,10 @@ def authorization(request)
end
def
decode_credentials
(
request
)
ActiveSupport
::
Base64
.
decode64
(
authorization
(
request
).
split
.
last
||
''
)
# Properly decode credentials spanning a new-line
auth
=
authorization
(
request
)
auth
.
slice!
(
'Basic '
)
ActiveSupport
::
Base64
.
decode64
(
auth
||
''
)
end
def
encode_credentials
(
user_name
,
password
)
...
...
@@ -120,5 +147,165 @@ def authentication_request(controller, realm)
controller
.
__send__
:render
,
:text
=>
"HTTP Basic: Access denied.
\n
"
,
:status
=>
:unauthorized
end
end
module
Digest
extend
self
module
ControllerMethods
def
authenticate_or_request_with_http_digest
(
realm
=
"Application"
,
&
password_procedure
)
begin
authenticate_with_http_digest!
(
realm
,
&
password_procedure
)
rescue
ActionController
::
HttpAuthentication
::
Error
=>
e
msg
=
e
.
message
msg
=
"
#{
msg
}
expected '
#{
e
.
expected
}
' was '
#{
e
.
was
}
'"
unless
e
.
expected
.
nil?
raise
msg
if
e
.
fatal?
request_http_digest_authentication
(
realm
,
msg
)
end
end
# Authenticate using HTTP Digest, throwing ActionController::HttpAuthentication::Error on failure.
# This allows more detailed analysis of authentication failures
# to be relayed to the client.
def
authenticate_with_http_digest!
(
realm
=
"Application"
,
&
login_procedure
)
HttpAuthentication
::
Digest
.
authenticate
(
self
,
realm
,
&
login_procedure
)
end
# Authenticate with HTTP Digest, returns true or false
def
authenticate_with_http_digest
(
realm
=
"Application"
,
&
login_procedure
)
HttpAuthentication
::
Digest
.
authenticate
(
self
,
realm
,
&
login_procedure
)
rescue
false
end
# Render output including the HTTP Digest authentication header
def
request_http_digest_authentication
(
realm
=
"Application"
,
message
=
nil
)
HttpAuthentication
::
Digest
.
authentication_request
(
self
,
realm
,
message
)
end
# Add HTTP Digest authentication header to result headers
def
http_digest_authentication_header
(
realm
=
"Application"
)
HttpAuthentication
::
Digest
.
authentication_header
(
self
,
realm
)
end
end
# Raises error unless authentictaion succeeds, returns true otherwise
def
authenticate
(
controller
,
realm
,
&
password_procedure
)
raise
Error
.
new
(
false
),
"No authorization header found"
unless
authorization
(
controller
.
request
)
validate_digest_response
(
controller
,
realm
,
&
password_procedure
)
true
end
def
authorization
(
request
)
request
.
env
[
'HTTP_AUTHORIZATION'
]
||
request
.
env
[
'X-HTTP_AUTHORIZATION'
]
||
request
.
env
[
'X_HTTP_AUTHORIZATION'
]
||
request
.
env
[
'REDIRECT_X_HTTP_AUTHORIZATION'
]
end
# Raises error unless the request credentials response value matches the expected value.
def
validate_digest_response
(
controller
,
realm
,
&
password_procedure
)
credentials
=
decode_credentials
(
controller
.
request
)
# Check the nonce, opaque and realm.
# Ignore nc, as we have no way to validate the number of times this nonce has been used
validate_nonce
(
controller
.
request
,
credentials
[
:nonce
])
raise
Error
.
new
(
false
,
realm
,
credentials
[
:realm
]),
"Realm doesn't match"
unless
realm
==
credentials
[
:realm
]
raise
Error
.
new
(
true
,
opaque
(
controller
.
request
),
credentials
[
:opaque
]),
"Opaque doesn't match"
unless
opaque
(
controller
.
request
)
==
credentials
[
:opaque
]
password
=
password_procedure
.
call
(
credentials
[
:username
])
raise
Error
.
new
(
false
),
"No password"
if
password
.
nil?
expected
=
expected_response
(
controller
.
request
.
env
[
'REQUEST_METHOD'
],
controller
.
request
.
url
,
credentials
,
password
)
raise
Error
.
new
(
false
,
expected
,
credentials
[
:response
]),
"Invalid response"
unless
expected
==
credentials
[
:response
]
end
# Returns the expected response for a request of +http_method+ to +uri+ with the decoded +credentials+ and the expected +password+
def
expected_response
(
http_method
,
uri
,
credentials
,
password
)
ha1
=
::
Digest
::
MD5
.
hexdigest
([
credentials
[
:username
],
credentials
[
:realm
],
password
].
join
(
':'
))
ha2
=
::
Digest
::
MD5
.
hexdigest
([
http_method
.
to_s
.
upcase
,
uri
].
join
(
':'
))
::
Digest
::
MD5
.
hexdigest
([
ha1
,
credentials
[
:nonce
],
credentials
[
:nc
],
credentials
[
:cnonce
],
credentials
[
:qop
],
ha2
].
join
(
':'
))
end
def
encode_credentials
(
http_method
,
credentials
,
password
)
credentials
[
:response
]
=
expected_response
(
http_method
,
credentials
[
:uri
],
credentials
,
password
)
"Digest "
+
credentials
.
sort_by
{
|
x
|
x
[
0
].
to_s
}.
inject
([])
{
|
a
,
v
|
a
<<
"
#{
v
[
0
]
}
='
#{
v
[
1
]
}
'"
}.
join
(
', '
)
end
def
decode_credentials
(
request
)
authorization
(
request
).
to_s
.
gsub
(
/^Digest\s+/
,
''
).
split
(
','
).
inject
({})
do
|
hash
,
pair
|
key
,
value
=
pair
.
split
(
'='
,
2
)
hash
[
key
.
strip
.
to_sym
]
=
value
.
to_s
.
gsub
(
/^"|"$/
,
''
).
gsub
(
/'/
,
''
)
hash
end
end
def
authentication_header
(
controller
,
realm
)
controller
.
headers
[
"WWW-Authenticate"
]
=
%(Digest realm="#{realm}", qop="auth", algorithm=MD5, nonce="#{nonce(controller.request)}", opaque="#{opaque(controller.request)}")
end
def
authentication_request
(
controller
,
realm
,
message
=
"HTTP Digest: Access denied"
)
authentication_header
(
controller
,
realm
)
controller
.
send!
:render
,
:text
=>
message
,
:status
=>
:unauthorized
end
# Uses an MD5 digest based on time to generate a value to be used only once.
#
# A server-specified data string which should be uniquely generated each time a 401 response is made.
# It is recommended that this string be base64 or hexadecimal data.
# Specifically, since the string is passed in the header lines as a quoted string, the double-quote character is not allowed.
#
# The contents of the nonce are implementation dependent.
# The quality of the implementation depends on a good choice.
# A nonce might, for example, be constructed as the base 64 encoding of
#
# => time-stamp H(time-stamp ":" ETag ":" private-key)
#
# where time-stamp is a server-generated time or other non-repeating value,
# ETag is the value of the HTTP ETag header associated with the requested entity,
# and private-key is data known only to the server.
# With a nonce of this form a server would recalculate the hash portion after receiving the client authentication header and
# reject the request if it did not match the nonce from that header or
# if the time-stamp value is not recent enough. In this way the server can limit the time of the nonce's validity.
# The inclusion of the ETag prevents a replay request for an updated version of the resource.
# (Note: including the IP address of the client in the nonce would appear to offer the server the ability
# to limit the reuse of the nonce to the same client that originally got it.
# However, that would break proxy farms, where requests from a single user often go through different proxies in the farm.
# Also, IP address spoofing is not that hard.)
#
# An implementation might choose not to accept a previously used nonce or a previously used digest, in order to
# protect against a replay attack. Or, an implementation might choose to use one-time nonces or digests for
# POST or PUT requests and a time-stamp for GET requests. For more details on the issues involved see Section 4
# of this document.
#
# The nonce is opaque to the client.
def
nonce
(
request
,
time
=
Time
.
now
)
session_id
=
request
.
is_a?
(
String
)
?
request
:
request
.
session
.
session_id
t
=
time
.
to_i
hashed
=
[
t
,
session_id
]
digest
=
::
Digest
::
MD5
.
hexdigest
(
hashed
.
join
(
":"
))
Base64
.
encode64
(
"
#{
t
}
:
#{
digest
}
"
).
gsub
(
"
\n
"
,
''
)
end
def
validate_nonce
(
request
,
value
)
t
=
Base64
.
decode64
(
value
).
split
(
":"
).
first
.
to_i
raise
Error
.
new
(
true
),
"Stale Nonce"
if
(
t
-
Time
.
now
.
to_i
).
abs
>
10
*
60
n
=
nonce
(
request
,
t
)
raise
Error
.
new
(
true
,
value
,
n
),
"Bad Nonce"
unless
n
==
value
end
# Opaque based on digest of session_id
def
opaque
(
request
)
session_id
=
request
.
is_a?
(
String
)
?
request
:
request
.
session
.
session_id
@opaque
||=
Base64
.
encode64
(
::
Digest
::
MD5
::
hexdigest
(
session_id
)).
gsub
(
"
\n
"
,
''
)
end
end
class
Error
<
RuntimeError
attr_accessor
:expected
,
:was
def
initialize
(
fatal
=
false
,
expected
=
nil
,
was
=
nil
)
@fatal
=
fatal
@expected
=
expected
@was
=
was
end
def
fatal?
;
@fatal
;
end
end
end
end
actionpack/lib/action_controller/integration.rb
浏览文件 @
19208e74
...
...
@@ -68,6 +68,15 @@ class Session
# A running counter of the number of requests processed.
attr_accessor
:request_count
# Nonce value for Digest Authentication, implicitly set on response with WWW-Authentication
attr_accessor
:nonce
# Opaque value for Digest Authentication, implicitly set on response with WWW-Authentication
attr_accessor
:opaque
# Opaque value for Authentication, implicitly set on response with WWW-Authentication
attr_accessor
:realm
class
MultiPartNeededException
<
Exception
end
...
...
@@ -243,6 +252,53 @@ def xml_http_request(request_method, path, parameters = nil, headers = nil)
end
alias
xhr
:xml_http_request
def
request_with_noauth
(
http_method
,
uri
,
parameters
,
headers
)
process_with_auth
http_method
,
uri
,
parameters
,
headers
end
# Performs a request with the given http_method and parameters, including HTTP Basic authorization headers.
# See get() for more details on paramters and headers.
#
# You can perform GET, POST, PUT, DELETE, and HEAD requests with #get_with_basic, #post_with_basic,
# #put_with_basic, #delete_with_basic, and #head_with_basic.
def
request_with_basic
(
http_method
,
uri
,
parameters
,
headers
,
user_name
,
password
)
process_with_auth
http_method
,
uri
,
parameters
,
headers
.
merge
(
:authorization
=>
ActionController
::
HttpAuthentication
::
Basic
.
encode_credentials
(
user_name
,
password
))
end
# Performs a request with the given http_method and parameters, including HTTP Digest authorization headers.
# See get() for more details on paramters and headers.
#
# You can perform GET, POST, PUT, DELETE, and HEAD requests with #get_with_digest, #post_with_digest,
# #put_with_digest, #delete_with_digest, and #head_with_digest.
def
request_with_digest
(
http_method
,
uri
,
parameters
,
headers
,
user_name
,
password
)
# Realm, Nonce, and Opaque taken from previoius 401 response
credentials
=
{
:username
=>
user_name
,
:realm
=>
@realm
,
:nonce
=>
@nonce
,
:qop
=>
"auth"
,
:nc
=>
"00000001"
,
:cnonce
=>
"0a4f113b"
,
:opaque
=>
@opaque
,
:uri
=>
uri
}
raise
"Digest request without previous 401 response"
if
@opaque
.
nil?
process_with_auth
http_method
,
uri
,
parameters
,
headers
.
merge
(
:authorization
=>
ActionController
::
HttpAuthentication
::
Digest
.
encode_credentials
(
http_method
,
credentials
,
password
))
end
# def get_with_basic, def post_with_basic, def put_with_basic, def delete_with_basic, def head_with_basic
# def get_with_digest, def post_with_digest, def put_with_digest, def delete_with_digest, def head_with_digest
[
:get
,
:post
,
:put
,
:delete
,
:head
].
each
do
|
method
|
[
:noauth
,
:basic
,
:digest
].
each
do
|
auth_type
|
define_method
(
"
#{
method
}
_with_
#{
auth_type
}
"
)
do
|
uri
,
parameters
,
headers
,
*
auth
|
send
(
"request_with_
#{
auth_type
}
"
,
method
,
uri
,
parameters
,
headers
,
*
auth
)
end
end
end
# Returns the URL for the given options, according to the rules specified
# in the application's routes.
def
url_for
(
options
)
...
...
@@ -364,6 +420,32 @@ def process(method, path, parameters = nil, headers = nil)
return
status
end
# Same as process, but handles authentication returns to perform
# Basic or Digest authentication
def
process_with_auth
(
method
,
path
,
parameters
=
nil
,
headers
=
nil
)
status
=
process
(
method
,
path
,
parameters
,
headers
)
if
status
==
401
# Extract authentication information from response
auth_data
=
@response
.
headers
[
'WWW-Authenticate'
]
if
/^Basic /
.
match
(
auth_data
)
# extract realm, to be used in subsequent request
@realm
=
auth_header
.
split
(
' '
)[
1
]
elsif
/^Digest/
.
match
(
auth_data
)
creds
=
auth_data
.
to_s
.
gsub
(
/^Digest\s+/
,
''
).
split
(
','
).
inject
({})
do
|
hash
,
pair
|
key
,
value
=
pair
.
split
(
'='
,
2
)
hash
[
key
.
strip
.
to_sym
]
=
value
.
to_s
.
gsub
(
/^"|"$/
,
''
).
gsub
(
/'/
,
''
)
hash
end
@realm
=
creds
[
:realm
]
@nonce
=
creds
[
:nonce
]
@opaque
=
creds
[
:opaque
]
end
end
return
status
end
# Encode the cookies hash in a format suitable for passing to a
# request.
def
encode_cookies
...
...
actionpack/test/controller/http_digest_authentication_test.rb
0 → 100644
浏览文件 @
19208e74
require
'abstract_unit'
class
HttpDigestAuthenticationTest
<
Test
::
Unit
::
TestCase
include
ActionController
::
HttpAuthentication
::
Digest
class
DummyController
attr_accessor
:headers
,
:renders
,
:request
,
:response
def
initialize
@headers
,
@renders
=
{},
[]
@request
=
ActionController
::
TestRequest
.
new
@response
=
ActionController
::
TestResponse
.
new
request
.
session
.
session_id
=
"test_session"
end
def
render
(
options
)
self
.
renderers
<<
options
end
end
def
setup
@controller
=
DummyController
.
new
@credentials
=
{
:username
=>
"dhh"
,
:realm
=>
"testrealm@host.com"
,
:nonce
=>
ActionController
::
HttpAuthentication
::
Digest
.
nonce
(
@controller
.
request
),
:qop
=>
"auth"
,
:nc
=>
"00000001"
,
:cnonce
=>
"0a4f113b"
,
:opaque
=>
ActionController
::
HttpAuthentication
::
Digest
.
opaque
(
@controller
.
request
),
:uri
=>
"http://test.host/"
}
@encoded_credentials
=
ActionController
::
HttpAuthentication
::
Digest
.
encode_credentials
(
"GET"
,
@credentials
,
"secret"
)
end
def
test_decode_credentials
set_headers
assert_equal
@credentials
,
decode_credentials
(
@controller
.
request
)
end
def
test_nonce_format
assert_nothing_thrown
do
validate_nonce
(
@controller
.
request
,
nonce
(
@controller
.
request
))
end
end
def
test_authenticate_should_raise_for_nil_password
set_headers
ActionController
::
HttpAuthentication
::
Digest
.
encode_credentials
(
:get
,
@credentials
,
nil
)
assert_raise
ActionController
::
HttpAuthentication
::
Error
do
authenticate
(
@controller
,
@credentials
[
:realm
])
{
|
user
|
user
==
"dhh"
&&
"secret"
}
end
end
def
test_authenticate_should_raise_for_incorrect_password
set_headers
assert_raise
ActionController
::
HttpAuthentication
::
Error
do
authenticate
(
@controller
,
@credentials
[
:realm
])
{
|
user
|
user
==
"dhh"
&&
"bad password"
}
end
end
def
test_authenticate_should_not_raise_for_correct_password
set_headers
assert_nothing_thrown
do
authenticate
(
@controller
,
@credentials
[
:realm
])
{
|
user
|
user
==
"dhh"
&&
"secret"
}
end
end
private
def
set_headers
(
value
=
@encoded_credentials
,
name
=
'HTTP_AUTHORIZATION'
,
method
=
"GET"
)
@controller
.
request
.
env
[
name
]
=
value
@controller
.
request
.
env
[
"REQUEST_METHOD"
]
=
method
end
end
actionpack/test/controller/integration_test.rb
浏览文件 @
19208e74
...
...
@@ -8,7 +8,25 @@ class SessionTest < Test::Unit::TestCase
}
def
setup
@credentials
=
{
:username
=>
"username"
,
:realm
=>
"MyApp"
,
:nonce
=>
ActionController
::
HttpAuthentication
::
Digest
.
nonce
(
"session_id"
),
:qop
=>
"auth"
,
:nc
=>
"00000001"
,
:cnonce
=>
"0a4f113b"
,
:opaque
=>
ActionController
::
HttpAuthentication
::
Digest
.
opaque
(
"session_id"
),
:uri
=>
"/index"
}
@session
=
ActionController
::
Integration
::
Session
.
new
(
StubApp
)
@session
.
nonce
=
@credentials
[
:nonce
]
@session
.
opaque
=
@credentials
[
:opaque
]
@session
.
realm
=
@credentials
[
:realm
]
end
def
encoded_credentials
(
method
)
ActionController
::
HttpAuthentication
::
Digest
.
encode_credentials
(
method
,
@credentials
,
"password"
)
end
def
test_https_bang_works_and_sets_truth_by_default
...
...
@@ -132,6 +150,76 @@ def test_head
@session
.
head
(
path
,
params
,
headers
)
end
def
test_get_with_basic
path
=
"/index"
;
params
=
"blah"
;
headers
=
{
:location
=>
'blah'
}
expected_headers
=
headers
.
merge
(
:authorization
=>
"Basic dXNlcm5hbWU6cGFzc3dvcmQ=
\n
"
)
@session
.
expects
(
:process
).
with
(
:get
,
path
,
params
,
expected_headers
)
@session
.
get_with_basic
(
path
,
params
,
headers
,
'username'
,
'password'
)
end
def
test_post_with_basic
path
=
"/index"
;
params
=
"blah"
;
headers
=
{
:location
=>
'blah'
}
expected_headers
=
headers
.
merge
(
:authorization
=>
"Basic dXNlcm5hbWU6cGFzc3dvcmQ=
\n
"
)
@session
.
expects
(
:process
).
with
(
:post
,
path
,
params
,
expected_headers
)
@session
.
post_with_basic
(
path
,
params
,
headers
,
'username'
,
'password'
)
end
def
test_put_with_basic
path
=
"/index"
;
params
=
"blah"
;
headers
=
{
:location
=>
'blah'
}
expected_headers
=
headers
.
merge
(
:authorization
=>
"Basic dXNlcm5hbWU6cGFzc3dvcmQ=
\n
"
)
@session
.
expects
(
:process
).
with
(
:put
,
path
,
params
,
expected_headers
)
@session
.
put_with_basic
(
path
,
params
,
headers
,
'username'
,
'password'
)
end
def
test_delete_with_basic
path
=
"/index"
;
params
=
"blah"
;
headers
=
{
:location
=>
'blah'
}
expected_headers
=
headers
.
merge
(
:authorization
=>
"Basic dXNlcm5hbWU6cGFzc3dvcmQ=
\n
"
)
@session
.
expects
(
:process
).
with
(
:delete
,
path
,
params
,
expected_headers
)
@session
.
delete_with_basic
(
path
,
params
,
headers
,
'username'
,
'password'
)
end
def
test_head_with_basic
path
=
"/index"
;
params
=
"blah"
;
headers
=
{
:location
=>
'blah'
}
expected_headers
=
headers
.
merge
(
:authorization
=>
"Basic dXNlcm5hbWU6cGFzc3dvcmQ=
\n
"
)
@session
.
expects
(
:process
).
with
(
:head
,
path
,
params
,
expected_headers
)
@session
.
head_with_basic
(
path
,
params
,
headers
,
'username'
,
'password'
)
end
def
test_get_with_digest
path
=
"/index"
;
params
=
"blah"
;
headers
=
{
:location
=>
'blah'
}
expected_headers
=
headers
.
merge
(
:authorization
=>
encoded_credentials
(
:get
))
@session
.
expects
(
:process
).
with
(
:get
,
path
,
params
,
expected_headers
)
@session
.
get_with_digest
(
path
,
params
,
headers
,
'username'
,
'password'
)
end
def
test_post_with_digest
path
=
"/index"
;
params
=
"blah"
;
headers
=
{
:location
=>
'blah'
}
expected_headers
=
headers
.
merge
(
:authorization
=>
encoded_credentials
(
:post
))
@session
.
expects
(
:process
).
with
(
:post
,
path
,
params
,
expected_headers
)
@session
.
post_with_digest
(
path
,
params
,
headers
,
'username'
,
'password'
)
end
def
test_put_with_digest
path
=
"/index"
;
params
=
"blah"
;
headers
=
{
:location
=>
'blah'
}
expected_headers
=
headers
.
merge
(
:authorization
=>
encoded_credentials
(
:put
))
@session
.
expects
(
:process
).
with
(
:put
,
path
,
params
,
expected_headers
)
@session
.
put_with_digest
(
path
,
params
,
headers
,
'username'
,
'password'
)
end
def
test_delete_with_digest
path
=
"/index"
;
params
=
"blah"
;
headers
=
{
:location
=>
'blah'
}
expected_headers
=
headers
.
merge
(
:authorization
=>
encoded_credentials
(
:delete
))
@session
.
expects
(
:process
).
with
(
:delete
,
path
,
params
,
expected_headers
)
@session
.
delete_with_digest
(
path
,
params
,
headers
,
'username'
,
'password'
)
end
def
test_head_with_digest
path
=
"/index"
;
params
=
"blah"
;
headers
=
{
:location
=>
'blah'
}
expected_headers
=
headers
.
merge
(
:authorization
=>
encoded_credentials
(
:head
))
@session
.
expects
(
:process
).
with
(
:head
,
path
,
params
,
expected_headers
)
@session
.
head_with_digest
(
path
,
params
,
headers
,
'username'
,
'password'
)
end
def
test_xml_http_request_get
path
=
"/index"
;
params
=
"blah"
;
headers
=
{
:location
=>
'blah'
}
headers_after_xhr
=
headers
.
merge
(
...
...
activesupport/lib/active_support/callbacks.rb
浏览文件 @
19208e74
...
...
@@ -192,13 +192,8 @@ def evaluate_method(method, *args, &block)
end
def
should_run_callback?
(
*
args
)
if
options
[
:if
]
evaluate_method
(
options
[
:if
],
*
args
)
elsif
options
[
:unless
]
!
evaluate_method
(
options
[
:unless
],
*
args
)
else
true
end
[
options
[
:if
]].
flatten
.
compact
.
all?
{
|
a
|
evaluate_method
(
a
,
*
args
)
}
&&
!
[
options
[
:unless
]].
flatten
.
compact
.
any?
{
|
a
|
evaluate_method
(
a
,
*
args
)
}
end
end
...
...
activesupport/test/callbacks_test.rb
浏览文件 @
19208e74
...
...
@@ -53,10 +53,41 @@ def save
end
class
ConditionalPerson
<
Record
# proc
before_save
Proc
.
new
{
|
r
|
r
.
history
<<
[
:before_save
,
:proc
]
},
:if
=>
Proc
.
new
{
|
r
|
true
}
before_save
Proc
.
new
{
|
r
|
r
.
history
<<
"b00m"
},
:if
=>
Proc
.
new
{
|
r
|
false
}
before_save
Proc
.
new
{
|
r
|
r
.
history
<<
[
:before_save
,
:proc
]
},
:unless
=>
Proc
.
new
{
|
r
|
false
}
before_save
Proc
.
new
{
|
r
|
r
.
history
<<
"b00m"
},
:unless
=>
Proc
.
new
{
|
r
|
true
}
# symbol
before_save
Proc
.
new
{
|
r
|
r
.
history
<<
[
:before_save
,
:symbol
]
},
:if
=>
:yes
before_save
Proc
.
new
{
|
r
|
r
.
history
<<
"b00m"
},
:if
=>
:no
before_save
Proc
.
new
{
|
r
|
r
.
history
<<
[
:before_save
,
:symbol
]
},
:unless
=>
:no
before_save
Proc
.
new
{
|
r
|
r
.
history
<<
"b00m"
},
:unless
=>
:yes
# string
before_save
Proc
.
new
{
|
r
|
r
.
history
<<
[
:before_save
,
:string
]
},
:if
=>
'yes'
before_save
Proc
.
new
{
|
r
|
r
.
history
<<
"b00m"
},
:if
=>
'no'
before_save
Proc
.
new
{
|
r
|
r
.
history
<<
[
:before_save
,
:string
]
},
:unless
=>
'no'
before_save
Proc
.
new
{
|
r
|
r
.
history
<<
"b00m"
},
:unless
=>
'yes'
# Array with conditions
before_save
Proc
.
new
{
|
r
|
r
.
history
<<
[
:before_save
,
:symbol_array
]
},
:if
=>
[
:yes
,
:other_yes
]
before_save
Proc
.
new
{
|
r
|
r
.
history
<<
"b00m"
},
:if
=>
[
:yes
,
:no
]
before_save
Proc
.
new
{
|
r
|
r
.
history
<<
[
:before_save
,
:symbol_array
]
},
:unless
=>
[
:no
,
:other_no
]
before_save
Proc
.
new
{
|
r
|
r
.
history
<<
"b00m"
},
:unless
=>
[
:yes
,
:no
]
# Combined if and unless
before_save
Proc
.
new
{
|
r
|
r
.
history
<<
[
:before_save
,
:combined_symbol
]
},
:if
=>
:yes
,
:unless
=>
:no
before_save
Proc
.
new
{
|
r
|
r
.
history
<<
"b00m"
},
:if
=>
:yes
,
:unless
=>
:yes
# Array with different types of conditions
before_save
Proc
.
new
{
|
r
|
r
.
history
<<
[
:before_save
,
:symbol_proc_string_array
]
},
:if
=>
[
:yes
,
Proc
.
new
{
|
r
|
true
},
'yes'
]
before_save
Proc
.
new
{
|
r
|
r
.
history
<<
"b00m"
},
:if
=>
[
:yes
,
Proc
.
new
{
|
r
|
true
},
'no'
]
# Array with different types of conditions comibned if and unless
before_save
Proc
.
new
{
|
r
|
r
.
history
<<
[
:before_save
,
:combined_symbol_proc_string_array
]
},
:if
=>
[
:yes
,
Proc
.
new
{
|
r
|
true
},
'yes'
],
:unless
=>
[
:no
,
'no'
]
before_save
Proc
.
new
{
|
r
|
r
.
history
<<
"b00m"
},
:if
=>
[
:yes
,
Proc
.
new
{
|
r
|
true
},
'no'
],
:unless
=>
[
:no
,
'no'
]
def
yes
;
true
;
end
def
other_yes
;
true
;
end
def
no
;
false
;
end
def
other_no
;
false
;
end
def
save
run_callbacks
(
:before_save
)
...
...
@@ -90,7 +121,16 @@ def test_save_conditional_person
person
.
save
assert_equal
[
[
:before_save
,
:proc
],
[
:before_save
,
:proc
]
[
:before_save
,
:proc
],
[
:before_save
,
:symbol
],
[
:before_save
,
:symbol
],
[
:before_save
,
:string
],
[
:before_save
,
:string
],
[
:before_save
,
:symbol_array
],
[
:before_save
,
:symbol_array
],
[
:before_save
,
:combined_symbol
],
[
:before_save
,
:symbol_proc_string_array
],
[
:before_save
,
:combined_symbol_proc_string_array
]
],
person
.
history
end
end
...
...
railties/lib/rails_generator/commands.rb
浏览文件 @
19208e74
...
...
@@ -294,7 +294,7 @@ def template(relative_source, relative_destination, template_options = {})
file
(
relative_source
,
relative_destination
,
template_options
)
do
|
file
|
# Evaluate any assignments in a temporary, throwaway binding.
vars
=
template_options
[
:assigns
]
||
{}
b
=
binding
b
=
template_options
[
:binding
]
||
binding
vars
.
each
{
|
k
,
v
|
eval
"
#{
k
}
= vars[:
#{
k
}
] || vars['
#{
k
}
']"
,
b
}
# Render the source file with the temporary binding.
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录