예제 #1
0
파일: endpoints.py 프로젝트: kidaa/eve
def media_endpoint(_id):
    """ This endpoint is active when RETURN_MEDIA_AS_URL is True. It retrieves
    a media file and streams it to the client.

    .. versionadded:: 0.6
    """
    file_ = app.media.get(_id)
    if file_ is None:
        return abort(404)

    if_modified_since = weak_date(request.headers.get('If-Modified-Since'))
    if if_modified_since is not None:
        if if_modified_since.tzinfo is None:
            if_modified_since = if_modified_since.replace(
                tzinfo=tz_util.utc)

        if if_modified_since > file_.upload_date:
            return Response(status=304)

    headers = {
        'Last-Modified': date_to_rfc1123(file_.upload_date),
        'Content-Length': file_.length,
    }

    response = Response(file_, headers=headers, mimetype=file_.content_type,
                        direct_passthrough=True)

    return response
예제 #2
0
파일: endpoints.py 프로젝트: sindbach/eve
def media_endpoint(_id):
    """ This endpoint is active when RETURN_MEDIA_AS_URL is True. It retrieves
    a media file and streams it to the client.

    .. versionadded:: 0.6
    """
    file_ = app.media.get(_id)
    if file_ is None:
        return abort(404)

    headers = {
        "Last-Modified": date_to_rfc1123(file_.upload_date),
        "Content-Length": file_.length,
        "Accept-Ranges": "bytes",
    }

    range_header = request.headers.get("Range")
    if range_header:
        status = 206

        size = file_.length
        try:
            m = re.search("(\d+)-(\d*)", range_header)
            begin, end = m.groups()
            begin = int(begin)
            end = int(end)
        except:
            begin, end = 0, None

        length = size - begin
        if end is not None:
            length = end - begin + 1

        file_.seek(begin)

        data = file_.read(length)
        headers["Content-Range"] = "bytes {0}-{1}/{2}".format(
            begin, begin + length - 1, size)
    else:
        if_modified_since = weak_date(request.headers.get("If-Modified-Since"))
        if if_modified_since:
            if not if_modified_since.tzinfo:
                if_modified_since = if_modified_since.replace(
                    tzinfo=tz_util.utc)

            if if_modified_since > file_.upload_date:
                return Response(status=304)

        data = file_
        status = 200

    response = Response(
        data,
        status=status,
        headers=headers,
        mimetype=file_.content_type,
        direct_passthrough=True,
    )

    return response
def media_endpoint(_id):
    """ This endpoint is active when RETURN_MEDIA_AS_URL is True. It retrieves
    a media file and streams it to the client.

    .. versionadded:: 0.6
    """
    file_ = app.media.get(_id)
    if file_ is None:
        return abort(404)

    if_modified_since = weak_date(request.headers.get('If-Modified-Since'))
    if if_modified_since is not None:
        if if_modified_since.tzinfo is None:
            if_modified_since = if_modified_since.replace(tzinfo=tz_util.utc)

        if if_modified_since > file_.upload_date:
            return Response(status=304)

    headers = {
        'Last-Modified': date_to_rfc1123(file_.upload_date),
        'Content-Length': file_.length,
    }

    response = Response(file_,
                        headers=headers,
                        mimetype=file_.content_type,
                        direct_passthrough=True)

    return response
예제 #4
0
파일: render.py 프로젝트: iotrl/eve
def _prepare_response(resource, dct, last_modified=None, etag=None,
                      status=200, headers=None):
    """ Prepares the response object according to the client request and
    available renderers, making sure that all accessory directives (caching,
    etag, last-modified) are present.

    :param resource: the resource involved.
    :param dct: the dict that should be sent back as a response.
    :param last_modified: Last-Modified header value.
    :param etag: ETag header value.
    :param status: response status.

    .. versionchanged:: 0.7
       Add support for regexes in X_DOMAINS_RE. Closes #660, #974.
       ETag value now surrounded by double quotes. Closes #794.

    .. versionchanged:: 0.6
       JSONP Support.

    .. versionchanged:: 0.4
       Support for optional extra headers.
       Fix #381. 500 instead of 404 if CORS is enabled.

    .. versionchanged:: 0.3
       Support for X_MAX_AGE.

    .. versionchanged:: 0.1.0
       Support for optional HATEOAS.

    .. versionchanged:: 0.0.9
       Support for Python 3.3.

    .. versionchanged:: 0.0.7
       Support for Rate-Limiting.

    .. versionchanged:: 0.0.6
       Support for HEAD requests.

    .. versionchanged:: 0.0.5
       Support for Cross-Origin Resource Sharing (CORS).

    .. versionadded:: 0.0.4
    """
    if request.method == 'OPTIONS':
        resp = app.make_default_options_response()
    else:
        # obtain the best match between client's request and available mime
        # types, along with the corresponding render function.
        mime, renderer_cls = _best_mime()

        # invoke the render function and obtain the corresponding rendered item
        rendered = renderer_cls().render(dct)

        # JSONP
        if config.JSONP_ARGUMENT:
            jsonp_arg = config.JSONP_ARGUMENT
            if jsonp_arg in request.args and 'json' in mime:
                callback = request.args.get(jsonp_arg)
                rendered = "%s(%s)" % (callback, rendered)

        # build the main wsgi response object
        resp = make_response(rendered, status)
        resp.mimetype = mime

    # extra headers
    if headers:
        for header, value in headers:
            if header != 'Content-Type':
                resp.headers.add(header, value)

    # cache directives
    if request.method in ('GET', 'HEAD'):
        if resource:
            cache_control = config.DOMAIN[resource]['cache_control']
            expires = config.DOMAIN[resource]['cache_expires']
        else:
            cache_control = config.CACHE_CONTROL
            expires = config.CACHE_EXPIRES
        if cache_control:
            resp.headers.add('Cache-Control', cache_control)
        if expires:
            resp.expires = time.time() + expires

    # etag and last-modified
    if etag:
        resp.headers.add('ETag', '"' + etag + '"')
    if last_modified:
        resp.headers.add('Last-Modified', date_to_rfc1123(last_modified))

    # CORS
    origin = request.headers.get('Origin')
    if origin and (config.X_DOMAINS or config.X_DOMAINS_RE):
        if config.X_DOMAINS is None:
            domains = []
        elif isinstance(config.X_DOMAINS, str):
            domains = [config.X_DOMAINS]
        else:
            domains = config.X_DOMAINS

        if config.X_DOMAINS_RE is None:
            domains_re = []
        elif isinstance(config.X_DOMAINS_RE, str):
            domains_re = [config.X_DOMAINS_RE]
        else:
            domains_re = config.X_DOMAINS_RE

        # precompile regexes and ignore invalids
        domains_re_compiled = []
        for domain_re in domains_re:
            try:
                domains_re_compiled.append(re.compile(domain_re))
            except re.error:
                continue

        if config.X_HEADERS is None:
            headers = []
        elif isinstance(config.X_HEADERS, str):
            headers = [config.X_HEADERS]
        else:
            headers = config.X_HEADERS

        if config.X_EXPOSE_HEADERS is None:
            expose_headers = []
        elif isinstance(config.X_EXPOSE_HEADERS, str):
            expose_headers = [config.X_EXPOSE_HEADERS]
        else:
            expose_headers = config.X_EXPOSE_HEADERS

        # The only accepted value for Access-Control-Allow-Credentials header
        # is "true"
        allow_credentials = config.X_ALLOW_CREDENTIALS is True

        methods = app.make_default_options_response().headers.get('allow', '')

        if '*' in domains:
            resp.headers.add('Access-Control-Allow-Origin', origin)
            resp.headers.add('Vary', 'Origin')
        elif any(origin == domain for domain in domains):
            resp.headers.add('Access-Control-Allow-Origin', origin)
        elif any(domain.match(origin) for domain in domains_re_compiled):
            resp.headers.add('Access-Control-Allow-Origin', origin)
        else:
            resp.headers.add('Access-Control-Allow-Origin', '')
        resp.headers.add('Access-Control-Allow-Headers', ', '.join(headers))
        resp.headers.add('Access-Control-Expose-Headers',
                         ', '.join(expose_headers))
        resp.headers.add('Access-Control-Allow-Methods', methods)
        resp.headers.add('Access-Control-Max-Age', config.X_MAX_AGE)
        if allow_credentials:
            resp.headers.add('Access-Control-Allow-Credentials', "true")

    # Rate-Limiting
    limit = get_rate_limit()
    if limit and limit.send_x_headers:
        resp.headers.add('X-RateLimit-Remaining', str(limit.remaining))
        resp.headers.add('X-RateLimit-Limit', str(limit.limit))
        resp.headers.add('X-RateLimit-Reset', str(limit.reset))

    return resp
예제 #5
0
파일: render.py 프로젝트: zhaoyh1991/eve
def _prepare_response(resource,
                      dct,
                      last_modified=None,
                      etag=None,
                      status=200,
                      headers=None):
    """ Prepares the response object according to the client request and
    available renderers, making sure that all accessory directives (caching,
    etag, last-modified) are present.

    :param resource: the resource involved.
    :param dct: the dict that should be sent back as a response.
    :param last_modified: Last-Modified header value.
    :param etag: ETag header value.
    :param status: response status.

    .. versionchanged:: 0.6
       JSONP Support.

    .. versionchanged:: 0.4
       Support for optional extra headers.
       Fix #381. 500 instead of 404 if CORS is enabled.

    .. versionchanged:: 0.3
       Support for X_MAX_AGE.

    .. versionchanged:: 0.1.0
       Support for optional HATEOAS.

    .. versionchanged:: 0.0.9
       Support for Python 3.3.

    .. versionchanged:: 0.0.7
       Support for Rate-Limiting.

    .. versionchanged:: 0.0.6
       Support for HEAD requests.

    .. versionchanged:: 0.0.5
       Support for Cross-Origin Resource Sharing (CORS).

    .. versionadded:: 0.0.4
    """
    if request.method == 'OPTIONS':
        resp = app.make_default_options_response()
    else:
        # obtain the best match between client's request and available mime
        # types, along with the corresponding render function.
        mime, renderer = _best_mime()

        # invoke the render function and obtain the corresponding rendered item
        rendered = globals()[renderer](dct)

        # JSONP
        if config.JSONP_ARGUMENT:
            jsonp_arg = config.JSONP_ARGUMENT
            if jsonp_arg in request.args and 'json' in mime:
                callback = request.args.get(jsonp_arg)
                rendered = "%s(%s)" % (callback, rendered)

        # build the main wsgi rensponse object
        resp = make_response(rendered, status)
        resp.mimetype = mime

    # extra headers
    if headers:
        for header, value in headers:
            if header != 'Content-Type':
                resp.headers.add(header, value)

    # cache directives
    if request.method in ('GET', 'HEAD'):
        if resource:
            cache_control = config.DOMAIN[resource]['cache_control']
            expires = config.DOMAIN[resource]['cache_expires']
        else:
            cache_control = config.CACHE_CONTROL
            expires = config.CACHE_EXPIRES
        if cache_control:
            resp.headers.add('Cache-Control', cache_control)
        if expires:
            resp.expires = time.time() + expires

    # etag and last-modified
    if etag:
        resp.headers.add('ETag', etag)
    if last_modified:
        resp.headers.add('Last-Modified', date_to_rfc1123(last_modified))

    # CORS
    origin = request.headers.get('Origin')
    if origin and config.X_DOMAINS:
        if isinstance(config.X_DOMAINS, str):
            domains = [config.X_DOMAINS]
        else:
            domains = config.X_DOMAINS

        if config.X_HEADERS is None:
            headers = []
        elif isinstance(config.X_HEADERS, str):
            headers = [config.X_HEADERS]
        else:
            headers = config.X_HEADERS

        if config.X_EXPOSE_HEADERS is None:
            expose_headers = []
        elif isinstance(config.X_EXPOSE_HEADERS, str):
            expose_headers = [config.X_EXPOSE_HEADERS]
        else:
            expose_headers = config.X_EXPOSE_HEADERS

        # The only accepted value for Access-Control-Allow-Credentials header
        # is "true"
        allow_credentials = config.X_ALLOW_CREDENTIALS is True

        methods = app.make_default_options_response().headers.get('allow', '')

        if '*' in domains:
            resp.headers.add('Access-Control-Allow-Origin', origin)
            resp.headers.add('Vary', 'Origin')
        elif origin in domains:
            resp.headers.add('Access-Control-Allow-Origin', origin)
        else:
            resp.headers.add('Access-Control-Allow-Origin', '')
        resp.headers.add('Access-Control-Allow-Headers', ', '.join(headers))
        resp.headers.add('Access-Control-Expose-Headers',
                         ', '.join(expose_headers))
        resp.headers.add('Access-Control-Allow-Methods', methods)
        resp.headers.add('Access-Control-Max-Age', config.X_MAX_AGE)
        if allow_credentials:
            resp.headers.add('Access-Control-Allow-Credentials', "true")

    # Rate-Limiting
    limit = get_rate_limit()
    if limit and limit.send_x_headers:
        resp.headers.add('X-RateLimit-Remaining', str(limit.remaining))
        resp.headers.add('X-RateLimit-Limit', str(limit.limit))
        resp.headers.add('X-RateLimit-Reset', str(limit.reset))

    return resp
예제 #6
0
파일: render.py 프로젝트: Zealsathish/eve
def _prepare_response(resource, dct, last_modified=None, etag=None,
                      status=200, headers=None):
    """ Prepares the response object according to the client request and
    available renderers, making sure that all accessory directives (caching,
    etag, last-modified) are present.

    :param resource: the resource involved.
    :param dct: the dict that should be sent back as a response.
    :param last_modified: Last-Modified header value.
    :param etag: ETag header value.
    :param status: response status.

    .. versionchanged:: 0.4
       Support for optional extra headers.
       Fix #381. 500 instead of 404 if CORS is enabled.

    .. versionchanged:: 0.3
       Support for X_MAX_AGE.

    .. versionchanged:: 0.1.0
       Support for optional HATEOAS.

    .. versionchanged:: 0.0.9
       Support for Python 3.3.

    .. versionchanged:: 0.0.7
       Support for Rate-Limiting.

    .. versionchanged:: 0.0.6
       Support for HEAD requests.

    .. versionchanged:: 0.0.5
       Support for Cross-Origin Resource Sharing (CORS).

    .. versionadded:: 0.0.4
    """
    if request.method == 'OPTIONS':
        resp = app.make_default_options_response()
    else:
        # obtain the best match between client's request and available mime
        # types, along with the corresponding render function.
        mime, renderer = _best_mime()

        # invoke the render function and obtain the corresponding rendered item
        rendered = globals()[renderer](dct)

        # build the main wsgi rensponse object
        resp = make_response(rendered, status)
        resp.mimetype = mime

    # extra headers
    if headers:
        for header, value in headers:
            if header != 'Content-Type':
                resp.headers.add(header, value)

    # cache directives
    if request.method in ('GET', 'HEAD'):
        if resource:
            cache_control = config.DOMAIN[resource]['cache_control']
            expires = config.DOMAIN[resource]['cache_expires']
        else:
            cache_control = config.CACHE_CONTROL
            expires = config.CACHE_EXPIRES
        if cache_control:
            resp.headers.add('Cache-Control', cache_control)
        if expires:
            resp.expires = time.time() + expires

    # etag and last-modified
    if etag:
        resp.headers.add('ETag', etag)
    if last_modified:
        resp.headers.add('Last-Modified', date_to_rfc1123(last_modified))

    # CORS
    origin = request.headers.get('Origin')
    if origin and config.X_DOMAINS:
        if isinstance(config.X_DOMAINS, str):
            domains = [config.X_DOMAINS]
        else:
            domains = config.X_DOMAINS

        if config.X_HEADERS is None:
            headers = []
        elif isinstance(config.X_HEADERS, str):
            headers = [config.X_HEADERS]
        else:
            headers = config.X_HEADERS

        if config.X_EXPOSE_HEADERS is None:
            expose_headers = []
        elif isinstance(config.X_EXPOSE_HEADERS, str):
            expose_headers = [config.X_EXPOSE_HEADERS]
        else:
            expose_headers = config.X_EXPOSE_HEADERS

        methods = app.make_default_options_response().headers.get('allow', '')

        if '*' in domains:
            resp.headers.add('Access-Control-Allow-Origin', origin)
            resp.headers.add('Vary', 'Origin')
        elif origin in domains:
            resp.headers.add('Access-Control-Allow-Origin', origin)
        else:
            resp.headers.add('Access-Control-Allow-Origin', '')
        resp.headers.add('Access-Control-Allow-Headers', ', '.join(headers))
        resp.headers.add('Access-Control-Expose-Headers',
                         ', '.join(expose_headers))
        resp.headers.add('Access-Control-Allow-Methods', methods)
        resp.headers.add('Access-Control-Allow-Max-Age', config.X_MAX_AGE)

    # Rate-Limiting
    limit = get_rate_limit()
    if limit and limit.send_x_headers:
        resp.headers.add('X-RateLimit-Remaining', str(limit.remaining))
        resp.headers.add('X-RateLimit-Limit', str(limit.limit))
        resp.headers.add('X-RateLimit-Reset', str(limit.reset))

    return resp
예제 #7
0
파일: render.py 프로젝트: sindbach/eve
def _prepare_response(resource,
                      dct,
                      last_modified=None,
                      etag=None,
                      status=200,
                      headers=None):
    """ Prepares the response object according to the client request and
    available renderers, making sure that all accessory directives (caching,
    etag, last-modified) are present.

    :param resource: the resource involved.
    :param dct: the dict that should be sent back as a response.
    :param last_modified: Last-Modified header value.
    :param etag: ETag header value.
    :param status: response status.

    .. versionchanged:: 0.7
       Add support for regexes in X_DOMAINS_RE. Closes #660, #974.
       ETag value now surrounded by double quotes. Closes #794.

    .. versionchanged:: 0.6
       JSONP Support.

    .. versionchanged:: 0.4
       Support for optional extra headers.
       Fix #381. 500 instead of 404 if CORS is enabled.

    .. versionchanged:: 0.3
       Support for X_MAX_AGE.

    .. versionchanged:: 0.1.0
       Support for optional HATEOAS.

    .. versionchanged:: 0.0.9
       Support for Python 3.3.

    .. versionchanged:: 0.0.7
       Support for Rate-Limiting.

    .. versionchanged:: 0.0.6
       Support for HEAD requests.

    .. versionchanged:: 0.0.5
       Support for Cross-Origin Resource Sharing (CORS).

    .. versionadded:: 0.0.4
    """
    if request.method == "OPTIONS":
        resp = app.make_default_options_response()
    else:
        # obtain the best match between client's request and available mime
        # types, along with the corresponding render function.
        mime, renderer_cls = _best_mime()

        # invoke the render function and obtain the corresponding rendered item
        rendered = renderer_cls().render(dct)

        # JSONP
        if config.JSONP_ARGUMENT:
            jsonp_arg = config.JSONP_ARGUMENT
            if jsonp_arg in request.args and "json" in mime:
                callback = request.args.get(jsonp_arg)
                rendered = "%s(%s)" % (callback, rendered)

        # build the main wsgi response object
        resp = make_response(rendered, status)
        resp.mimetype = mime

    # extra headers
    if headers:
        for header, value in headers:
            if header != "Content-Type":
                resp.headers.add(header, value)

    # cache directives
    if request.method in ("GET", "HEAD"):
        if resource:
            cache_control = config.DOMAIN[resource]["cache_control"]
            expires = config.DOMAIN[resource]["cache_expires"]
        else:
            cache_control = config.CACHE_CONTROL
            expires = config.CACHE_EXPIRES
        if cache_control:
            resp.headers.add("Cache-Control", cache_control)
        if expires:
            resp.expires = time.time() + expires

    # etag and last-modified
    if etag:
        resp.headers.add("ETag", '"' + etag + '"')
    if last_modified:
        resp.headers.add("Last-Modified", date_to_rfc1123(last_modified))

    # CORS
    origin = request.headers.get("Origin")
    if origin and (config.X_DOMAINS or config.X_DOMAINS_RE):
        if config.X_DOMAINS is None:
            domains = []
        elif isinstance(config.X_DOMAINS, str):
            domains = [config.X_DOMAINS]
        else:
            domains = config.X_DOMAINS

        if config.X_DOMAINS_RE is None:
            domains_re = []
        elif isinstance(config.X_DOMAINS_RE, str):
            domains_re = [config.X_DOMAINS_RE]
        else:
            domains_re = config.X_DOMAINS_RE

        # precompile regexes and ignore invalids
        domains_re_compiled = []
        for domain_re in domains_re:
            try:
                domains_re_compiled.append(re.compile(domain_re))
            except re.error:
                continue

        if config.X_HEADERS is None:
            headers = []
        elif isinstance(config.X_HEADERS, str):
            headers = [config.X_HEADERS]
        else:
            headers = config.X_HEADERS

        if config.X_EXPOSE_HEADERS is None:
            expose_headers = []
        elif isinstance(config.X_EXPOSE_HEADERS, str):
            expose_headers = [config.X_EXPOSE_HEADERS]
        else:
            expose_headers = config.X_EXPOSE_HEADERS

        # The only accepted value for Access-Control-Allow-Credentials header
        # is "true"
        allow_credentials = config.X_ALLOW_CREDENTIALS is True

        methods = app.make_default_options_response().headers.get("allow", "")

        if "*" in domains:
            resp.headers.add("Access-Control-Allow-Origin", origin)
            resp.headers.add("Vary", "Origin")
        elif any(origin == domain for domain in domains):
            resp.headers.add("Access-Control-Allow-Origin", origin)
        elif any(domain.match(origin) for domain in domains_re_compiled):
            resp.headers.add("Access-Control-Allow-Origin", origin)
        else:
            resp.headers.add("Access-Control-Allow-Origin", "")
        resp.headers.add("Access-Control-Allow-Headers", ", ".join(headers))
        resp.headers.add("Access-Control-Expose-Headers",
                         ", ".join(expose_headers))
        resp.headers.add("Access-Control-Allow-Methods", methods)
        resp.headers.add("Access-Control-Max-Age", config.X_MAX_AGE)
        if allow_credentials:
            resp.headers.add("Access-Control-Allow-Credentials", "true")

    # Rate-Limiting
    limit = get_rate_limit()
    if limit and limit.send_x_headers:
        resp.headers.add("X-RateLimit-Remaining", str(limit.remaining))
        resp.headers.add("X-RateLimit-Limit", str(limit.limit))
        resp.headers.add("X-RateLimit-Reset", str(limit.reset))

    return resp
예제 #8
0
def media_endpoint(_id):
    """ This endpoint is active when RETURN_MEDIA_AS_URL is True. It retrieves
    a media file and streams it to the client.

    .. versionadded:: 0.6
    """
    file_ = app.media.get(_id)
    if file_ is None:
        return abort(404)

    headers = {
        'Last-Modified': date_to_rfc1123(file_.upload_date),
        'Content-Length': file_.length,
        'Accept-Ranges': 'bytes',
    }

    range_header = request.headers.get('Range')
    if range_header:
        status = 206

        size = file_.length
        try:
            m = re.search('(\d+)-(\d*)', range_header)
            begin, end = m.groups()
            begin = int(begin)
            end = int(end)
        except:
            begin, end = 0, None

        length = size - begin
        if end is not None:
            length = end - begin + 1

        file_.seek(begin)

        data = file_.read(length)
        headers['Content-Range'] = 'bytes {0}-{1}/{2}'.format(
            begin,
            begin + length - 1,
            size
        )
    else:
        if_modified_since = weak_date(request.headers.get('If-Modified-Since'))
        if if_modified_since:
            if not if_modified_since.tzinfo:
                if_modified_since = if_modified_since.replace(
                    tzinfo=tz_util.utc)

            if if_modified_since > file_.upload_date:
                return Response(status=304)

        data = file_
        status = 200

    response = Response(
        data,
        status=status,
        headers=headers,
        mimetype=file_.content_type,
        direct_passthrough=True
    )

    return response
예제 #9
0
파일: render.py 프로젝트: nathforge/eve
def _prepare_response(resource, dct, last_modified=None, etag=None, status=200, headers=None):
    """ Prepares the response object according to the client request and
    available renderers, making sure that all accessory directives (caching,
    etag, last-modified) are present.

    :param resource: the resource involved.
    :param dct: the dict that should be sent back as a response.
    :param last_modified: Last-Modified header value.
    :param etag: ETag header value.
    :param status: response status.

    .. versionchanged:: 0.6
       JSONP Support.

    .. versionchanged:: 0.4
       Support for optional extra headers.
       Fix #381. 500 instead of 404 if CORS is enabled.

    .. versionchanged:: 0.3
       Support for X_MAX_AGE.

    .. versionchanged:: 0.1.0
       Support for optional HATEOAS.

    .. versionchanged:: 0.0.9
       Support for Python 3.3.

    .. versionchanged:: 0.0.7
       Support for Rate-Limiting.

    .. versionchanged:: 0.0.6
       Support for HEAD requests.

    .. versionchanged:: 0.0.5
       Support for Cross-Origin Resource Sharing (CORS).

    .. versionadded:: 0.0.4
    """
    if request.method == "OPTIONS":
        resp = app.make_default_options_response()
    else:
        # obtain the best match between client's request and available mime
        # types, along with the corresponding render function.
        mime, renderer = _best_mime()

        # invoke the render function and obtain the corresponding rendered item
        rendered = globals()[renderer](dct)

        # JSONP
        if config.JSONP_ARGUMENT:
            jsonp_arg = config.JSONP_ARGUMENT
            if jsonp_arg in request.args and "json" in mime:
                callback = request.args.get(jsonp_arg)
                rendered = "%s(%s)" % (callback, rendered)

        # build the main wsgi rensponse object
        resp = make_response(rendered, status)
        resp.mimetype = mime

    # extra headers
    if headers:
        for header, value in headers:
            if header != "Content-Type":
                resp.headers.add(header, value)

    # cache directives
    if request.method in ("GET", "HEAD"):
        if resource:
            cache_control = config.DOMAIN[resource]["cache_control"]
            expires = config.DOMAIN[resource]["cache_expires"]
        else:
            cache_control = config.CACHE_CONTROL
            expires = config.CACHE_EXPIRES
        if cache_control:
            resp.headers.add("Cache-Control", cache_control)
        if expires:
            resp.expires = time.time() + expires

    # etag and last-modified
    if etag:
        resp.headers.add("ETag", etag)
    if last_modified:
        resp.headers.add("Last-Modified", date_to_rfc1123(last_modified))

    # CORS
    origin = request.headers.get("Origin")
    if origin and config.X_DOMAINS:
        if isinstance(config.X_DOMAINS, str):
            domains = [config.X_DOMAINS]
        else:
            domains = config.X_DOMAINS

        if config.X_HEADERS is None:
            headers = []
        elif isinstance(config.X_HEADERS, str):
            headers = [config.X_HEADERS]
        else:
            headers = config.X_HEADERS

        if config.X_EXPOSE_HEADERS is None:
            expose_headers = []
        elif isinstance(config.X_EXPOSE_HEADERS, str):
            expose_headers = [config.X_EXPOSE_HEADERS]
        else:
            expose_headers = config.X_EXPOSE_HEADERS

        # The only accepted value for Access-Control-Allow-Credentials header
        # is "true"
        allow_credentials = config.X_ALLOW_CREDENTIALS is True

        methods = app.make_default_options_response().headers.get("allow", "")

        if "*" in domains:
            resp.headers.add("Access-Control-Allow-Origin", origin)
            resp.headers.add("Vary", "Origin")
        elif origin in domains:
            resp.headers.add("Access-Control-Allow-Origin", origin)
        else:
            resp.headers.add("Access-Control-Allow-Origin", "")
        resp.headers.add("Access-Control-Allow-Headers", ", ".join(headers))
        resp.headers.add("Access-Control-Expose-Headers", ", ".join(expose_headers))
        resp.headers.add("Access-Control-Allow-Methods", methods)
        resp.headers.add("Access-Control-Allow-Max-Age", config.X_MAX_AGE)
        if allow_credentials:
            resp.headers.add("Access-Control-Allow-Credentials", "true")

    # Rate-Limiting
    limit = get_rate_limit()
    if limit and limit.send_x_headers:
        resp.headers.add("X-RateLimit-Remaining", str(limit.remaining))
        resp.headers.add("X-RateLimit-Limit", str(limit.limit))
        resp.headers.add("X-RateLimit-Reset", str(limit.reset))

    return resp