Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
镜像
tornadoweb
Tornado
提交
f98d06dd
Tornado
项目概览
镜像
/
tornadoweb
/
Tornado
11 个月 前同步成功
通知
26
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
Tornado
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
f98d06dd
编写于
3月 18, 2018
作者:
B
Ben Darnell
提交者:
GitHub
3月 18, 2018
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #2317 from bdarnell/auth-deprecation
auth: Add deprecation warnings for callback-based interfaces
上级
8cb645b8
f6f56f58
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
297 addition
and
39 deletion
+297
-39
tornado/auth.py
tornado/auth.py
+85
-16
tornado/concurrent.py
tornado/concurrent.py
+13
-0
tornado/test/auth_test.py
tornado/test/auth_test.py
+174
-14
tornado/test/concurrent_test.py
tornado/test/concurrent_test.py
+15
-8
tornado/test/util.py
tornado/test/util.py
+9
-0
tornado/web.py
tornado/web.py
+1
-1
未找到文件。
tornado/auth.py
浏览文件 @
f98d06dd
...
...
@@ -73,6 +73,7 @@ import hashlib
import
hmac
import
time
import
uuid
import
warnings
from
tornado.concurrent
import
(
Future
,
return_future
,
chain_future
,
future_set_exc_info
,
...
...
@@ -113,6 +114,9 @@ def _auth_return_future(f):
Note that when using this decorator the ``callback`` parameter
inside the function will actually be a future.
.. deprecated:: 5.1
Will be removed in 6.0.
"""
replacer
=
ArgReplacer
(
f
,
'callback'
)
...
...
@@ -121,6 +125,8 @@ def _auth_return_future(f):
future
=
Future
()
callback
,
args
,
kwargs
=
replacer
.
replace
(
future
,
args
,
kwargs
)
if
callback
is
not
None
:
warnings
.
warn
(
"callback arguments are deprecated, use the returned Future instead"
,
DeprecationWarning
)
future
.
add_done_callback
(
functools
.
partial
(
_auth_future_to_callback
,
callback
))
...
...
@@ -162,6 +168,11 @@ class OpenIdMixin(object):
not strictly necessary as this method is synchronous,
but they are supplied for consistency with
`OAuthMixin.authorize_redirect`.
.. deprecated:: 5.1
The ``callback`` argument and returned awaitable will be removed
in Tornado 6.0; this will be an ordinary synchronous function.
"""
callback_uri
=
callback_uri
or
self
.
request
.
uri
args
=
self
.
_openid_args
(
callback_uri
,
ax_attrs
=
ax_attrs
)
...
...
@@ -179,6 +190,11 @@ class OpenIdMixin(object):
is present and `authenticate_redirect` if it is not).
The result of this method will generally be used to set a cookie.
.. deprecated:: 5.1
The ``callback`` argument is deprecated and will be removed in 6.0.
Use the returned awaitable object instead.
"""
# Verify the OpenID response via direct request to the OP
args
=
dict
((
k
,
v
[
-
1
])
for
k
,
v
in
self
.
request
.
arguments
.
items
())
...
...
@@ -329,25 +345,29 @@ class OAuthMixin(object):
"""Redirects the user to obtain OAuth authorization for this service.
The ``callback_uri`` may be omitted if you have previously
registered a callback URI with the third-party service. For
some services (including Friendfeed), you must use a
previously-registered callback URI and cannot specify a
callback via this method.
registered a callback URI with the third-party service. For
some services, you must use a previously-registered callback
URI and cannot specify a callback via this method.
This method sets a cookie called ``_oauth_request_token`` which is
subsequently used (and cleared) in `get_authenticated_user` for
security purposes.
Note that this method is asynchronous, although it calls
`.RequestHandler.finish` for you so it may not be necessary
to pass a callback or use the `.Future` it returns. However,
if this method is called from a function decorated with
`.gen.coroutine`, you must call it with ``yield`` to keep the
response from being closed prematurely.
This method is asynchronous and must be called with ``await``
or ``yield`` (This is different from other ``auth*_redirect``
methods defined in this module). It calls
`.RequestHandler.finish` for you so you should not write any
other response after it returns.
.. versionchanged:: 3.1
Now returns a `.Future` and takes an optional callback, for
compatibility with `.gen.coroutine`.
.. deprecated:: 5.1
The ``callback`` argument is deprecated and will be removed in 6.0.
Use the returned awaitable object instead.
"""
if
callback_uri
and
getattr
(
self
,
"_OAUTH_NO_CALLBACKS"
,
False
):
raise
Exception
(
"This service does not support oauth_callback"
)
...
...
@@ -381,6 +401,11 @@ class OAuthMixin(object):
requests to this service on behalf of the user. The dictionary will
also contain other fields such as ``name``, depending on the service
used.
.. deprecated:: 5.1
The ``callback`` argument is deprecated and will be removed in 6.0.
Use the returned awaitable object instead.
"""
future
=
callback
request_key
=
escape
.
utf8
(
self
.
get_argument
(
"oauth_token"
))
...
...
@@ -479,7 +504,9 @@ class OAuthMixin(object):
return
access_token
=
_oauth_parse_response
(
response
.
body
)
self
.
_oauth_get_user_future
(
access_token
).
add_done_callback
(
fut
=
self
.
_oauth_get_user_future
(
access_token
)
fut
=
gen
.
convert_yielded
(
fut
)
fut
.
add_done_callback
(
functools
.
partial
(
self
.
_on_oauth_get_user
,
access_token
,
future
))
def
_oauth_consumer_token
(
self
):
...
...
@@ -504,7 +531,18 @@ class OAuthMixin(object):
For backwards compatibility, the callback-based ``_oauth_get_user``
method is also supported.
.. versionchanged:: 5.1
Subclasses may also define this method with ``async def``.
.. deprecated:: 5.1
The ``_oauth_get_user`` fallback is deprecated and support for it
will be removed in 6.0.
"""
warnings
.
warn
(
"_oauth_get_user is deprecated, override _oauth_get_user_future instead"
,
DeprecationWarning
)
# By default, call the old-style _oauth_get_user, but new code
# should override this method instead.
self
.
_oauth_get_user
(
access_token
,
callback
)
...
...
@@ -588,6 +626,11 @@ class OAuth2Mixin(object):
not strictly necessary as this method is synchronous,
but they are supplied for consistency with
`OAuthMixin.authorize_redirect`.
.. deprecated:: 5.1
The ``callback`` argument and returned awaitable will be removed
in Tornado 6.0; this will be an ordinary synchronous function.
"""
args
=
{
"redirect_uri"
:
redirect_uri
,
...
...
@@ -648,6 +691,11 @@ class OAuth2Mixin(object):
:hide:
.. versionadded:: 4.3
.. deprecated:: 5.1
The ``callback`` argument is deprecated and will be removed in 6.0.
Use the returned awaitable object instead.
"""
all_args
=
{}
if
access_token
:
...
...
@@ -734,6 +782,11 @@ class TwitterMixin(OAuthMixin):
.. versionchanged:: 3.1
Now returns a `.Future` and takes an optional callback, for
compatibility with `.gen.coroutine`.
.. deprecated:: 5.1
The ``callback`` argument is deprecated and will be removed in 6.0.
Use the returned awaitable object instead.
"""
http
=
self
.
get_auth_http_client
()
http
.
fetch
(
self
.
_oauth_request_token_url
(
callback_uri
=
callback_uri
),
...
...
@@ -781,6 +834,10 @@ class TwitterMixin(OAuthMixin):
.. testoutput::
:hide:
.. deprecated:: 5.1
The ``callback`` argument is deprecated and will be removed in 6.0.
Use the returned awaitable object instead.
"""
if
path
.
startswith
(
'http:'
)
or
path
.
startswith
(
'https:'
):
# Raw urls are useful for e.g. search which doesn't follow the
...
...
@@ -896,6 +953,10 @@ class GoogleOAuth2Mixin(OAuth2Mixin):
.. testoutput::
:hide:
.. deprecated:: 5.1
The ``callback`` argument is deprecated and will be removed in 6.0.
Use the returned awaitable object instead.
"""
# noqa: E501
http
=
self
.
get_auth_http_client
()
body
=
urllib_parse
.
urlencode
({
...
...
@@ -973,6 +1034,11 @@ class FacebookGraphMixin(OAuth2Mixin):
.. versionchanged:: 4.5
The ``session_expires`` field was updated to support changes made to the
Facebook API in March 2017.
.. deprecated:: 5.1
The ``callback`` argument is deprecated and will be removed in 6.0.
Use the returned awaitable object instead.
"""
http
=
self
.
get_auth_http_client
()
args
=
{
...
...
@@ -991,6 +1057,7 @@ class FacebookGraphMixin(OAuth2Mixin):
functools
.
partial
(
self
.
_on_access_token
,
redirect_uri
,
client_id
,
client_secret
,
callback
,
fields
))
@
gen
.
coroutine
def
_on_access_token
(
self
,
redirect_uri
,
client_id
,
client_secret
,
future
,
fields
,
response
):
if
response
.
error
:
...
...
@@ -1003,10 +1070,8 @@ class FacebookGraphMixin(OAuth2Mixin):
"expires_in"
:
args
.
get
(
"expires_in"
)
}
self
.
facebook_request
(
user
=
yield
self
.
facebook_request
(
path
=
"/me"
,
callback
=
functools
.
partial
(
self
.
_on_get_user_info
,
future
,
session
,
fields
),
access_token
=
session
[
"access_token"
],
appsecret_proof
=
hmac
.
new
(
key
=
client_secret
.
encode
(
'utf8'
),
msg
=
session
[
"access_token"
].
encode
(
'utf8'
),
...
...
@@ -1014,7 +1079,6 @@ class FacebookGraphMixin(OAuth2Mixin):
fields
=
","
.
join
(
fields
)
)
def
_on_get_user_info
(
self
,
future
,
session
,
fields
,
user
):
if
user
is
None
:
future_set_result_unless_cancelled
(
future
,
None
)
return
...
...
@@ -1050,7 +1114,7 @@ class FacebookGraphMixin(OAuth2Mixin):
Example usage:
..testcode::
..
testcode::
class MainHandler(tornado.web.RequestHandler,
tornado.auth.FacebookGraphMixin):
...
...
@@ -1080,6 +1144,11 @@ class FacebookGraphMixin(OAuth2Mixin):
.. versionchanged:: 3.1
Added the ability to override ``self._FACEBOOK_BASE_URL``.
.. deprecated:: 5.1
The ``callback`` argument is deprecated and will be removed in 6.0.
Use the returned awaitable object instead.
"""
url
=
self
.
_FACEBOOK_BASE_URL
+
path
# Thanks to the _auth_return_future decorator, our "callback"
...
...
tornado/concurrent.py
浏览文件 @
f98d06dd
...
...
@@ -33,6 +33,7 @@ import platform
import
textwrap
import
traceback
import
sys
import
warnings
from
tornado.log
import
app_log
from
tornado.stack_context
import
ExceptionStackContext
,
wrap
...
...
@@ -496,6 +497,15 @@ def return_future(f):
same function, provided ``@return_future`` appears first. However,
consider using ``@gen.coroutine`` instead of this combination.
.. versionchanged:: 5.1
Now raises a `.DeprecationWarning` if a callback argument is passed to
the decorated function and deprecation warnings are enabled.
.. deprecated:: 5.1
New code should use coroutines directly instead of wrapping
callback-based code with this decorator.
"""
replacer
=
ArgReplacer
(
f
,
'callback'
)
...
...
@@ -533,6 +543,9 @@ def return_future(f):
# immediate exception, and again when the future resolves and
# the callback triggers its exception by calling future.result()).
if
callback
is
not
None
:
warnings
.
warn
(
"callback arguments are deprecated, use the returned Future instead"
,
DeprecationWarning
)
def
run_callback
(
future
):
result
=
future
.
result
()
if
result
is
_NO_RESULT
:
...
...
tornado/test/auth_test.py
浏览文件 @
f98d06dd
...
...
@@ -6,6 +6,8 @@
from
__future__
import
absolute_import
,
division
,
print_function
import
warnings
from
tornado.auth
import
(
AuthError
,
OpenIdMixin
,
OAuthMixin
,
OAuth2Mixin
,
GoogleOAuth2Mixin
,
FacebookGraphMixin
,
TwitterMixin
,
...
...
@@ -16,19 +18,22 @@ from tornado import gen
from
tornado.httputil
import
url_concat
from
tornado.log
import
gen_log
from
tornado.testing
import
AsyncHTTPTestCase
,
ExpectLog
from
tornado.test.util
import
ignore_deprecation
from
tornado.web
import
RequestHandler
,
Application
,
asynchronous
,
HTTPError
class
OpenIdClientLoginHandler
(
RequestHandler
,
OpenIdMixin
):
class
OpenIdClientLoginHandler
Legacy
(
RequestHandler
,
OpenIdMixin
):
def
initialize
(
self
,
test
):
self
.
_OPENID_ENDPOINT
=
test
.
get_url
(
'/openid/server/authenticate'
)
@
asynchronous
def
get
(
self
):
if
self
.
get_argument
(
'openid.mode'
,
None
):
self
.
get_authenticated_user
(
self
.
on_user
,
http_client
=
self
.
settings
[
'http_client'
])
return
with
warnings
.
catch_warnings
():
warnings
.
simplefilter
(
'ignore'
,
DeprecationWarning
)
self
.
get_authenticated_user
(
self
.
on_user
,
http_client
=
self
.
settings
[
'http_client'
])
return
res
=
self
.
authenticate_redirect
()
assert
isinstance
(
res
,
Future
)
assert
res
.
done
()
...
...
@@ -39,6 +44,23 @@ class OpenIdClientLoginHandler(RequestHandler, OpenIdMixin):
self
.
finish
(
user
)
class
OpenIdClientLoginHandler
(
RequestHandler
,
OpenIdMixin
):
def
initialize
(
self
,
test
):
self
.
_OPENID_ENDPOINT
=
test
.
get_url
(
'/openid/server/authenticate'
)
@
gen
.
coroutine
def
get
(
self
):
if
self
.
get_argument
(
'openid.mode'
,
None
):
user
=
yield
self
.
get_authenticated_user
(
http_client
=
self
.
settings
[
'http_client'
])
if
user
is
None
:
raise
Exception
(
"user is None"
)
self
.
finish
(
user
)
return
res
=
self
.
authenticate_redirect
()
assert
isinstance
(
res
,
Future
)
assert
res
.
done
()
class
OpenIdServerAuthenticateHandler
(
RequestHandler
):
def
post
(
self
):
if
self
.
get_argument
(
'openid.mode'
)
!=
'check_authentication'
:
...
...
@@ -46,7 +68,7 @@ class OpenIdServerAuthenticateHandler(RequestHandler):
self
.
write
(
'is_valid:true'
)
class
OAuth1ClientLoginHandler
(
RequestHandler
,
OAuthMixin
):
class
OAuth1ClientLoginHandler
Legacy
(
RequestHandler
,
OAuthMixin
):
def
initialize
(
self
,
test
,
version
):
self
.
_OAUTH_VERSION
=
version
self
.
_OAUTH_REQUEST_TOKEN_URL
=
test
.
get_url
(
'/oauth1/server/request_token'
)
...
...
@@ -59,8 +81,10 @@ class OAuth1ClientLoginHandler(RequestHandler, OAuthMixin):
@
asynchronous
def
get
(
self
):
if
self
.
get_argument
(
'oauth_token'
,
None
):
self
.
get_authenticated_user
(
self
.
on_user
,
http_client
=
self
.
settings
[
'http_client'
])
with
warnings
.
catch_warnings
():
warnings
.
simplefilter
(
'ignore'
,
DeprecationWarning
)
self
.
get_authenticated_user
(
self
.
on_user
,
http_client
=
self
.
settings
[
'http_client'
])
return
res
=
self
.
authorize_redirect
(
http_client
=
self
.
settings
[
'http_client'
])
assert
isinstance
(
res
,
Future
)
...
...
@@ -78,6 +102,35 @@ class OAuth1ClientLoginHandler(RequestHandler, OAuthMixin):
callback
(
dict
(
email
=
'foo@example.com'
))
class
OAuth1ClientLoginHandler
(
RequestHandler
,
OAuthMixin
):
def
initialize
(
self
,
test
,
version
):
self
.
_OAUTH_VERSION
=
version
self
.
_OAUTH_REQUEST_TOKEN_URL
=
test
.
get_url
(
'/oauth1/server/request_token'
)
self
.
_OAUTH_AUTHORIZE_URL
=
test
.
get_url
(
'/oauth1/server/authorize'
)
self
.
_OAUTH_ACCESS_TOKEN_URL
=
test
.
get_url
(
'/oauth1/server/access_token'
)
def
_oauth_consumer_token
(
self
):
return
dict
(
key
=
'asdf'
,
secret
=
'qwer'
)
@
gen
.
coroutine
def
get
(
self
):
if
self
.
get_argument
(
'oauth_token'
,
None
):
user
=
yield
self
.
get_authenticated_user
(
http_client
=
self
.
settings
[
'http_client'
])
if
user
is
None
:
raise
Exception
(
"user is None"
)
self
.
finish
(
user
)
return
yield
self
.
authorize_redirect
(
http_client
=
self
.
settings
[
'http_client'
])
@
gen
.
coroutine
def
_oauth_get_user_future
(
self
,
access_token
):
if
self
.
get_argument
(
'fail_in_get_user'
,
None
):
raise
Exception
(
"failing in get_user"
)
if
access_token
!=
dict
(
key
=
'uiop'
,
secret
=
'5678'
):
raise
Exception
(
"incorrect access token %r"
%
access_token
)
return
dict
(
email
=
'foo@example.com'
)
class
OAuth1ClientLoginCoroutineHandler
(
OAuth1ClientLoginHandler
):
"""Replaces OAuth1ClientLoginCoroutineHandler's get() with a coroutine."""
@
gen
.
coroutine
...
...
@@ -172,7 +225,7 @@ class TwitterClientHandler(RequestHandler, TwitterMixin):
return
self
.
settings
[
'http_client'
]
class
TwitterClientLoginHandler
(
TwitterClientHandler
):
class
TwitterClientLoginHandler
Legacy
(
TwitterClientHandler
):
@
asynchronous
def
get
(
self
):
if
self
.
get_argument
(
"oauth_token"
,
None
):
...
...
@@ -186,6 +239,18 @@ class TwitterClientLoginHandler(TwitterClientHandler):
self
.
finish
(
user
)
class
TwitterClientLoginHandler
(
TwitterClientHandler
):
@
gen
.
coroutine
def
get
(
self
):
if
self
.
get_argument
(
"oauth_token"
,
None
):
user
=
yield
self
.
get_authenticated_user
()
if
user
is
None
:
raise
Exception
(
"user is None"
)
self
.
finish
(
user
)
return
yield
self
.
authorize_redirect
()
class
TwitterClientLoginGenEngineHandler
(
TwitterClientHandler
):
@
asynchronous
@
gen
.
engine
...
...
@@ -211,15 +276,17 @@ class TwitterClientLoginGenCoroutineHandler(TwitterClientHandler):
yield
self
.
authorize_redirect
()
class
TwitterClientShowUserHandler
(
TwitterClientHandler
):
class
TwitterClientShowUserHandler
Legacy
(
TwitterClientHandler
):
@
asynchronous
@
gen
.
engine
def
get
(
self
):
# TODO: would be nice to go through the login flow instead of
# cheating with a hard-coded access token.
response
=
yield
gen
.
Task
(
self
.
twitter_request
,
'/users/show/%s'
%
self
.
get_argument
(
'name'
),
access_token
=
dict
(
key
=
'hjkl'
,
secret
=
'vbnm'
))
with
warnings
.
catch_warnings
():
warnings
.
simplefilter
(
'ignore'
,
DeprecationWarning
)
response
=
yield
gen
.
Task
(
self
.
twitter_request
,
'/users/show/%s'
%
self
.
get_argument
(
'name'
),
access_token
=
dict
(
key
=
'hjkl'
,
secret
=
'vbnm'
))
if
response
is
None
:
self
.
set_status
(
500
)
self
.
finish
(
'error from twitter request'
)
...
...
@@ -227,6 +294,22 @@ class TwitterClientShowUserHandler(TwitterClientHandler):
self
.
finish
(
response
)
class
TwitterClientShowUserHandler
(
TwitterClientHandler
):
@
gen
.
coroutine
def
get
(
self
):
# TODO: would be nice to go through the login flow instead of
# cheating with a hard-coded access token.
try
:
response
=
yield
self
.
twitter_request
(
'/users/show/%s'
%
self
.
get_argument
(
'name'
),
access_token
=
dict
(
key
=
'hjkl'
,
secret
=
'vbnm'
))
except
AuthError
:
self
.
set_status
(
500
)
self
.
finish
(
'error from twitter request'
)
else
:
self
.
finish
(
response
)
class
TwitterClientShowUserFutureHandler
(
TwitterClientHandler
):
@
asynchronous
@
gen
.
engine
...
...
@@ -279,12 +362,17 @@ class AuthTest(AsyncHTTPTestCase):
return
Application
(
[
# test endpoints
(
'/legacy/openid/client/login'
,
OpenIdClientLoginHandlerLegacy
,
dict
(
test
=
self
)),
(
'/openid/client/login'
,
OpenIdClientLoginHandler
,
dict
(
test
=
self
)),
(
'/legacy/oauth10/client/login'
,
OAuth1ClientLoginHandlerLegacy
,
dict
(
test
=
self
,
version
=
'1.0'
)),
(
'/oauth10/client/login'
,
OAuth1ClientLoginHandler
,
dict
(
test
=
self
,
version
=
'1.0'
)),
(
'/oauth10/client/request_params'
,
OAuth1ClientRequestParametersHandler
,
dict
(
version
=
'1.0'
)),
(
'/legacy/oauth10a/client/login'
,
OAuth1ClientLoginHandlerLegacy
,
dict
(
test
=
self
,
version
=
'1.0a'
)),
(
'/oauth10a/client/login'
,
OAuth1ClientLoginHandler
,
dict
(
test
=
self
,
version
=
'1.0a'
)),
(
'/oauth10a/client/login_coroutine'
,
...
...
@@ -297,11 +385,14 @@ class AuthTest(AsyncHTTPTestCase):
(
'/facebook/client/login'
,
FacebookClientLoginHandler
,
dict
(
test
=
self
)),
(
'/legacy/twitter/client/login'
,
TwitterClientLoginHandlerLegacy
,
dict
(
test
=
self
)),
(
'/twitter/client/login'
,
TwitterClientLoginHandler
,
dict
(
test
=
self
)),
(
'/twitter/client/login_gen_engine'
,
TwitterClientLoginGenEngineHandler
,
dict
(
test
=
self
)),
(
'/twitter/client/login_gen_coroutine'
,
TwitterClientLoginGenCoroutineHandler
,
dict
(
test
=
self
)),
(
'/legacy/twitter/client/show_user'
,
TwitterClientShowUserHandlerLegacy
,
dict
(
test
=
self
)),
(
'/twitter/client/show_user'
,
TwitterClientShowUserHandler
,
dict
(
test
=
self
)),
(
'/twitter/client/show_user_future'
,
...
...
@@ -325,6 +416,21 @@ class AuthTest(AsyncHTTPTestCase):
facebook_api_key
=
'test_facebook_api_key'
,
facebook_secret
=
'test_facebook_secret'
)
def
test_openid_redirect_legacy
(
self
):
response
=
self
.
fetch
(
'/legacy/openid/client/login'
,
follow_redirects
=
False
)
self
.
assertEqual
(
response
.
code
,
302
)
self
.
assertTrue
(
'/openid/server/authenticate?'
in
response
.
headers
[
'Location'
])
def
test_openid_get_user_legacy
(
self
):
response
=
self
.
fetch
(
'/legacy/openid/client/login?openid.mode=blah'
'&openid.ns.ax=http://openid.net/srv/ax/1.0'
'&openid.ax.type.email=http://axschema.org/contact/email'
'&openid.ax.value.email=foo@example.com'
)
response
.
rethrow
()
parsed
=
json_decode
(
response
.
body
)
self
.
assertEqual
(
parsed
[
"email"
],
"foo@example.com"
)
def
test_openid_redirect
(
self
):
response
=
self
.
fetch
(
'/openid/client/login'
,
follow_redirects
=
False
)
self
.
assertEqual
(
response
.
code
,
302
)
...
...
@@ -340,6 +446,16 @@ class AuthTest(AsyncHTTPTestCase):
parsed
=
json_decode
(
response
.
body
)
self
.
assertEqual
(
parsed
[
"email"
],
"foo@example.com"
)
def
test_oauth10_redirect_legacy
(
self
):
response
=
self
.
fetch
(
'/legacy/oauth10/client/login'
,
follow_redirects
=
False
)
self
.
assertEqual
(
response
.
code
,
302
)
self
.
assertTrue
(
response
.
headers
[
'Location'
].
endswith
(
'/oauth1/server/authorize?oauth_token=zxcv'
))
# the cookie is base64('zxcv')|base64('1234')
self
.
assertTrue
(
'_oauth_request_token="enhjdg==|MTIzNA=="'
in
response
.
headers
[
'Set-Cookie'
],
response
.
headers
[
'Set-Cookie'
])
def
test_oauth10_redirect
(
self
):
response
=
self
.
fetch
(
'/oauth10/client/login'
,
follow_redirects
=
False
)
self
.
assertEqual
(
response
.
code
,
302
)
...
...
@@ -350,6 +466,16 @@ class AuthTest(AsyncHTTPTestCase):
'_oauth_request_token="enhjdg==|MTIzNA=="'
in
response
.
headers
[
'Set-Cookie'
],
response
.
headers
[
'Set-Cookie'
])
def
test_oauth10_get_user_legacy
(
self
):
with
ignore_deprecation
():
response
=
self
.
fetch
(
'/legacy/oauth10/client/login?oauth_token=zxcv'
,
headers
=
{
'Cookie'
:
'_oauth_request_token=enhjdg==|MTIzNA=='
})
response
.
rethrow
()
parsed
=
json_decode
(
response
.
body
)
self
.
assertEqual
(
parsed
[
'email'
],
'foo@example.com'
)
self
.
assertEqual
(
parsed
[
'access_token'
],
dict
(
key
=
'uiop'
,
secret
=
'5678'
))
def
test_oauth10_get_user
(
self
):
response
=
self
.
fetch
(
'/oauth10/client/login?oauth_token=zxcv'
,
...
...
@@ -368,6 +494,26 @@ class AuthTest(AsyncHTTPTestCase):
self
.
assertTrue
(
'oauth_nonce'
in
parsed
)
self
.
assertTrue
(
'oauth_signature'
in
parsed
)
def
test_oauth10a_redirect_legacy
(
self
):
response
=
self
.
fetch
(
'/legacy/oauth10a/client/login'
,
follow_redirects
=
False
)
self
.
assertEqual
(
response
.
code
,
302
)
self
.
assertTrue
(
response
.
headers
[
'Location'
].
endswith
(
'/oauth1/server/authorize?oauth_token=zxcv'
))
# the cookie is base64('zxcv')|base64('1234')
self
.
assertTrue
(
'_oauth_request_token="enhjdg==|MTIzNA=="'
in
response
.
headers
[
'Set-Cookie'
],
response
.
headers
[
'Set-Cookie'
])
def
test_oauth10a_get_user_legacy
(
self
):
with
ignore_deprecation
():
response
=
self
.
fetch
(
'/legacy/oauth10a/client/login?oauth_token=zxcv'
,
headers
=
{
'Cookie'
:
'_oauth_request_token=enhjdg==|MTIzNA=='
})
response
.
rethrow
()
parsed
=
json_decode
(
response
.
body
)
self
.
assertEqual
(
parsed
[
'email'
],
'foo@example.com'
)
self
.
assertEqual
(
parsed
[
'access_token'
],
dict
(
key
=
'uiop'
,
secret
=
'5678'
))
def
test_oauth10a_redirect
(
self
):
response
=
self
.
fetch
(
'/oauth10a/client/login'
,
follow_redirects
=
False
)
self
.
assertEqual
(
response
.
code
,
302
)
...
...
@@ -428,6 +574,9 @@ class AuthTest(AsyncHTTPTestCase):
'_oauth_request_token="enhjdg==|MTIzNA=="'
in
response
.
headers
[
'Set-Cookie'
],
response
.
headers
[
'Set-Cookie'
])
def
test_twitter_redirect_legacy
(
self
):
self
.
base_twitter_redirect
(
'/legacy/twitter/client/login'
)
def
test_twitter_redirect
(
self
):
self
.
base_twitter_redirect
(
'/twitter/client/login'
)
...
...
@@ -451,6 +600,18 @@ class AuthTest(AsyncHTTPTestCase):
u
'screen_name'
:
u
'foo'
,
u
'username'
:
u
'foo'
})
def
test_twitter_show_user_legacy
(
self
):
response
=
self
.
fetch
(
'/legacy/twitter/client/show_user?name=somebody'
)
response
.
rethrow
()
self
.
assertEqual
(
json_decode
(
response
.
body
),
{
'name'
:
'Somebody'
,
'screen_name'
:
'somebody'
})
def
test_twitter_show_user_error_legacy
(
self
):
with
ExpectLog
(
gen_log
,
'Error response HTTP 500'
):
response
=
self
.
fetch
(
'/legacy/twitter/client/show_user?name=error'
)
self
.
assertEqual
(
response
.
code
,
500
)
self
.
assertEqual
(
response
.
body
,
b
'error from twitter request'
)
def
test_twitter_show_user
(
self
):
response
=
self
.
fetch
(
'/twitter/client/show_user?name=somebody'
)
response
.
rethrow
()
...
...
@@ -458,8 +619,7 @@ class AuthTest(AsyncHTTPTestCase):
{
'name'
:
'Somebody'
,
'screen_name'
:
'somebody'
})
def
test_twitter_show_user_error
(
self
):
with
ExpectLog
(
gen_log
,
'Error response HTTP 500'
):
response
=
self
.
fetch
(
'/twitter/client/show_user?name=error'
)
response
=
self
.
fetch
(
'/twitter/client/show_user?name=error'
)
self
.
assertEqual
(
response
.
code
,
500
)
self
.
assertEqual
(
response
.
body
,
b
'error from twitter request'
)
...
...
tornado/test/concurrent_test.py
浏览文件 @
f98d06dd
...
...
@@ -31,7 +31,7 @@ from tornado.log import app_log
from
tornado
import
stack_context
from
tornado.tcpserver
import
TCPServer
from
tornado.testing
import
AsyncTestCase
,
ExpectLog
,
bind_unused_port
,
gen_test
from
tornado.test.util
import
unittest
,
skipBefore35
,
exec_test
from
tornado.test.util
import
unittest
,
skipBefore35
,
exec_test
,
ignore_deprecation
try
:
...
...
@@ -99,7 +99,8 @@ class ReturnFutureTest(AsyncTestCase):
self
.
return_value
(
callback
=
self
.
stop
)
def
test_callback_kw
(
self
):
future
=
self
.
sync_future
(
callback
=
self
.
stop
)
with
ignore_deprecation
():
future
=
self
.
sync_future
(
callback
=
self
.
stop
)
result
=
self
.
wait
()
self
.
assertEqual
(
result
,
42
)
self
.
assertEqual
(
future
.
result
(),
42
)
...
...
@@ -107,7 +108,8 @@ class ReturnFutureTest(AsyncTestCase):
def
test_callback_positional
(
self
):
# When the callback is passed in positionally, future_wrap shouldn't
# add another callback in the kwargs.
future
=
self
.
sync_future
(
self
.
stop
)
with
ignore_deprecation
():
future
=
self
.
sync_future
(
self
.
stop
)
result
=
self
.
wait
()
self
.
assertEqual
(
result
,
42
)
self
.
assertEqual
(
future
.
result
(),
42
)
...
...
@@ -154,20 +156,23 @@ class ReturnFutureTest(AsyncTestCase):
self
.
assertEqual
(
future
.
result
(),
42
)
def
test_error_in_callback
(
self
):
self
.
sync_future
(
callback
=
lambda
future
:
1
/
0
)
with
ignore_deprecation
():
self
.
sync_future
(
callback
=
lambda
future
:
1
/
0
)
# The exception gets caught by our StackContext and will be re-raised
# when we wait.
self
.
assertRaises
(
ZeroDivisionError
,
self
.
wait
)
def
test_no_result_future
(
self
):
future
=
self
.
no_result_future
(
self
.
stop
)
with
ignore_deprecation
():
future
=
self
.
no_result_future
(
self
.
stop
)
result
=
self
.
wait
()
self
.
assertIs
(
result
,
None
)
# result of this future is undefined, but not an error
future
.
result
()
def
test_no_result_future_callback
(
self
):
future
=
self
.
no_result_future
(
callback
=
lambda
:
self
.
stop
())
with
ignore_deprecation
():
future
=
self
.
no_result_future
(
callback
=
lambda
:
self
.
stop
())
result
=
self
.
wait
()
self
.
assertIs
(
result
,
None
)
future
.
result
()
...
...
@@ -334,12 +339,14 @@ class ClientTestMixin(object):
super
(
ClientTestMixin
,
self
).
tearDown
()
# type: ignore
def
test_callback
(
self
):
self
.
client
.
capitalize
(
"hello"
,
callback
=
self
.
stop
)
with
ignore_deprecation
():
self
.
client
.
capitalize
(
"hello"
,
callback
=
self
.
stop
)
result
=
self
.
wait
()
self
.
assertEqual
(
result
,
"HELLO"
)
def
test_callback_error
(
self
):
self
.
client
.
capitalize
(
"HELLO"
,
callback
=
self
.
stop
)
with
ignore_deprecation
():
self
.
client
.
capitalize
(
"HELLO"
,
callback
=
self
.
stop
)
self
.
assertRaisesRegexp
(
CapError
,
"already capitalized"
,
self
.
wait
)
def
test_future
(
self
):
...
...
tornado/test/util.py
浏览文件 @
f98d06dd
...
...
@@ -6,6 +6,7 @@ import platform
import
socket
import
sys
import
textwrap
import
warnings
from
tornado.testing
import
bind_unused_port
...
...
@@ -107,3 +108,11 @@ def subTest(test, *args, **kwargs):
except
AttributeError
:
subTest
=
contextlib
.
contextmanager
(
lambda
*
a
,
**
kw
:
(
yield
))
return
subTest
(
*
args
,
**
kwargs
)
@
contextlib
.
contextmanager
def
ignore_deprecation
():
"""Context manager to ignore deprecation warnings."""
with
warnings
.
catch_warnings
():
warnings
.
simplefilter
(
'ignore'
,
DeprecationWarning
)
yield
tornado/web.py
浏览文件 @
f98d06dd
...
...
@@ -246,7 +246,7 @@ class RequestHandler(object):
of the request method.
Asynchronous support: Decorate this method with `.gen.coroutine`
or
`.return_future
` to make it asynchronous (the
or
use ``async def`
` to make it asynchronous (the
`asynchronous` decorator cannot be used on `prepare`).
If this method returns a `.Future` execution will not proceed
until the `.Future` is done.
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录