class Application(object):
def __call__(self, request):
"""Called by HTTPServer to execute the request."""
transforms = [t(request) for t in self.transforms]
handler = None
args = []
kwargs = {}
#根据请求的目标主机,匹配主机模版对应的正则表达式和Handlers
handlers = self._get_host_handlers(request)
if not handlers:
handler = RedirectHandler(
self, request, url="http://" + self.default_host + "/")
else:
for spec in handlers:
match = spec.regex.match(request.path)
if match:
# None-safe wrapper around url_unescape to handle
# unmatched optional groups correctly
def unquote(s):
if s is None: return s
return escape.url_unescape(s, encoding=None)
handler = spec.handler_class(self, request, **spec.kwargs) #创建RquestHandler对象
# Pass matched groups to the handler. Since
# match.groups() includes both named and unnamed groups,
# we want to use either groups or groupdict but not both.
# Note that args are passed as bytes so the handler can
# decide what encoding to use.
kwargs = dict((k, unquote(v))
for (k, v) in match.groupdict().iteritems())
if kwargs:
args = []
else:
args = [unquote(s) for s in match.groups()]
break
if not handler:
handler = ErrorHandler(self, request, status_code=404)
# In debug mode, re-compile templates and reload static files on every
# request so you don't need to restart to see changes
if self.settings.get("debug"):
if getattr(RequestHandler, "_templates", None):
for loader in RequestHandler._templates.values():
loader.reset()
RequestHandler._static_hashes = {}
#==== 执行RequestHandler的_execute方法 ====
handler._execute(transforms, *args, **kwargs)
return handler
class Application(object):
def _get_host_handlers(self, request):
#将请求的host和handlers中的主机模型进行匹配
host = request.host.lower().split(':')[0]
for pattern, handlers in self.handlers:
if pattern.match(host):
return handlers
# Look for default host if not behind load balancer (for debugging)if"X-Real-Ip"notin request.headers:
for pattern, handlers in self.handlers:
if pattern.match(self.default_host):
return handlers
return None
Application._get_host_handlers
class RequestHandler(object):
SUPPORTED_METHODS = ("GET", "HEAD", "POST", "DELETE", "PUT", "OPTIONS")
def__init__(self, application, request, **kwargs):
self.application = application
self.request = request
self._headers_written = False
self._finished = False
self._auto_finish = True
self._transforms = None # will be set in _execute#获取在application中设置的 ui_modules 和ui_method
self.ui = _O((n, self._ui_method(m)) for n, m in
application.ui_methods.iteritems())
self.ui["modules"] = _O((n, self._ui_module(n, m)) for n, m in
application.ui_modules.iteritems())
self.clear() #设置服务器、内容类型编码和连接# Check since connection is not available in WSGI#检查连接是否可用,应该是长短连接有关。if hasattr(self.request, "connection"):
self.request.connection.stream.set_close_callback(self.on_connection_close)
self.initialize(**kwargs)
def initialize(self):
passdef clear(self):
"""Resets all headers and content for this response."""
self._headers = {
"Server": "TornadoServer/%s" % tornado.version,
"Content-Type": "text/html; charset=UTF-8",
}
ifnot self.request.supports_http_1_1():
if self.request.headers.get("Connection") == "Keep-Alive":
self.set_header("Connection", "Keep-Alive")
self._write_buffer = []
self._status_code = 200
class RequestHandler(object):
def _execute(self, transforms, *args, **kwargs):
"""Executes this request with the given output transforms."""
self._transforms = transforms
with stack_context.ExceptionStackContext(
self._stack_context_handle_exception):
if self.request.method not in self.SUPPORTED_METHODS:
raise HTTPError(405)
# If XSRF cookies are turned on, reject form submissions without
# the proper cookie
if self.request.method not in ("GET", "HEAD") and
self.application.settings.get("xsrf_cookies"):
self.check_xsrf_cookie()
self.prepare()
if not self._finished:
#通过反射的方法,执行 RequestHandler 派生类的的 get、post、put方法
getattr(self, self.request.method.lower())(*args, **kwargs)
if self._auto_finish and not self._finished:
self.finish()
例:用户发送get请求
class MyHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, world")
MyHandler.get
class RequestHandler(object):
def write(self, chunk):
assertnot self._finished
if isinstance(chunk, dict):
chunk = escape.json_encode(chunk)
self.set_header("Content-Type", "text/javascript; charset=UTF-8")
chunk = _utf8(chunk)
self._write_buffer.append(chunk)
class RequestHandler:
def finish(self, chunk=None):
"""Finishes this response, ending the HTTP request."""
assert not self._finished
if chunk is not None: self.write(chunk)
if not self._headers_written:
if (self._status_code == 200 and
self.request.method in ("GET", "HEAD") and
"Etag" not in self._headers):
hasher = hashlib.sha1()
for part in self._write_buffer:
hasher.update(part)
etag = '"%s"' % hasher.hexdigest()
inm = self.request.headers.get("If-None-Match")
if inm and inm.find(etag) != -1:
self._write_buffer = []
self.set_status(304)
else:
self.set_header("Etag", etag)
if "Content-Length" not in self._headers:
content_length = sum(len(part) for part in self._write_buffer)
self.set_header("Content-Length", content_length)
if hasattr(self.request, "connection"):
self.request.connection.stream.set_close_callback(None)
if not self.application._wsgi:
#将处理请求返回的数据发送到IOStream的_write_buffer队列中
self.flush(include_footers=True)
self.request.finish()
#纪录日志
self._log()
self._finished = True
3.15、执行RequestHandler的flush方法
此处代码主要有一项任务:
将处理请求返回的数据发送到IOStream的_write_buffer队列中
def flush(self, include_footers=False):
"""Flushes the current output buffer to the network."""
if self.application._wsgi:
raise Exception("WSGI applications do not support flush()")
chunk = "".join(self._write_buffer)
self._write_buffer = []
if not self._headers_written:
self._headers_written = True
for transform in self._transforms:
self._headers, chunk = transform.transform_first_chunk(
self._headers, chunk, include_footers)
headers = self._generate_headers()
else:
for transform in self._transforms:
chunk = transform.transform_chunk(chunk, include_footers)
headers = ""
# Ignore the chunk and only write the headers for HEAD requests
if self.request.method == "HEAD":
if headers: self.request.write(headers)
return
if headers or chunk:
#执行HTTPReqeust的write方法
self.request.write(headers + chunk)
class HTTPRequest(object):
def write(self, chunk):
"""Writes the given chunk to the response stream."""assert isinstance(chunk, str)
#执行HTTPConnection的write方法
self.connection.write(chunk)
class IOStream(object):
def _handle_events(self, fd, events):
if not self.socket:
logging.warning("Got events for closed stream %d", fd)
return
try:
if events & self.io_loop.READ:
self._handle_read()
if not self.socket:
return
if events & self.io_loop.WRITE:
if self._connecting:
self._handle_connect()
#执行_handle_write方法,内部调用socket.send将数据响应给客户端
self._handle_write()
if not self.socket:
return
if events & self.io_loop.ERROR:
self.close()
return
state = self.io_loop.ERROR
if self.reading():
state |= self.io_loop.READ
if self.writing():
state |= self.io_loop.WRITE
if state != self._state:
self._state = state
self.io_loop.update_handler(self.socket.fileno(), self._state)
except:
logging.error("Uncaught exception, closing connection.",
exc_info=True)
self.close()
raise
3.22、IOStream的_handle_write方法
此段代码主要有两项任务:
调用socket.send给客户端发送响应数据
执行回调函数HTTPConnection的_on_write_complete方法
class IOStream(object):
def _handle_write(self):
while self._write_buffer:
try:
if not self._write_buffer_frozen:
_merge_prefix(self._write_buffer, 128 * 1024)
#调用客户端socket对象的send方法发送数据
num_bytes = self.socket.send(self._write_buffer[0])
self._write_buffer_frozen = False
_merge_prefix(self._write_buffer, num_bytes)
self._write_buffer.popleft()
except socket.error, e:
if e.args[0] in (errno.EWOULDBLOCK, errno.EAGAIN):
self._write_buffer_frozen = True
break
else:
logging.warning("Write error on %d: %s",
self.socket.fileno(), e)
self.close()
return
if not self._write_buffer and self._write_callback:
callback = self._write_callback
self._write_callback = None
#执行回调函数关闭客户端socket连接(HTTPConnection的_on_write_complete方法)
self._run_callback(callback)
class IOStream(object):
def _run_callback(self, callback, *args, **kwargs):
try:
with stack_context.NullContext():
callback(*args, **kwargs)
except:
logging.error("Uncaught exception, closing connection.",
exc_info=True)
self.close()
raise
class HTTPConnection(object):
def _on_write_complete(self):
if self._request_finished:
self._finish_request()
def _finish_request(self):
if self.no_keep_alive:
disconnect = True
else:
connection_header = self._request.headers.get("Connection")
if self._request.supports_http_1_1():
disconnect = connection_header == "close"
elif ("Content-Length" in self._request.headers
or self._request.method in ("HEAD", "GET")):
disconnect = connection_header != "Keep-Alive"
else:
disconnect = True
self._request = None
self._request_finished = False
if disconnect:
self.stream.close()
return
self.stream.read_until("
", self._header_callback)
class IOStream(object):
def read_until(self, delimiter, callback):
"""Call callback when we read the given delimiter."""assertnot self._read_callback, "Already reading"
self._read_delimiter = delimiter
self._read_callback = stack_context.wrap(callback)
while True:
# See if we've already got the data from a previous readif self._read_from_buffer():
return
self._check_closed()
if self._read_to_buffer() == 0:
break#更新为READ
self._add_io_state(self.io_loop.READ)
IOStream.read_until
class IOStream(object):
def _add_io_state(self, state):
if self.socket is None:
# connection has been closed, so there can be no future eventsreturnifnot self._state & state:
self._state = self._state | state
#执行IOLoop对象的update_handler方法
self.io_loop.update_handler(self.socket.fileno(), self._state)
IOStream._add_io_state
class IOLoop(object):
def update_handler(self, fd, events):
"""Changes the events we listen for fd."""#self._impl就是epoll对象
self._impl.modify(fd, events | self.ERROR)
IOLoop.update_handler
3.24、IOStream的_handle_write方法(含3.25、3.26)
此段代码主要有一项任务:
关闭客户端socket
class IOStream(object):
def _handle_events(self, fd, events):
if not self.socket:
logging.warning("Got events for closed stream %d", fd)
return
try:
#由于在 2.23 步骤中已经将epoll的状态更新为READ,所以这次会执行_handle_read方法
if events & self.io_loop.READ:
self._handle_read()
#执行完_handle_read后,客户端socket被关闭且置空,所有此处就会执行return
if not self.socket:
return
#===============================终止===========================
if events & self.io_loop.WRITE:
if self._connecting:
self._handle_connect()
self._handle_write()
if not self.socket:
return
if events & self.io_loop.ERROR:
self.close()
return
state = self.io_loop.ERROR
if self.reading():
state |= self.io_loop.READ
if self.writing():
state |= self.io_loop.WRITE
if state != self._state:
self._state = state
self.io_loop.update_handler(self.socket.fileno(), self._state)
except:
logging.error("Uncaught exception, closing connection.",
exc_info=True)
self.close()
raise
class IOStream(object):
def _handle_read(self):
while True:
try:
# Read from the socket until we get EWOULDBLOCK or equivalent.# SSL sockets do some internal buffering, and if the data is# sitting in the SSL object's buffer select() and friends# can't see it; the only way to find out if it's there is to# try to read it.
result = self._read_to_buffer()
except Exception:
self.close()
returnif result == 0:
breakelse:
if self._read_from_buffer():
return
IOStream._handle_read
class IOStream(object):
def _read_from_socket(self):
"""Attempts to read from the socket.
Returns the data read or None if there is nothing to read.
May be overridden in subclasses.
"""try:
chunk = self.socket.recv(self.read_chunk_size)
except socket.error, e:
if e.args[0] in (errno.EWOULDBLOCK, errno.EAGAIN):
return None
else:
raiseifnot chunk:
#执行close方法 self.close()
return None
return chunk
IOStream._read_from_socket
class IOStream(object):
def close(self):
"""Close this stream."""if self.socket isnot None:
#将客户端socket句柄在epoll中的移除,即:不再监听此客户端请求。 self.io_loop.remove_handler(self.socket.fileno())
#关闭客户端socket self.socket.close()
#将socket置空
self.socket = None
if self._close_callback:
self._run_callback(self._close_callback)
IOStream.close
class IOLoop(object):
def remove_handler(self, fd):
"""Stop listening for events on fd."""
self._handlers.pop(fd, None)
self._events.pop(fd, None)
try:
self._impl.unregister(fd)
except (OSError, IOError):
logging.debug("Error deleting fd from IOLoop", exc_info=True)