===================================
Constraint Functions for Interfaces
===================================

The `zope.mimetype.interfaces` module defines interfaces that use some
helper functions to define constraints on the accepted data.  These
helpers are used to determine whether values conform to the what's
allowed for parts of a MIME type specification and other parts of a
Content-Type header as specified in RFC 2045.

Single Token
------------

The first is the simplest:  the `tokenConstraint()` function returns
`True` if the ASCII string it is passed conforms to the `token`
production in section 5.1 of the RFC.  Let's import the function::

  >>> from zope.mimetype.interfaces import tokenConstraint

Typical token are the major and minor parts of the MIME type and the
parameter names for the Content-Type header.  The function should
return `True` for these values::

  >>> tokenConstraint("text")
  True
  >>> tokenConstraint("plain")
  True
  >>> tokenConstraint("charset")
  True

The function should also return `True` for unusual but otherwise
normal token that may be used in some situations::

  >>> tokenConstraint("not-your-fathers-token")
  True

It must also allow extension tokens and vendor-specific tokens::

  >>> tokenConstraint("x-magic")
  True

  >>> tokenConstraint("vnd.zope.special-data")
  True

Since we expect input handlers to normalize values to lower case,
upper case text is not allowed::

  >>> tokenConstraint("Text")
  False

Non-ASCII text is also not allowed::

  >>> tokenConstraint("\x80")
  False
  >>> tokenConstraint("\xC8")
  False
  >>> tokenConstraint("\xFF")
  False

Note that lots of characters are allowed in tokens, and there are no
constraints that the token "look like" something a person would want
to read::

  >>> tokenConstraint(".-.-.-.")
  True

Other characters are disallowed, however, including all forms of
whitespace::

  >>> tokenConstraint("foo bar")
  False
  >>> tokenConstraint("foo\tbar")
  False
  >>> tokenConstraint("foo\nbar")
  False
  >>> tokenConstraint("foo\rbar")
  False
  >>> tokenConstraint("foo\x7Fbar")
  False

Whitespace before or after the token is not accepted either::

  >>> tokenConstraint(" text")
  False
  >>> tokenConstraint("plain ")
  False

Other disallowed characters are defined in the `tspecials` production
from the RFC (also in section 5.1)::

  >>> tokenConstraint("(")
  False
  >>> tokenConstraint(")")
  False
  >>> tokenConstraint("<")
  False
  >>> tokenConstraint(">")
  False
  >>> tokenConstraint("@")
  False
  >>> tokenConstraint(",")
  False
  >>> tokenConstraint(";")
  False
  >>> tokenConstraint(":")
  False
  >>> tokenConstraint("\\")
  False
  >>> tokenConstraint('"')
  False
  >>> tokenConstraint("/")
  False
  >>> tokenConstraint("[")
  False
  >>> tokenConstraint("]")
  False
  >>> tokenConstraint("?")
  False
  >>> tokenConstraint("=")
  False

A token must contain at least one character, so `tokenConstraint()`
returns false for an empty string::

  >>> tokenConstraint("")
  False


MIME Type
---------

A MIME type is specified using two tokens separated by a slash;
whitespace between the tokens and the slash must be normalized away in
the input handler.

The `mimeTypeConstraint()` function is available to test a normalized
MIME type value; let's import that function now::

  >>> from zope.mimetype.interfaces import mimeTypeConstraint

Let's test some common MIME types to make sure the function isn't
obviously insane::

  >>> mimeTypeConstraint("text/plain")
  True
  >>> mimeTypeConstraint("application/xml")
  True
  >>> mimeTypeConstraint("image/svg+xml")
  True

If parts of the MIME type are missing, it isn't accepted::

  >>> mimeTypeConstraint("text")
  False
  >>> mimeTypeConstraint("text/")
  False
  >>> mimeTypeConstraint("/plain")
  False

As for individual tokens, whitespace is not allowed::

  >>> mimeTypeConstraint("foo bar/plain")
  False
  >>> mimeTypeConstraint("text/foo bar")
  False

Whitespace is not accepted around the slash either::

  >>> mimeTypeConstraint("text /plain")
  False
  >>> mimeTypeConstraint("text/ plain")
  False

Surrounding whitespace is also not accepted::

  >>> mimeTypeConstraint(" text/plain")
  False
  >>> mimeTypeConstraint("text/plain ")
  False
