std::unique_ptr get_decompressor_from_header()

in Release/src/http/common/http_compression.cpp [1003:1095]


std::unique_ptr<decompress_provider> get_decompressor_from_header(
    const utility::string_t& encoding,
    header_types type,
    const std::vector<std::shared_ptr<decompress_factory>>& factories)
{
    const std::vector<std::shared_ptr<decompress_factory>>& f =
        factories.empty() ? web::http::compression::builtin::g_decompress_factories : factories;
    std::unique_ptr<decompress_provider> decompressor;
    utility::string_t token;
    size_t start;
    size_t length;
    size_t comma;
    size_t n;

    _ASSERTE(type == header_types::transfer_encoding || type == header_types::content_encoding);

    n = 0;
    while (n != utility::string_t::npos)
    {
        // Tokenize by commas first
        comma = encoding.find(_XPLATSTR(','), n);
        start = n;
        if (comma == utility::string_t::npos)
        {
            length = encoding.size() - n;
            n = utility::string_t::npos;
        }
        else
        {
            length = comma - n;
            n = comma + 1;
        }

        // Then remove leading and trailing whitespace
        remove_surrounding_http_whitespace(encoding, start, length);

        if (!length)
        {
            throw http_exception(status_codes::BadRequest, "Empty field in header");
        }

        // Immediately try to instantiate a decompressor
        token = encoding.substr(start, length);
        auto d = web::http::compression::builtin::_make_decompressor(f, token);
        if (d)
        {
            if (decompressor)
            {
                status_code code = status_codes::NotImplemented;
                if (type == header_types::content_encoding)
                {
                    code = status_codes::UnsupportedMediaType;
                }
                throw http_exception(code, "Multiple compression algorithms not supported for a single request");
            }

            // We found our decompressor; store it off while we process the rest of the header
            decompressor = std::move(d);
        }
        else
        {
            if (n != utility::string_t::npos)
            {
                if (type == header_types::transfer_encoding &&
                    utility::details::str_iequal(_XPLATSTR("chunked"), token))
                {
                    throw http_exception(status_codes::BadRequest,
                                         "Chunked must come last in the Transfer-Encoding header");
                }
            }
            if (!decompressor && !f.empty() && (n != utility::string_t::npos || type == header_types::content_encoding))
            {
                // The first encoding type did not match; throw an informative
                // exception with an encoding-type-appropriate HTTP error code
                status_code code = status_codes::NotImplemented;
                if (type == header_types::content_encoding)
                {
                    code = status_codes::UnsupportedMediaType;
                }
                throw http_exception(code, "Unsupported encoding type");
            }
        }
    }

    if (type == header_types::transfer_encoding && !utility::details::str_iequal(_XPLATSTR("chunked"), token))
    {
        throw http_exception(status_codes::BadRequest, "Transfer-Encoding header missing chunked");
    }

    // Either the response is compressed and we have a decompressor that can handle it, or
    // built-in compression is not enabled and we don't have an alternate set of decompressors
    return decompressor;
}