Beispiel #1
0
 def cookies(self):
     """Container of request cookies
     """
     cookies = SimpleCookie()
     cookie = self.environ.get('HTTP_COOKIE')
     if cookie:
         cookies.load(cookie)
     return cookies
Beispiel #2
0
 def cookies(self):
     """Container of request cookies
     """
     cookies = SimpleCookie()
     cookie = self.environ.get('HTTP_COOKIE')
     if cookie:
         cookies.load(cookie)
     return cookies
Beispiel #3
0
 def test_parse_cookie(self):
     self.assertEqual(parse_cookie('invalid key=true'), {'key': 'true'})
     self.assertEqual(parse_cookie('invalid;key=true'), {'key': 'true'})
     self.assertEqual(parse_cookie(''), {})
     self.assertEqual(parse_cookie(None), {})
     c = SimpleCookie()
     c.load('key=true')
     self.assertEqual(parse_cookie(c), {'key': 'true'})
     self.assertEqual(parse_cookie('key='), {'key': ''})
Beispiel #4
0
 def __init__(self, status=None, content=None, response_headers=None,
              content_type=None, encoding=None, environ=None):
     self.environ = environ
     self.status_code = status or self.DEFAULT_STATUS_CODE
     self.encoding = encoding
     self.cookies = SimpleCookie()
     self.headers = Headers(response_headers, kind='server')
     self.content = content
     if content_type is not None:
         self.content_type = content_type
Beispiel #5
0
 def test_parse_cookie(self):
     self.assertEqual(parse_cookie('invalid key=true'),
                      {'key':'true'})
     self.assertEqual(parse_cookie('invalid;key=true'),
                      {'key':'true'})
     self.assertEqual(parse_cookie(''), {})
     self.assertEqual(parse_cookie(None), {})
     c = SimpleCookie()
     c.load('key=true')
     self.assertEqual(parse_cookie(c), {'key':'true'})
     self.assertEqual(parse_cookie('key='), {'key': ''})
Beispiel #6
0
 def test_cookies(self):
     h = Headers()
     cookies = SimpleCookie({'bla': 'foo', 'pippo': 'pluto'})
     self.assertEqual(len(cookies), 2)
     for c in cookies.values():
         v = c.OutputString()
         h.add_header('Set-Cookie', v)
     h = str(h)
     self.assertTrue(
         h in ('Set-Cookie: bla=foo\r\nSet-Cookie: pippo=pluto\r\n\r\n',
               'Set-Cookie: pippo=pluto\r\nSet-Cookie: bla=foo\r\n\r\n'))
Beispiel #7
0
 def test_cookies(self):
     h = Headers()
     cookies = SimpleCookie({'bla': 'foo', 'pippo': 'pluto'})
     self.assertEqual(len(cookies), 2)
     for c in cookies.values():
         v = c.OutputString()
         h.add_header('Set-Cookie', v)
     h = str(h)
     self.assertTrue(
         h in ('Set-Cookie: bla=foo\r\nSet-Cookie: pippo=pluto\r\n\r\n',
               'Set-Cookie: pippo=pluto\r\nSet-Cookie: bla=foo\r\n\r\n'))
Beispiel #8
0
 def __init__(self,
              status=None,
              content=None,
              response_headers=None,
              content_type=None,
              encoding=None,
              environ=None,
              can_store_cookies=True):
     self.environ = environ
     self.status_code = status or self.DEFAULT_STATUS_CODE
     self.encoding = encoding
     self.cookies = SimpleCookie()
     self.headers = Headers(response_headers or ())
     self.content = content
     self._can_store_cookies = can_store_cookies
     if content_type is not None:
         self.content_type = content_type
Beispiel #9
0
 def __init__(self, status=None, content=None, response_headers=None,
              content_type=None, encoding=None, environ=None):
     self.environ = environ
     self.status_code = status or self.DEFAULT_STATUS_CODE
     self.encoding = encoding
     self.cookies = SimpleCookie()
     self.headers = Headers(response_headers, kind='server')
     self.content = content
     if content_type is not None:
         self.content_type = content_type
Beispiel #10
0
 def __init__(self, status=None, content=None, response_headers=None,
              content_type=None, encoding=None, environ=None,
              can_store_cookies=True):
     self.environ = environ
     self.status_code = status or self.DEFAULT_STATUS_CODE
     self.encoding = encoding
     self.cookies = SimpleCookie()
     self.headers = Headers(response_headers or ())
     self.content = content
     self._can_store_cookies = can_store_cookies
     if content_type is not None:
         self.content_type = content_type
Beispiel #11
0
def handle_cookies(response, exc=None):
    '''Handle response cookies.
    '''
    headers = response.headers
    request = response.request
    client = request.client
    response._cookies = c = SimpleCookie()
    if 'set-cookie' in headers or 'set-cookie2' in headers:
        for cookie in (headers.get('set-cookie2'), headers.get('set-cookie')):
            if cookie:
                c.load(cookie)
        if client.store_cookies:
            client.cookies.extract_cookies(response, request)
Beispiel #12
0
 def __init__(self, status=None, content=None, response_headers=None,
              content_type=None, encoding=None, environ=None,
              can_store_cookies=True):
     self.environ = environ
     self.status_code = status or self.DEFAULT_STATUS_CODE
     self.encoding = encoding
     self.cookies = SimpleCookie()
     self.headers = Headers(response_headers, kind='server')
     self.content = content
     self._can_store_cookies = can_store_cookies
     if content_type is not None:
         self.content_type = content_type
     if environ:
         cookie = environ.get('HTTP_COOKIE')
         if cookie:
             self.cookies.load(cookie)
Beispiel #13
0
 def __init__(
     self,
     status=None,
     content=None,
     response_headers=None,
     content_type=None,
     encoding=None,
     environ=None,
     start_response=None,
 ):
     super(WsgiResponse, self).__init__(environ, start_response)
     self.status_code = status or self.DEFAULT_STATUS_CODE
     self.encoding = encoding
     self.cookies = SimpleCookie()
     self.headers = Headers(response_headers, kind="server")
     self.content = content
     if content_type is not None:
         self.content_type = content_type
Beispiel #14
0
class WsgiResponse(object):
    '''A WSGI response.

    Instances are callable using the standard WSGI call and, importantly,
    iterable::

        response = WsgiResponse(200)

    A :class:`WsgiResponse` is an iterable over bytes to send back to the
    requesting client.

    .. attribute:: status_code

        Integer indicating the HTTP status, (i.e. 200)

    .. attribute:: response

        String indicating the HTTP status (i.e. 'OK')

    .. attribute:: status

        String indicating the HTTP status code and response (i.e. '200 OK')

    .. attribute:: content_type

        The content type of this response. Can be ``None``.

    .. attribute:: headers

        The :class:`pulsar.utils.httpurl.Headers` container for this response.

    .. attribute:: environ

        The dictionary of WSGI environment if passed to the constructor.

    '''
    _started = False
    DEFAULT_STATUS_CODE = 200

    def __init__(self, status=None, content=None, response_headers=None,
                 content_type=None, encoding=None, environ=None):
        self.environ = environ
        self.status_code = status or self.DEFAULT_STATUS_CODE
        self.encoding = encoding
        self.cookies = SimpleCookie()
        self.headers = Headers(response_headers, kind='server')
        self.content = content
        if content_type is not None:
            self.content_type = content_type

    @property
    def started(self):
        return self._started

    @property
    def path(self):
        if self.environ:
            return self.environ.get('PATH_INFO', '')

    @property
    def method(self):
        if self.environ:
            return self.environ.get('REQUEST_METHOD')

    @property
    def connection(self):
        if self.environ:
            return self.environ.get('pulsar.connection')

    def _get_content(self):
        return self._content

    def _set_content(self, content):
        if not self._started:
            if content is None:
                content = ()
            elif ispy3k:
                if isinstance(content, str):
                    content = content.encode(self.encoding or 'utf-8')
            else:   # pragma    nocover
                if isinstance(content, unicode):
                    content = content.encode(self.encoding or 'utf-8')
            if isinstance(content, bytes):
                content = (content,)
            self._content = content
        else:
            raise RuntimeError('Cannot set content. Already iterated')
    content = property(_get_content, _set_content)

    def _get_content_type(self):
        return self.headers.get('content-type')

    def _set_content_type(self, typ):
        if typ:
            self.headers['content-type'] = typ
        else:
            self.headers.pop('content-type', None)
    content_type = property(_get_content_type, _set_content_type)

    def length(self):
        if not self.is_streamed:
            return reduce(lambda x, y: x+len(y), self.content, 0)

    @property
    def response(self):
        return responses.get(self.status_code)

    @property
    def status(self):
        return '%s %s' % (self.status_code, self.response)

    def __str__(self):
        return self.status

    def __repr__(self):
        return '%s(%s)' % (self.__class__.__name__, self)

    @property
    def is_streamed(self):
        """If the response is streamed (the response is not an iterable with
length information) this property is `True`.  In this case streamed
means that there is no information about the number of iterations.
This is usually `True` if a generator is passed to the response object."""
        return is_streamed(self.content)

    def __iter__(self):
        if self._started:
            raise RuntimeError('WsgiResponse can be iterated once only')
        self._started = True
        if is_streamed(self.content):
            return wsgi_encoder(self.content, self.encoding or 'utf-8')
        else:
            return iter(self.content)

    def __len__(self):
        return len(self.content)

    def set_cookie(self, key, **kwargs):
        """
        Sets a cookie.

        ``expires`` can be a string in the correct format or a
        ``datetime.datetime`` object in UTC. If ``expires`` is a datetime
        object then ``max_age`` will be calculated.
        """
        set_cookie(self.cookies, key, **kwargs)

    def delete_cookie(self, key, path='/', domain=None):
        set_cookie(self.cookies, key, max_age=0, path=path, domain=domain,
                   expires='Thu, 01-Jan-1970 00:00:00 GMT')

    def get_headers(self):
        headers = self.headers
        if has_empty_content(self.status_code, self.method):
            headers.pop('content-type', None)
            headers.pop('content-length', None)
            self._content = ()
        else:
            if not self.is_streamed:
                cl = 0
                for c in self.content:
                    cl += len(c)
                if cl == 0 and self.content_type in JSON_CONTENT_TYPES:
                    self._content = (b'{}',)
                    cl = len(self._content[0])
                headers['Content-Length'] = str(cl)
            if not self.content_type:
                headers['Content-Type'] = 'text/plain'
        for c in self.cookies.values():
            headers['Set-Cookie'] = c.OutputString()
        return list(headers)

    def has_header(self, header):
        return header in self.headers
    __contains__ = has_header

    def __setitem__(self, header, value):
        self.headers[header] = value

    def __getitem__(self, header):
        return self.headers[header]
Beispiel #15
0
class WsgiResponse:
    """A WSGI response.

    Instances are callable using the standard WSGI call and, importantly,
    iterable::

        response = WsgiResponse(200)

    A :class:`WsgiResponse` is an iterable over bytes to send back to the
    requesting client.

    .. attribute:: status_code

        Integer indicating the HTTP status, (i.e. 200)

    .. attribute:: response

        String indicating the HTTP status (i.e. 'OK')

    .. attribute:: status

        String indicating the HTTP status code and response (i.e. '200 OK')

    .. attribute:: content_type

        The content type of this response. Can be ``None``.

    .. attribute:: headers

        The :class:`.Headers` container for this response.

    .. attribute:: environ

        The dictionary of WSGI environment if passed to the constructor.

    .. attribute:: cookies

        A python :class:`SimpleCookie` container of cookies included in the
        request as well as cookies set during the response.
    """
    _iterated = False
    _started = False
    DEFAULT_STATUS_CODE = 200

    def __init__(self,
                 status=None,
                 content=None,
                 response_headers=None,
                 content_type=None,
                 encoding=None,
                 environ=None,
                 can_store_cookies=True):
        self.environ = environ
        self.status_code = status or self.DEFAULT_STATUS_CODE
        self.encoding = encoding
        self.cookies = SimpleCookie()
        self.headers = Headers(response_headers, kind='server')
        self.content = content
        self._can_store_cookies = can_store_cookies
        if content_type is not None:
            self.content_type = content_type

    @property
    def started(self):
        return self._started

    @property
    def iterated(self):
        return self._iterated

    @property
    def path(self):
        if self.environ:
            return self.environ.get('PATH_INFO', '')

    @property
    def method(self):
        if self.environ:
            return self.environ.get('REQUEST_METHOD')

    @property
    def connection(self):
        if self.environ:
            return self.environ.get('pulsar.connection')

    @property
    def content(self):
        return self._content

    @content.setter
    def content(self, content):
        if not self._iterated:
            if content is None:
                content = ()
            else:
                if isinstance(content, str):
                    if not self.encoding:  # use utf-8 if not set
                        self.encoding = 'utf-8'
                    content = content.encode(self.encoding)

            if isinstance(content, bytes):
                content = (content, )
            self._content = content
        else:
            raise RuntimeError('Cannot set content. Already iterated')

    def _get_content_type(self):
        return self.headers.get('content-type')

    def _set_content_type(self, typ):
        if typ:
            self.headers['content-type'] = typ
        else:
            self.headers.pop('content-type', None)

    content_type = property(_get_content_type, _set_content_type)

    @property
    def response(self):
        return responses.get(self.status_code)

    @property
    def status(self):
        return '%s %s' % (self.status_code, self.response)

    def __str__(self):
        return self.status

    def __repr__(self):
        return '%s(%s)' % (self.__class__.__name__, self)

    @property
    def is_streamed(self):
        """Check if the response is streamed.

        A streamed response is an iterable with no length information.
        In this case streamed means that there is no information about
        the number of iterations.

        This is usually `True` if a generator is passed to the response object.
        """
        try:
            len(self.content)
        except TypeError:
            return True
        return False

    def can_set_cookies(self):
        if self.status_code < 400:
            return self._can_store_cookies

    def length(self):
        if not self.is_streamed:
            return reduce(lambda x, y: x + len(y), self.content, 0)

    def start(self, start_response):
        assert not self._started
        self._started = True
        return start_response(self.status, self.get_headers())

    def __iter__(self):
        if self._iterated:
            raise RuntimeError('WsgiResponse can be iterated once only')
        self._started = True
        self._iterated = True
        if self.is_streamed:
            return wsgi_encoder(self.content, self.encoding or 'utf-8')
        else:
            return iter(self.content)

    def close(self):
        """Close this response, required by WSGI
        """
        if self.is_streamed:
            if hasattr(self.content, 'close'):
                self.content.close()

    def set_cookie(self, key, **kwargs):
        """
        Sets a cookie.

        ``expires`` can be a string in the correct format or a
        ``datetime.datetime`` object in UTC. If ``expires`` is a datetime
        object then ``max_age`` will be calculated.
        """
        set_cookie(self.cookies, key, **kwargs)

    def delete_cookie(self, key, path='/', domain=None):
        set_cookie(self.cookies,
                   key,
                   max_age=0,
                   path=path,
                   domain=domain,
                   expires='Thu, 01-Jan-1970 00:00:00 GMT')

    def get_headers(self):
        """The list of headers for this response
        """
        headers = self.headers
        if has_empty_content(self.status_code):
            headers.pop('content-type', None)
            headers.pop('content-length', None)
            self._content = ()
        else:
            if not self.is_streamed:
                cl = 0
                for c in self.content:
                    cl += len(c)
                if cl == 0 and self.content_type in JSON_CONTENT_TYPES:
                    self._content = (b'{}', )
                    cl = len(self._content[0])
                headers['Content-Length'] = str(cl)
            ct = self.content_type
            # content type encoding available
            if self.encoding:
                ct = ct or 'text/plain'
                if 'charset=' not in ct:
                    ct = '%s; charset=%s' % (ct, self.encoding)
            if ct:
                headers['Content-Type'] = ct
            if self.method == HEAD:
                self._content = ()
        if self.can_set_cookies():
            for c in self.cookies.values():
                headers.add_header('Set-Cookie', c.OutputString())
        return list(headers)

    def has_header(self, header):
        return header in self.headers

    __contains__ = has_header

    def __setitem__(self, header, value):
        self.headers[header] = value

    def __getitem__(self, header):
        return self.headers[header]
Beispiel #16
0
class WsgiResponse(WsgiResponseGenerator):
    """A WSGI response wrapper initialized by a WSGI request middleware.
Instances are callable using the standard WSGI call::

    response = WsgiResponse(200)
    response(environ, start_response)

A :class:`WsgiResponse` is an iterable over bytes to send back to the requesting
client.

.. attribute:: status_code

    Integer indicating the HTTP status, (i.e. 200)

.. attribute:: response

    String indicating the HTTP status (i.e. 'OK')

.. attribute:: status

    String indicating the HTTP status code and response (i.e. '200 OK')

.. attribute:: environ

    The dictionary of WSGI environment if passed to the constructor.

"""

    _started = False
    DEFAULT_STATUS_CODE = 200

    def __init__(
        self,
        status=None,
        content=None,
        response_headers=None,
        content_type=None,
        encoding=None,
        environ=None,
        start_response=None,
    ):
        super(WsgiResponse, self).__init__(environ, start_response)
        self.status_code = status or self.DEFAULT_STATUS_CODE
        self.encoding = encoding
        self.cookies = SimpleCookie()
        self.headers = Headers(response_headers, kind="server")
        self.content = content
        if content_type is not None:
            self.content_type = content_type

    @property
    def started(self):
        return self._started

    @property
    def path(self):
        if self.environ:
            return self.environ.get("PATH_INFO", "")

    @property
    def method(self):
        if self.environ:
            return self.environ.get("REQUEST_METHOD")

    @property
    def connection(self):
        if self.environ:
            return self.environ.get("pulsar.connection")

    def _get_content(self):
        return self._content

    def _set_content(self, content):
        if not self._started:
            if content is None:
                content = ()
            elif ispy3k:  # what a f*****g pain
                if isinstance(content, str):
                    content = bytes(content, "latin-1")
            else:  # pragma    nocover
                if isinstance(content, unicode):
                    content = bytes(content, "latin-1")
            if isinstance(content, bytes):
                content = (content,)
            self._content = content
        else:
            raise RuntimeError("Cannot set content. Already iterated")

    content = property(_get_content, _set_content)

    def _get_content_type(self):
        return self.headers.get("content-type")

    def _set_content_type(self, typ):
        if typ:
            self.headers["content-type"] = typ
        else:
            self.headers.pop("content-type", None)

    content_type = property(_get_content_type, _set_content_type)

    def __call__(self, environ, start_response, exc_info=None):
        """Make sure the headers are set."""
        if not exc_info:
            for rm in self.middleware:
                try:
                    rm(environ, self)
                except:
                    LOGGER.error("Exception in response middleware", exc_info=True)
        start_response(self.status, self.get_headers(), exc_info=exc_info)
        return self

    def start(self):
        self.__call__(self.environ, self.start_response)

    def length(self):
        if not self.is_streamed:
            return reduce(lambda x, y: x + len(y), self.content, 0)

    @property
    def response(self):
        return responses.get(self.status_code)

    @property
    def status(self):
        return "%s %s" % (self.status_code, self.response)

    def __str__(self):
        return self.status

    def __repr__(self):
        return "%s(%s)" % (self.__class__.__name__, self)

    @property
    def is_streamed(self):
        """If the response is streamed (the response is not an iterable with
length information) this property is `True`.  In this case streamed
means that there is no information about the number of iterations.
This is usually `True` if a generator is passed to the response object."""
        return is_streamed(self.content)

    def __iter__(self):
        if self._started:
            raise RuntimeError("WsgiResponse can be iterated only once")
        self._started = True
        if self.is_streamed:
            return wsgi_iterator(self.content, self.encoding)
        else:
            return iter(self.content)

    def __len__(self):
        return len(self.content)

    def set_cookie(self, key, **kwargs):
        """
        Sets a cookie.

        ``expires`` can be a string in the correct format or a
        ``datetime.datetime`` object in UTC. If ``expires`` is a datetime
        object then ``max_age`` will be calculated.
        """
        set_cookie(self.cookies, key, **kwargs)

    def delete_cookie(self, key, path="/", domain=None):
        set_cookie(self.cookies, key, max_age=0, path=path, domain=domain, expires="Thu, 01-Jan-1970 00:00:00 GMT")

    def get_headers(self):
        headers = self.headers
        if has_empty_content(self.status_code, self.method):
            headers.pop("content-type", None)
            headers.pop("content-length", None)
        elif not self.is_streamed:
            cl = 0
            for c in self.content:
                cl += len(c)
            headers["Content-Length"] = str(cl)
        for c in self.cookies.values():
            headers["Set-Cookie"] = c.OutputString()
        return list(headers)
Beispiel #17
0
class WsgiResponse:
    """A WSGI response.

    Instances are callable using the standard WSGI call and, importantly,
    iterable::

        response = WsgiResponse(200)

    A :class:`WsgiResponse` is an iterable over bytes to send back to the
    requesting client.

    .. attribute:: status_code

        Integer indicating the HTTP status, (i.e. 200)

    .. attribute:: response

        String indicating the HTTP status (i.e. 'OK')

    .. attribute:: status

        String indicating the HTTP status code and response (i.e. '200 OK')

    .. attribute:: content_type

        The content type of this response. Can be ``None``.

    .. attribute:: headers

        The :class:`.Headers` container for this response.

    .. attribute:: environ

        The dictionary of WSGI environment if passed to the constructor.

    .. attribute:: cookies

        A python :class:`SimpleCookie` container of cookies included in the
        request as well as cookies set during the response.
    """
    _iterated = False
    _started = False
    DEFAULT_STATUS_CODE = 200

    def __init__(self, status=None, content=None, response_headers=None,
                 content_type=None, encoding=None, environ=None,
                 can_store_cookies=True):
        self.environ = environ
        self.status_code = status or self.DEFAULT_STATUS_CODE
        self.encoding = encoding
        self.cookies = SimpleCookie()
        self.headers = Headers(response_headers, kind='server')
        self.content = content
        self._can_store_cookies = can_store_cookies
        if content_type is not None:
            self.content_type = content_type

    @property
    def started(self):
        return self._started

    @property
    def iterated(self):
        return self._iterated

    @property
    def path(self):
        if self.environ:
            return self.environ.get('PATH_INFO', '')

    @property
    def method(self):
        if self.environ:
            return self.environ.get('REQUEST_METHOD')

    @property
    def connection(self):
        if self.environ:
            return self.environ.get('pulsar.connection')

    @property
    def content(self):
        return self._content

    @content.setter
    def content(self, content):
        if not self._iterated:
            if content is None:
                content = ()
            else:
                if isinstance(content, str):
                    if not self.encoding:   # use utf-8 if not set
                        self.encoding = 'utf-8'
                    content = content.encode(self.encoding)

            if isinstance(content, bytes):
                content = (content,)
            self._content = content
        else:
            raise RuntimeError('Cannot set content. Already iterated')

    def _get_content_type(self):
        return self.headers.get('content-type')

    def _set_content_type(self, typ):
        if typ:
            self.headers['content-type'] = typ
        else:
            self.headers.pop('content-type', None)
    content_type = property(_get_content_type, _set_content_type)

    @property
    def response(self):
        return responses.get(self.status_code)

    @property
    def status(self):
        return '%s %s' % (self.status_code, self.response)

    def __str__(self):
        return self.status

    def __repr__(self):
        return '%s(%s)' % (self.__class__.__name__, self)

    @property
    def is_streamed(self):
        """Check if the response is streamed.

        A streamed response is an iterable with no length information.
        In this case streamed means that there is no information about
        the number of iterations.

        This is usually `True` if a generator is passed to the response object.
        """
        try:
            len(self.content)
        except TypeError:
            return True
        return False

    def can_set_cookies(self):
        if self.status_code < 400:
            return self._can_store_cookies

    def length(self):
        if not self.is_streamed:
            return reduce(lambda x, y: x+len(y), self.content, 0)

    def start(self, start_response):
        assert not self._started
        self._started = True
        return start_response(self.status, self.get_headers())

    def __iter__(self):
        if self._iterated:
            raise RuntimeError('WsgiResponse can be iterated once only')
        self._started = True
        self._iterated = True
        if self.is_streamed:
            return wsgi_encoder(self.content, self.encoding or 'utf-8')
        else:
            return iter(self.content)

    def close(self):
        """Close this response, required by WSGI
        """
        if self.is_streamed:
            if hasattr(self.content, 'close'):
                self.content.close()

    def set_cookie(self, key, **kwargs):
        """
        Sets a cookie.

        ``expires`` can be a string in the correct format or a
        ``datetime.datetime`` object in UTC. If ``expires`` is a datetime
        object then ``max_age`` will be calculated.
        """
        set_cookie(self.cookies, key, **kwargs)

    def delete_cookie(self, key, path='/', domain=None):
        set_cookie(self.cookies, key, max_age=0, path=path, domain=domain,
                   expires='Thu, 01-Jan-1970 00:00:00 GMT')

    def get_headers(self):
        """The list of headers for this response
        """
        headers = self.headers
        if has_empty_content(self.status_code):
            headers.pop('content-type', None)
            headers.pop('content-length', None)
            self._content = ()
        else:
            if not self.is_streamed:
                cl = 0
                for c in self.content:
                    cl += len(c)
                if cl == 0 and self.content_type in JSON_CONTENT_TYPES:
                    self._content = (b'{}',)
                    cl = len(self._content[0])
                headers['Content-Length'] = str(cl)
            ct = self.content_type
            # content type encoding available
            if self.encoding:
                ct = ct or 'text/plain'
                if 'charset=' not in ct:
                    ct = '%s; charset=%s' % (ct, self.encoding)
            if ct:
                headers['Content-Type'] = ct
            if self.method == HEAD:
                self._content = ()
        if self.can_set_cookies():
            for c in self.cookies.values():
                headers.add_header('Set-Cookie', c.OutputString())
        return list(headers)

    def has_header(self, header):
        return header in self.headers
    __contains__ = has_header

    def __setitem__(self, header, value):
        self.headers[header] = value

    def __getitem__(self, header):
        return self.headers[header]