text: from datetime import datetime
  from datetime import timedelta
  
  from .._compat import string_types
  from ..datastructures import CallbackDict
  from ..http import dump_age
  from ..http import dump_header
  from ..http import dump_options_header
  from ..http import http_date
  from ..http import parse_age
  from ..http import parse_date
  from ..http import parse_options_header
  from ..http import parse_set_header
  from ..utils import cached_property
  from ..utils import environ_property
  from ..utils import get_content_type
  from ..utils import header_property
  from ..wsgi import get_content_length
  
  
  class CommonRequestDescriptorsMixin(object):
      """A mixin for :class:`BaseRequest` subclasses.  Request objects that
      mix this class in will automatically get descriptors for a couple of
      HTTP headers with automatic type conversion.
  
      .. versionadded:: 0.5
      """
  
      content_type = environ_property(
          "CONTENT_TYPE",
          doc="""The Content-Type entity-header field indicates the media
          type of the entity-body sent to the recipient or, in the case of
          the HEAD method, the media type that would have been sent had
          the request been a GET.""",
      )
  
      @cached_property
      def content_length(self):
          """The Content-Length entity-header field indicates the size of the
          entity-body in bytes or, in the case of the HEAD method, the size of
          the entity-body that would have been sent had the request been a
          GET.
          """
          return get_content_length(self.environ)
  
      content_encoding = environ_property(
          "HTTP_CONTENT_ENCODING",
          doc="""The Content-Encoding entity-header field is used as a
          modifier to the media-type. When present, its value indicates
          what additional content codings have been applied to the
          entity-body, and thus what decoding mechanisms must be applied
          in order to obtain the media-type referenced by the Content-Type
          header field.
  
          .. versionadded:: 0.9""",
      )
      content_md5 = environ_property(
          "HTTP_CONTENT_MD5",
          doc="""The Content-MD5 entity-header field, as defined in
          RFC 1864, is an MD5 digest of the entity-body for the purpose of
          providing an end-to-end message integrity check (MIC) of the
          entity-body. (Note: a MIC is good for detecting accidental
          modification of the entity-body in transit, but is not proof
          against malicious attacks.)
  
          .. versionadded:: 0.9""",
      )
      referrer = environ_property(
          "HTTP_REFERER",
          doc="""The Referer[sic] request-header field allows the client
          to specify, for the server's benefit, the address (URI) of the
          resource from which the Request-URI was obtained (the
          "referrer", although the header field is misspelled).""",
      )
      date = environ_property(
          "HTTP_DATE",
          None,
          parse_date,
          doc="""The Date general-header field represents the date and
          time at which the message was originated, having the same
          semantics as orig-date in RFC 822.""",
      )
      max_forwards = environ_property(
          "HTTP_MAX_FORWARDS",
          None,
          int,
          doc="""The Max-Forwards request-header field provides a
          mechanism with the TRACE and OPTIONS methods to limit the number
          of proxies or gateways that can forward the request to the next
          inbound server.""",
      )
  
      def _parse_content_type(self):
          if not hasattr(self, "_parsed_content_type"):
              self._parsed_content_type = parse_options_header(
                  self.environ.get("CONTENT_TYPE", "")
              )
  
      @property
      def mimetype(self):
          """Like :attr:`content_type`, but without parameters (eg, without
          charset, type etc.) and always lowercase.  For example if the content
          type is ``text/HTML; charset=utf-8`` the mimetype would be
          ``'text/html'``.
          """
          self._parse_content_type()
          return self._parsed_content_type[0].lower()
  
      @property
      def mimetype_params(self):
          """The mimetype parameters as dict.  For example if the content
          type is ``text/html; charset=utf-8`` the params would be
          ``{'charset': 'utf-8'}``.
          """
          self._parse_content_type()
          return self._parsed_content_type[1]
  
      @cached_property
      def pragma(self):
          """The Pragma general-header field is used to include
          implementation-specific directives that might apply to any recipient
          along the request/response chain.  All pragma directives specify
          optional behavior from the viewpoint of the protocol; however, some
          systems MAY require that behavior be consistent with the directives.
          """
          return parse_set_header(self.environ.get("HTTP_PRAGMA", ""))
  
  
  class CommonResponseDescriptorsMixin(object):
      """A mixin for :class:`BaseResponse` subclasses.  Response objects that
      mix this class in will automatically get descriptors for a couple of
      HTTP headers with automatic type conversion.
      """
  
      @property
      def mimetype(self):
          """The mimetype (content type without charset etc.)"""
          ct = self.headers.get("content-type")
          if ct:
              return ct.split(";")[0].strip()
  
      @mimetype.setter
      def mimetype(self, value):
          self.headers["Content-Type"] = get_content_type(value, self.charset)
  
      @property
      def mimetype_params(self):
          """The mimetype parameters as dict. For example if the
          content type is ``text/html; charset=utf-8`` the params would be
          ``{'charset': 'utf-8'}``.
  
          .. versionadded:: 0.5
          """
  
          def on_update(d):
              self.headers["Content-Type"] = dump_options_header(self.mimetype, d)
  
          d = parse_options_header(self.headers.get("content-type", ""))[1]
          return CallbackDict(d, on_update)
  
      location = header_property(
          "Location",
          doc="""The Location response-header field is used to redirect
          the recipient to a location other than the Request-URI for
          completion of the request or identification of a new
          resource.""",
      )
      age = header_property(
          "Age",
          None,
          parse_age,
          dump_age,
          doc="""The Age response-header field conveys the sender's
          estimate of the amount of time since the response (or its
          revalidation) was generated at the origin server.
  
          Age values are non-negative decimal integers, representing time
          in seconds.""",
      )
      content_type = header_property(
          "Content-Type",
          doc="""The Content-Type entity-header field indicates the media
          type of the entity-body sent to the recipient or, in the case of
          the HEAD method, the media type that would have been sent had
          the request been a GET.""",
      )
      content_length = header_property(
          "Content-Length",
          None,
          int,
          str,
          doc="""The Content-Length entity-header field indicates the size
          of the entity-body, in decimal number of OCTETs, sent to the
          recipient or, in the case of the HEAD method, the size of the
          entity-body that would have been sent had the request been a
          GET.""",
      )
      content_location = header_property(
          "Content-Location",
          doc="""The Content-Location entity-header field MAY be used to
          supply the resource location for the entity enclosed in the
          message when that entity is accessible from a location separate
          from the requested resource's URI.""",
      )
      content_encoding = header_property(
          "Content-Encoding",
          doc="""The Content-Encoding entity-header field is used as a
          modifier to the media-type. When present, its value indicates
          what additional content codings have been applied to the
          entity-body, and thus what decoding mechanisms must be applied
          in order to obtain the media-type referenced by the Content-Type
          header field.""",
      )
      content_md5 = header_property(
          "Content-MD5",
          doc="""The Content-MD5 entity-header field, as defined in
          RFC 1864, is an MD5 digest of the entity-body for the purpose of
          providing an end-to-end message integrity check (MIC) of the
          entity-body. (Note: a MIC is good for detecting accidental
          modification of the entity-body in transit, but is not proof
          against malicious attacks.)""",
      )
      date = header_property(
          "Date",
          None,
          parse_date,
          http_date,
          doc="""The Date general-header field represents the date and
          time at which the message was originated, having the same
          semantics as orig-date in RFC 822.""",
      )
      expires = header_property(
          "Expires",
          None,
          parse_date,
          http_date,
          doc="""The Expires entity-header field gives the date/time after
          which the response is considered stale. A stale cache entry may
          not normally be returned by a cache.""",
      )
      last_modified = header_property(
          "Last-Modified",
          None,
          parse_date,
          http_date,
          doc="""The Last-Modified entity-header field indicates the date
          and time at which the origin server believes the variant was
          last modified.""",
      )
  
      @property
      def retry_after(self):
          """The Retry-After response-header field can be used with a
          503 (Service Unavailable) response to indicate how long the
          service is expected to be unavailable to the requesting client.
  
          Time in seconds until expiration or date.
          """
          value = self.headers.get("retry-after")
          if value is None:
              return
          elif value.isdigit():
              return datetime.utcnow() + timedelta(seconds=int(value))
          return parse_date(value)
  
      @retry_after.setter
      def retry_after(self, value):
          if value is None:
              if "retry-after" in self.headers:
                  del self.headers["retry-after"]
              return
          elif isinstance(value, datetime):
              value = http_date(value)
          else:
              value = str(value)
          self.headers["Retry-After"] = value
  
      def _set_property(name, doc=None):  # noqa: B902
          def fget(self):
              def on_update(header_set):
                  if not header_set and name in self.headers:
                      del self.headers[name]
                  elif header_set:
                      self.headers[name] = header_set.to_header()
  
              return parse_set_header(self.headers.get(name), on_update)
  
          def fset(self, value):
              if not value:
                  del self.headers[name]
              elif isinstance(value, string_types):
                  self.headers[name] = value
              else:
                  self.headers[name] = dump_header(value)
  
          return property(fget, fset, doc=doc)
  
      vary = _set_property(
          "Vary",
          doc="""The Vary field value indicates the set of request-header
          fields that fully determines, while the response is fresh,
          whether a cache is permitted to use the response to reply to a
          subsequent request without revalidation.""",
      )
      content_language = _set_property(
          "Content-Language",
          doc="""The Content-Language entity-header field describes the
          natural language(s) of the intended audience for the enclosed
          entity. Note that this might not be equivalent to all the
          languages used within the entity-body.""",
      )
      allow = _set_property(
          "Allow",
          doc="""The Allow entity-header field lists the set of methods
          supported by the resource identified by the Request-URI. The
          purpose of this field is strictly to inform the recipient of
          valid methods associated with the resource. An Allow header
          field MUST be present in a 405 (Method Not Allowed)
          response.""",
      )
  
      del _set_property
  