class HTTPRequest(object):
    """HTTP client request object."""

    # Default values for HTTPRequest parameters.
    # Merged with the values on the request object by AsyncHTTPClient
    # implementations.
    _DEFAULTS = dict(
        connect_timeout=20.0,
        request_timeout=20.0,
        follow_redirects=True,
        max_redirects=5,
        use_gzip=True,
        proxy_password='',
        allow_nonstandard_methods=False,
        validate_cert=True)

    def __init__(self, url, method="GET", headers=None, body=None,
                 auth_username=None, auth_password=None,
                 connect_timeout=None, request_timeout=None,
                 if_modified_since=None, follow_redirects=None,
                 max_redirects=None, user_agent=None, use_gzip=None,
                 network_interface=None, streaming_callback=None,
                 header_callback=None, prepare_curl_callback=None,
                 proxy_host=None, proxy_port=None, proxy_username=None,
                 proxy_password=None, allow_nonstandard_methods=None,
                 validate_cert=None, ca_certs=None,
                 allow_ipv6=None,
                 client_key=None, client_cert=None):
        r"""Creates an `HTTPRequest`.

        All parameters except `url` are optional.

        :arg string url: URL to fetch
        :arg string method: HTTP method, e.g. "GET" or "POST"
        :arg headers: Additional HTTP headers to pass on the request
        :type headers: `~tornado.httputil.HTTPHeaders` or `dict`
        :arg string auth_username: Username for HTTP "Basic" authentication
        :arg string auth_password: Password for HTTP "Basic" authentication
        :arg float connect_timeout: Timeout for initial connection in seconds
        :arg float request_timeout: Timeout for entire request in seconds
        :arg datetime if_modified_since: Timestamp for ``If-Modified-Since``
           header
        :arg bool follow_redirects: Should redirects be followed automatically
           or return the 3xx response?
        :arg int max_redirects: Limit for `follow_redirects`
        :arg string user_agent: String to send as ``User-Agent`` header
        :arg bool use_gzip: Request gzip encoding from the server
        :arg string network_interface: Network interface to use for request
        :arg callable streaming_callback: If set, `streaming_callback` will
           be run with each chunk of data as it is received, and
           `~HTTPResponse.body` and `~HTTPResponse.buffer` will be empty in
           the final response.
        :arg callable header_callback: If set, `header_callback` will
           be run with each header line as it is received (including the
           first line, e.g. ``HTTP/1.0 200 OK\r\n``, and a final line
           containing only ``\r\n``.  All lines include the trailing newline
           characters).  `~HTTPResponse.headers` will be empty in the final
           response.  This is most useful in conjunction with
           `streaming_callback`, because it's the only way to get access to
           header data while the request is in progress.
        :arg callable prepare_curl_callback: If set, will be called with
           a `pycurl.Curl` object to allow the application to make additional
           `setopt` calls.
        :arg string proxy_host: HTTP proxy hostname.  To use proxies,
           `proxy_host` and `proxy_port` must be set; `proxy_username` and
           `proxy_pass` are optional.  Proxies are currently only support
           with `curl_httpclient`.
        :arg int proxy_port: HTTP proxy port
        :arg string proxy_username: HTTP proxy username
        :arg string proxy_password: HTTP proxy password
        :arg bool allow_nonstandard_methods: Allow unknown values for `method`
           argument?
        :arg bool validate_cert: For HTTPS requests, validate the server's
           certificate?
        :arg string ca_certs: filename of CA certificates in PEM format,
           or None to use defaults.  Note that in `curl_httpclient`, if
           any request uses a custom `ca_certs` file, they all must (they
           don't have to all use the same `ca_certs`, but it's not possible
           to mix requests with ca_certs and requests that use the defaults.
        :arg bool allow_ipv6: Use IPv6 when available?  Default is false in
           `simple_httpclient` and true in `curl_httpclient`
        :arg string client_key: Filename for client SSL key, if any
        :arg string client_cert: Filename for client SSL certificate, if any
        """
        if headers is None:
            headers = httputil.HTTPHeaders()
        if if_modified_since:
            timestamp = calendar.timegm(if_modified_since.utctimetuple())
            headers["If-Modified-Since"] = email.utils.formatdate(
                timestamp, localtime=False, usegmt=True)
        self.proxy_host = proxy_host
        self.proxy_port = proxy_port
        self.proxy_username = proxy_username
        self.proxy_password = proxy_password
        self.url = url
        self.method = method
        self.headers = headers
        self.body = utf8(body)
        self.auth_username = auth_username
        self.auth_password = auth_password
        self.connect_timeout = connect_timeout
        self.request_timeout = request_timeout
        self.follow_redirects = follow_redirects
        self.max_redirects = max_redirects
        self.user_agent = user_agent
        self.use_gzip = use_gzip
        self.network_interface = network_interface
        self.streaming_callback = stack_context.wrap(streaming_callback)
        self.header_callback = stack_context.wrap(header_callback)
        self.prepare_curl_callback = stack_context.wrap(prepare_curl_callback)
        self.allow_nonstandard_methods = allow_nonstandard_methods
        self.validate_cert = validate_cert
        self.ca_certs = ca_certs
        self.allow_ipv6 = allow_ipv6
        self.client_key = client_key
        self.client_cert = client_cert
        self.start_time = time.time() class _RequestProxy(object):
    """Combines an object with a dictionary of defaults.

    Used internally by AsyncHTTPClient implementations.
    """
    def __init__(self, request, defaults):
        self.request = request
        self.defaults = defaults

    def __getattr__(self, name):
        request_attr = getattr(self.request, name)
        if request_attr is not None:
            return request_attr
        elif self.defaults is not None:
            return self.defaults.get(name, None)
        else:
            return None class IOStream(BaseIOStream):
    r"""Socket-based IOStream implementation.

    This class supports the read and write methods from `BaseIOStream`
    plus a `connect` method.

    The socket parameter may either be connected or unconnected.  For
    server operations the socket is the result of calling socket.accept().
    For client operations the socket is created with socket.socket(),
    and may either be connected before passing it to the IOStream or
    connected with IOStream.connect.

    A very simple (and broken) HTTP client using this class::

        from tornado import ioloop
        from tornado import iostream
        import socket

        def send_request():
            stream.write("GET / HTTP/1.0\r\nHost: friendfeed.com\r\n\r\n")
            stream.read_until("\r\n\r\n", on_headers)

        def on_headers(data):
            headers = {}
            for line in data.split("\r\n"):
               parts = line.split(":")
               if len(parts) == 2:
                   headers[parts[0].strip()] = parts[1].strip()
            stream.read_bytes(int(headers["Content-Length"]), on_body)

        def on_body(data):
            print data
            stream.close()
            ioloop.IOLoop.instance().stop()

        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
        stream = iostream.IOStream(s)
        stream.connect(("friendfeed.com", 80), send_request)
        ioloop.IOLoop.instance().start()
    """
    def __init__(self, socket, *args, **kwargs):
        self.socket = socket
        self.socket.setblocking(False)
        super(IOStream, self).__init__(*args, **kwargs)

    def fileno(self):
        return self.socket.fileno()

    def close_fd(self):
        self.socket.close()
        self.socket = None

    def get_fd_error(self):
        errno = self.socket.getsockopt(socket.SOL_SOCKET,
                                       socket.SO_ERROR)
        return socket.error(errno, os.strerror(errno))

    def read_from_fd(self):
        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:
                raise
        if not chunk:
            self.close()
            return None
        return chunk

    def write_to_fd(self, data):
        return self.socket.send(data)

    def connect(self, address, callback=None):
        """Connects the socket to a remote address without blocking.

        May only be called if the socket passed to the constructor was
        not previously connected.  The address parameter is in the
        same format as for socket.connect, i.e. a (host, port) tuple.
        If callback is specified, it will be called when the
        connection is completed.

        Note that it is safe to call IOStream.write while the
        connection is pending, in which case the data will be written
        as soon as the connection is ready.  Calling IOStream read
        methods before the socket is connected works on some platforms
        but is non-portable.
        """
        self._connecting = True
        try:
            self.socket.connect(address)
        except socket.error, e:
            # In non-blocking mode we expect connect() to raise an
            # exception with EINPROGRESS or EWOULDBLOCK.
            #
            # On freebsd, other errors such as ECONNREFUSED may be
            # returned immediately when attempting to connect to
            # localhost, so handle them the same way as an error
            # reported later in _handle_connect.
            if e.args[0] not in (errno.EINPROGRESS, errno.EWOULDBLOCK):
                gen_log.warning("Connect error on fd %d: %s",
                                self.socket.fileno(), e)
                self.close()
                return
        self._connect_callback = stack_context.wrap(callback)
        self._add_io_state(self.io_loop.WRITE)

    def _handle_connect(self):
        err = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
        if err != 0:
            self.error = socket.error(err, os.strerror(err))
            # IOLoop implementations may vary: some of them return
            # an error state before the socket becomes writable, so
            # in that case a connection failure would be handled by the
            # error path in _handle_events instead of here.
            gen_log.warning("Connect error on fd %d: %s",
                            self.socket.fileno(), errno.errorcode[err])
            self.close()
            return
        if self._connect_callback is not None:
            callback = self._connect_callback
            self._connect_callback = None
            self._run_callback(callback)
        self._connecting = False class TCPServer(object):
class Resolver(object):
    def __init__(self, io_loop=None, ssl_options=None):
    def listen(self, port, address=""):
    def add_sockets(self, sockets):
    def add_socket(self, socket):
    def bind(self, port, address=None, family=socket.AF_UNSPEC, backlog=128):
    def start(self, num_processes=1):
    def stop(self):
    def handle_stream(self, stream, address):
    def _handle_connection(self, connection, address):
def bind_sockets(port, address=None, family=socket.AF_UNSPEC, backlog=128, flags=None):
    def bind_unix_socket(file, mode=0600, backlog=128):
def add_accept_handler(sock, callback, io_loop=None):
    def accept_handler(fd, events):
    def __init__(self, io_loop=None, executor=None):
    def getaddrinfo(self, *args, **kwargs): class ExceptionStackContext(object):
    '''Specialization of StackContext for exception handling.

    The supplied exception_handler function will be called in the
    event of an uncaught exception in this context.  The semantics are
    similar to a try/finally clause, and intended use cases are to log
    an error, close a socket, or similar cleanup actions.  The
    exc_info triple (type, value, traceback) will be passed to the
    exception_handler function.

    If the exception handler returns true, the exception will be
    consumed and will not be propagated to other exception handlers.
    '''
    def __init__(self, exception_handler, _active_cell=None):
        self.exception_handler = exception_handler
        self.active_cell = _active_cell or [True]

    def __enter__(self):
        self.old_contexts = _state.contexts
        _state.contexts = (self.old_contexts +
                           ((ExceptionStackContext, self.exception_handler,
                             self.active_cell),))
        return lambda: operator.setitem(self.active_cell, 0, False)

    def __exit__(self, type, value, traceback):
        try:
            if type is not None:
                return self.exception_handler(type, value, traceback)
        finally:
            _state.contexts = self.old_contexts
            self.old_contexts = None class NullContext(object):
    '''Resets the StackContext.

    Useful when creating a shared resource on demand (e.g. an AsyncHTTPClient)
    where the stack that caused the creating is not relevant to future
    operations.
    '''
    def __enter__(self):
        self.old_contexts = _state.contexts
        _state.contexts = ()

    def __exit__(self, type, value, traceback):
        _state.contexts = self.old_contexts class AsyncHTTPTestCase(AsyncTestCase):
    '''A test case that starts up an HTTP server.

    Subclasses must override get_app(), which returns the
    tornado.web.Application (or other HTTPServer callback) to be tested.
    Tests will typically use the provided self.http_client to fetch
    URLs from this server.

    Example::

        class MyHTTPTest(AsyncHTTPTestCase):
            def get_app(self):
                return Application([('/', MyHandler)...])

            def test_homepage(self):
                # The following two lines are equivalent to
                #   response = self.fetch('/')
                # but are shown in full here to demonstrate explicit use
                # of self.stop and self.wait.
                self.http_client.fetch(self.get_url('/'), self.stop)
                response = self.wait()
                # test contents of response
    '''
    def setUp(self):
        super(AsyncHTTPTestCase, self).setUp()
        sock, port = bind_unused_port()
        self.__port = port

        self.http_client = self.get_http_client()
        self._app = self.get_app()
        self.http_server = self.get_http_server()
        self.http_server.add_sockets([sock])

    def get_http_client(self):
        return AsyncHTTPClient(io_loop=self.io_loop)

    def get_http_server(self):
        return HTTPServer(self._app, io_loop=self.io_loop,
                          **self.get_httpserver_options())

    def get_app(self):
        """Should be overridden by subclasses to return a
        tornado.web.Application or other HTTPServer callback.
        """
        raise NotImplementedError()

    def fetch(self, path, **kwargs):
        """Convenience method to synchronously fetch a url.

        The given path will be appended to the local server's host and port.
        Any additional kwargs will be passed directly to
        AsyncHTTPClient.fetch (and so could be used to pass method="POST",
        body="...", etc).
        """
        self.http_client.fetch(self.get_url(path), self.stop, **kwargs)
        return self.wait()

    def get_httpserver_options(self):
        """May be overridden by subclasses to return additional
        keyword arguments for the server.
        """
        return {}

    def get_http_port(self):
        """Returns the port used by the server.

        A new port is chosen for each test.
        """
        return self.__port

    def get_protocol(self):
        return 'http'

    def get_url(self, path):
        """Returns an absolute url for the given path on the test server."""
        return '%s://localhost:%s%s' % (self.get_protocol(),
                                        self.get_http_port(), path)

    def tearDown(self):
        self.http_server.stop()
        if (not IOLoop.initialized() or
            self.http_client.io_loop is not IOLoop.instance()):
            self.http_client.close()
        super(AsyncHTTPTestCase, self).tearDown() def bind_unused_port():
    """Binds a server socket to an available port on localhost.

    Returns a tuple (socket, port).
    """
    [sock] = netutil.bind_sockets(0, 'localhost', family=socket.AF_INET)
    port = sock.getsockname()[1]
    return sock, port class ObjectDict(dict):
class GzipDecompressor(object):
class Configurable(object):
    def __getattr__(self, name):
    def __setattr__(self, name, value):
    def __init__(self):
    def decompress(self, value):
    def flush(self):
def import_object(name):
    def b(s):
    def b(s):
def raise_exc_info(exc_info):
    def __new__(cls, **kwargs):
    def configurable_base(cls):
    def configurable_default(cls):
    def initialize(self):
    def configure(cls, impl, **kwargs):
    def configured_class(cls):
    def _save_configuration(cls):
    def _restore_configuration(cls, saved):
def doctests(): class RequestHandler(object):
class Application(object):
class HTTPError(Exception):
class ErrorHandler(RequestHandler):
class RedirectHandler(RequestHandler):
class StaticFileHandler(RequestHandler):
class FallbackHandler(RequestHandler):
class OutputTransform(object):
class GZipContentEncoding(OutputTransform):
class ChunkedTransferEncoding(OutputTransform):
class UIModule(object):
class _linkify(UIModule):
class _xsrf_form_html(UIModule):
class TemplateModule(UIModule):
class URLSpec(object):
    SUPPORTED_METHODS = ("GET", "HEAD", "POST", "DELETE", "PATCH", "PUT",
                         "OPTIONS")
    _ARG_DEFAULT = []
    CACHE_MAX_AGE = 86400 * 365 * 10  # 10 years
    CONTENT_TYPES = set([
        "text/plain", "text/html", "text/css", "text/xml", "application/javascript",
        "application/x-javascript", "application/xml", "application/atom+xml",
        "text/javascript", "application/json", "application/xhtml+xml"])
    MIN_LENGTH = 5
    def __init__(self, application, request, **kwargs):
    def initialize(self):
    def settings(self):
    def head(self, *args, **kwargs):
    def get(self, *args, **kwargs):
    def post(self, *args, **kwargs):
    def delete(self, *args, **kwargs):
    def patch(self, *args, **kwargs):
    def put(self, *args, **kwargs):
    def options(self, *args, **kwargs):
    def prepare(self):
    def on_finish(self):
    def on_connection_close(self):
    def clear(self):
    def set_default_headers(self):
    def set_status(self, status_code, reason=None):
    def get_status(self):
    def set_header(self, name, value):
    def add_header(self, name, value):
    def clear_header(self, name):
    def _convert_header_value(self, value):
    def get_argument(self, name, default=_ARG_DEFAULT, strip=True):
    def get_arguments(self, name, strip=True):
    def decode_argument(self, value, name=None):
    def cookies(self):
    def get_cookie(self, name, default=None):
    def set_cookie(self, name, value, domain=None, expires=None, path="/",
                   expires_days=None, **kwargs):
    def clear_cookie(self, name, path="/", domain=None):
    def clear_all_cookies(self):
    def set_secure_cookie(self, name, value, expires_days=30, **kwargs):
    def create_signed_value(self, name, value):
    def get_secure_cookie(self, name, value=None, max_age_days=31):
    def redirect(self, url, permanent=False, status=None):
    def write(self, chunk):
    def render(self, template_name, **kwargs):
        def is_absolute(path):
    def render_string(self, template_name, **kwargs):
    def get_template_namespace(self):
    def create_template_loader(self, template_path):
    def flush(self, include_footers=False, callback=None):
    def finish(self, chunk=None):
    def send_error(self, status_code=500, **kwargs):
    def write_error(self, status_code, **kwargs):
    def locale(self):
    def get_user_locale(self):
    def get_browser_locale(self, default="en_US"):
    def current_user(self):
    def get_current_user(self):
    def get_login_url(self):
    def get_template_path(self):
    def xsrf_token(self):
    def check_xsrf_cookie(self):
    def xsrf_form_html(self):
    def static_url(self, path, include_host=None):
    def async_callback(self, callback, *args, **kwargs):
        def wrapper(*args, **kwargs):
    def require_setting(self, name, feature="this feature"):
    def reverse_url(self, name, *args):
    def compute_etag(self):
    def _stack_context_handle_exception(self, type, value, traceback):
    def _execute(self, transforms, *args, **kwargs):
    def _generate_headers(self):
    def _log(self):
    def _request_summary(self):
    def _handle_request_exception(self, e):
    def _ui_module(self, name, module):
        def render(*args, **kwargs):
    def _ui_method(self, method):
    def _clear_headers_for_304(self):
def asynchronous(method):
    def wrapper(self, *args, **kwargs):
def removeslash(method):
    def wrapper(self, *args, **kwargs):
def addslash(method):
    def wrapper(self, *args, **kwargs):
    def __init__(self, handlers=None, default_host="", transforms=None,
                 wsgi=False, **settings):
    def listen(self, port, address="", **kwargs):
    def add_handlers(self, host_pattern, host_handlers):
    def add_transform(self, transform_class):
    def _get_host_handlers(self, request):
    def _load_ui_methods(self, methods):
    def _load_ui_modules(self, modules):
    def __call__(self, request):
                        def unquote(s):
    def reverse_url(self, name, *args):
    def log_request(self, handler):
    def __init__(self, status_code, log_message=None, *args, **kwargs):
    def __str__(self):
    def initialize(self, status_code):
    def prepare(self):
    def check_xsrf_cookie(self):
    def initialize(self, url, permanent=True):
    def get(self):
    def initialize(self, path, default_filename=None):
    def reset(cls):
    def head(self, path):
    def get(self, path, include_body=True):
    def set_extra_headers(self, path):
    def get_cache_time(self, path, modified, mime_type):
    def make_static_url(cls, settings, path):
    def get_version(cls, settings, path):
    def parse_url_path(self, url_path):
    def initialize(self, fallback):
    def prepare(self):
    def __init__(self, request):
    def transform_first_chunk(self, status_code, headers, chunk, finishing):
    def transform_chunk(self, chunk, finishing):
    def __init__(self, request):
    def transform_first_chunk(self, status_code, headers, chunk, finishing):
    def transform_chunk(self, chunk, finishing):
    def __init__(self, request):
    def transform_first_chunk(self, status_code, headers, chunk, finishing):
    def transform_chunk(self, block, finishing):
def authenticated(method):
    def wrapper(self, *args, **kwargs):
    def __init__(self, handler):
    def render(self, *args, **kwargs):
    def embedded_javascript(self):
    def javascript_files(self):
    def embedded_css(self):
    def css_files(self):
    def html_head(self):
    def html_body(self):
    def render_string(self, path, **kwargs):
    def render(self, text, **kwargs):
    def render(self):
    def __init__(self, handler):
    def render(self, path, **kwargs):
        def set_resources(**kwargs):
    def _get_resources(self, key):
    def embedded_javascript(self):
    def javascript_files(self):
    def embedded_css(self):
    def css_files(self):
    def html_head(self):
    def html_body(self):
    def __init__(self, pattern, handler_class, kwargs=None, name=None):
    def __repr__(self):
    def _find_groups(self):
    def reverse(self, *args):
    def _time_independent_equals(a, b):
def create_signed_value(secret, name, value):
def decode_signed_value(secret, name, value, max_age_days=31):
def _create_signature(secret, *parts):
import base64
import binascii
import functools
import re
import sys
from contextlib import closing
from tornado.escape import utf8
from tornado.httpclient import HTTPRequest, _RequestProxy
from tornado.iostream import IOStream
from tornado import netutil
from tornado.stack_context import ExceptionStackContext, NullContext
from tornado.testing import AsyncHTTPTestCase, bind_unused_port
from tornado.test.util import unittest
from tornado.util import b, bytes_type
from tornado.web import Application, RequestHandler, url
        response = self.fetch("/countdown/2", follow_redirects=False)
        self.assertEqual(302, response.code)
        self.assertTrue(response.headers["Location"].endswith("/countdown/1"))

        response = self.fetch("/countdown/2")
        self.assertEqual(200, response.code)
        self.assertTrue(response.effective_url.endswith("/countdown/0"))
        self.assertEqual(b("Zero"), response.body)

    def test_credentials_in_url(self):
        url = self.get_url("/auth").replace("http://", "http://me:secret@")
        self.http_client.fetch(url, self.stop)
        response = self.wait()
        self.assertEqual(b("Basic ") + base64.b64encode(b("me:secret")),
                         response.body)

    def test_body_encoding(self):
        unicode_body = u"\xe9"
        byte_body = binascii.a2b_hex(b("e9"))

        # unicode string in body gets converted to utf8
        response = self.fetch("/echopost", method="POST", body=unicode_body,
                              headers={"Content-Type": "application/blah"})
        self.assertEqual(response.headers["Content-Length"], "2")
        self.assertEqual(response.body, utf8(unicode_body))

        # byte strings pass through directly
        response = self.fetch("/echopost", method="POST",
                              body=byte_body,
                              headers={"Content-Type": "application/blah"})
        self.assertEqual(response.headers["Content-Length"], "1")
        self.assertEqual(response.body, byte_body)

        # Mixing unicode in headers and byte string bodies shouldn't
        # break anything
        response = self.fetch("/echopost", method="POST", body=byte_body,
                              headers={"Content-Type": "application/blah"},
                              user_agent=u"foo")
        self.assertEqual(response.headers["Content-Length"], "1")
        self.assertEqual(response.body, byte_body)

    def test_types(self):
        response = self.fetch("/hello")
        self.assertEqual(type(response.body), bytes_type)
        self.assertEqual(type(response.headers["Content-Type"]), str)
        self.assertEqual(type(response.code), int)
        self.assertEqual(type(response.effective_url), str)

    def test_header_callback(self):
        first_line = []
        headers = {}
        chunks = []

        def header_callback(header_line):
            if header_line.startswith('HTTP/'):
                first_line.append(header_line)
            elif header_line != '\r\n':
                k, v = header_line.split(':', 1)
                headers[k] = v.strip()

        def streaming_callback(chunk):
            # All header callbacks are run before any streaming callbacks,
            # so the header data is available to process the data as it
            # comes in.
            self.assertEqual(headers['Content-Type'], 'text/html; charset=UTF-8')
            chunks.append(chunk)

        self.fetch('/chunk', header_callback=header_callback,
                   streaming_callback=streaming_callback)
        self.assertEqual(len(first_line), 1)
        self.assertRegexpMatches(first_line[0], 'HTTP/1.[01] 200 OK\r\n')
        self.assertEqual(chunks, [b('asdf'), b('qwer')])

    def test_header_callback_stack_context(self):
        exc_info = []
        def error_handler(typ, value, tb):
            exc_info.append((typ, value, tb))
            return True

        def header_callback(header_line):
            if header_line.startswith('Content-Type:'):
                1 / 0

        with ExceptionStackContext(error_handler):
            self.fetch('/chunk', header_callback=header_callback)
        self.assertEqual(len(exc_info), 1)
        self.assertIs(exc_info[0][0], ZeroDivisionError)

    def test_configure_defaults(self):
        defaults = dict(user_agent='TestDefaultUserAgent')
        # Construct a new instance of the configured client class
        client = self.http_client.__class__(self.io_loop, force_instance=True,
                                            defaults=defaults)
        client.fetch(self.get_url('/user_agent'), callback=self.stop)
        response = self.wait()
        self.assertEqual(response.body, b('TestDefaultUserAgent'))

    def test_304_with_content_length(self):
        # According to the spec 304 responses SHOULD NOT include
        # Content-Length or other entity headers, but some servers do it
        # anyway.
        # http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5
        response = self.fetch('/304_with_content_length')
        self.assertEqual(response.code, 304)
        self.assertEqual(response.headers['Content-Length'], '42')

    def test_final_callback_stack_context(self):
        # The final callback should be run outside of the httpclient's
        # stack_context.  We want to ensure that there is not stack_context
        # between the user's callback and the IOLoop, so monkey-patch
        # IOLoop.handle_callback_exception and disable the test harness's
        # context with a NullContext.
        # Note that this does not apply to secondary callbacks (header
        # and streaming_callback), as errors there must be seen as errors
        # by the http client so it can clean up the connection.
        exc_info = []
        def handle_callback_exception(callback):
            exc_info.append(sys.exc_info())
            self.stop()
        self.io_loop.handle_callback_exception = handle_callback_exception

        with NullContext():