Repository: tornadoweb/tornado

Issue:
web: document that `xsrf_token` is bytes
Hi, i just got a problem here please help me thanks.
this caused when i send a post request.


i have not  a form， use requests.post to post requests . 


Error: _xsrf' argument has invalid format

application setting:
            cookie_secret=os.urandom(64), 
            xsrf_cookies=True,

class JsonHandler(BaseHandler):
    def initialize(self):
         self.request.headers['X-Xsrftoken'] = self.xsrf_token

python 2.7.14 worked ok, but python 3.6 not work. show error:    _xsrf' argument has invalid format.



Discussion:
Can you show the actual header being sent over the wire (e.g. with packet captures)?

I suspect that this is because `self.xsrf_token` is a byte string and headers are character strings, and you're getting bitten by python3's implicit (but useless) conversion from bytes to str. Run python with the `-b` flag and see if you get warnings about implicit conversions.

If this analysis is accurate, the solution will be to convert `self.xsrf_token` to a character string before setting it as a header: `self.request.headers['X-Xsrf-token'] = tornado.escape.to_unicode(self.xsrf_token)`. 
class JsonHandler(tornado.web.RequestHandler, SessionMixin):
    def initialize(self):
        # self.request.headers['X-Xsrftoken'] = self.xsrf_token
        self.request.headers['X-Xsrf-token'] = tornado.escape.to_unicode(self.xsrf_token)


report error:
[W 180226 08:19:30 web:1587] 403 POST / (127.0.0.1): '_xsrf' argument missing from POST

class JsonHandler(tornado.web.RequestHandler, SessionMixin):
    def initialize(self):
        # self.request.headers['X-Xsrftoken'] = self.xsrf_token
        self.request.headers['X-Xsrftoken'] = tornado.escape.to_unicode(self.xsrf_token)

use X-Xsrftoken is ok, thanks.
OK, so I think we just need to document that `xsrf_token` is of type bytes and may need to be converted for use in contexts that require character strings.

(also, using `tornado.httpclient` might be easier than `requests` here, since `tornado.httpclient` shares the same model of bytes vs character strings as the rest of Tornado). 

Resolving patch:
diff --git a/tornado/ioloop.py b/tornado/ioloop.py
--- a/tornado/ioloop.py
+++ b/tornado/ioloop.py
@@ -244,7 +244,7 @@ def clear_instance():
            Previously, this method would clear the `IOLoop` used as
            the global singleton by `IOLoop.instance()`. Now that
            `instance()` is an alias for `current()`,
-           `clear_instance()` is an alias for `clear_instance()`.
+           `clear_instance()` is an alias for `clear_current()`.
 
         .. deprecated:: 5.0
 
diff --git a/tornado/web.py b/tornado/web.py
--- a/tornado/web.py
+++ b/tornado/web.py
@@ -1220,6 +1220,11 @@ def xsrf_token(self):
 
         See http://en.wikipedia.org/wiki/Cross-site_request_forgery
 
+        This property is of type `bytes`, but it contains only ASCII
+        characters. If a character string is required, there is no
+        need to base64-encode it; just decode the byte string as
+        UTF-8.
+
         .. versionchanged:: 3.2.2
            The xsrf token will now be have a random mask applied in every
            request, which makes it safe to include the token in pages
diff --git a/tornado/websocket.py b/tornado/websocket.py
--- a/tornado/websocket.py
+++ b/tornado/websocket.py
@@ -17,7 +17,6 @@
 """
 
 from __future__ import absolute_import, division, print_function
-# Author: Jacob Kristhammar, 2010
 
 import base64
 import collections


Test patch: