diff options
author | Konstantin Käfer <mail@kkaefer.com> | 2015-11-19 21:47:15 +0100 |
---|---|---|
committer | Konstantin Käfer <mail@kkaefer.com> | 2015-11-20 14:39:44 +0100 |
commit | b5f7cafab45471bd7d714fb2972e33603a4baaae (patch) | |
tree | aff2a9125627105e1bd977105df5175f332b89dc | |
parent | 94e2d8a02c321380e650d055e7e7d6d6ed1c529d (diff) | |
download | qtlocation-mapboxgl-b5f7cafab45471bd7d714fb2972e33603a4baaae.tar.gz |
[core] more robust max-age parsing
-rw-r--r-- | src/mbgl/storage/http_request_base.cpp | 10 | ||||
-rw-r--r-- | src/mbgl/util/http_header.cpp | 29 | ||||
-rw-r--r-- | src/mbgl/util/http_header.hpp | 22 | ||||
-rw-r--r-- | test/storage/headers.cpp | 71 | ||||
-rw-r--r-- | test/test.gypi | 1 |
5 files changed, 128 insertions, 5 deletions
diff --git a/src/mbgl/storage/http_request_base.cpp b/src/mbgl/storage/http_request_base.cpp index 2da453ead8..f9e40c4f2b 100644 --- a/src/mbgl/storage/http_request_base.cpp +++ b/src/mbgl/storage/http_request_base.cpp @@ -1,18 +1,18 @@ #include <mbgl/storage/http_request_base.hpp> +#include <mbgl/util/http_header.hpp> #include <mbgl/util/chrono.hpp> namespace mbgl { int64_t HTTPRequestBase::parseCacheControl(const char *value) { if (value) { - unsigned long long seconds = 0; - // TODO: cache-control may contain other information as well: - // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9 - if (std::sscanf(value, "max-age=%llu", &seconds) == 1) { + const auto cacheControl = http::CacheControl::parse(value); + + if (cacheControl.maxAge) { return std::chrono::duration_cast<std::chrono::seconds>( std::chrono::system_clock::now().time_since_epoch()).count() + - seconds; + *cacheControl.maxAge; } } diff --git a/src/mbgl/util/http_header.cpp b/src/mbgl/util/http_header.cpp new file mode 100644 index 0000000000..00aee151c8 --- /dev/null +++ b/src/mbgl/util/http_header.cpp @@ -0,0 +1,29 @@ +#include <mbgl/util/http_header.hpp> + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wshadow" +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/phoenix_core.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> +#pragma GCC diagnostic pop + +namespace mbgl { +namespace http { + +CacheControl CacheControl::parse(const std::string& value) { + namespace qi = boost::spirit::qi; + namespace phoenix = boost::phoenix; + + CacheControl result; + qi::phrase_parse(value.begin(), value.end(), ( + (qi::lit("must-revalidate") [ phoenix::ref(result.mustRevalidate) = true ]) | + (qi::lit("max-age") >> '=' >> qi::ulong_long [ phoenix::ref(result.maxAge) = qi::_1 ]) | + (*(('"' >> *(('\\' >> qi::char_) | (qi::char_ - '"')) >> '"') | (qi::char_ - '"' - ','))) + ) % ',', qi::ascii::space); + return result; +} + +} // namespace http +} // namespace mbgl diff --git a/src/mbgl/util/http_header.hpp b/src/mbgl/util/http_header.hpp new file mode 100644 index 0000000000..bd1f809cee --- /dev/null +++ b/src/mbgl/util/http_header.hpp @@ -0,0 +1,22 @@ +#ifndef MBGL_UTIL_HTTP_HEADER +#define MBGL_UTIL_HTTP_HEADER + +#include <mapbox/optional.hpp> + +#include <string> + +namespace mbgl { +namespace http { + +class CacheControl { +public: + static CacheControl parse(const std::string&); + + mapbox::util::optional<uint64_t> maxAge; + bool mustRevalidate = false; +}; + +} // namespace http +} // namespace mbgl + +#endif diff --git a/test/storage/headers.cpp b/test/storage/headers.cpp new file mode 100644 index 0000000000..a0b6ecd546 --- /dev/null +++ b/test/storage/headers.cpp @@ -0,0 +1,71 @@ +#include "storage.hpp" +#include "../fixtures/fixture_log_observer.hpp" + +#include <mbgl/util/http_header.hpp> + +TEST_F(Storage, HTTPHeaderParsing) { + using namespace mbgl; + + http::CacheControl cc; + + cc = http::CacheControl::parse(R"#()#"); + ASSERT_FALSE(bool(cc.maxAge)); + EXPECT_EQ(false, cc.mustRevalidate); + + cc = http::CacheControl::parse(R"#(max-age =34)#"); + ASSERT_TRUE(bool(cc.maxAge)); + EXPECT_EQ(34, *cc.maxAge); + EXPECT_EQ(false, cc.mustRevalidate); + + cc = http::CacheControl::parse(R"#(,max-age=1)#"); + ASSERT_TRUE(bool(cc.maxAge)); + EXPECT_EQ(1, *cc.maxAge); + EXPECT_EQ(false, cc.mustRevalidate); + + cc = http::CacheControl::parse(R"#(max-age=-1)#"); + ASSERT_FALSE(bool(cc.maxAge)); + EXPECT_EQ(false, cc.mustRevalidate); + + cc = http::CacheControl::parse(R"#(max-age=foo)#"); + ASSERT_FALSE(bool(cc.maxAge)); + EXPECT_EQ(false, cc.mustRevalidate); + + cc = http::CacheControl::parse(R"#(max-age="34,max-age="22,max-age=28)#"); + ASSERT_TRUE(bool(cc.maxAge)); + EXPECT_EQ(28, *cc.maxAge); + EXPECT_EQ(false, cc.mustRevalidate); + + cc = http::CacheControl::parse(R"#(max-age=3,max-age="34)#"); + ASSERT_TRUE(bool(cc.maxAge)); + EXPECT_EQ(3, *cc.maxAge); + EXPECT_EQ(false, cc.mustRevalidate); + + cc = http::CacheControl::parse(R"#(max-age="\",max-age=4,")#"); + ASSERT_FALSE(bool(cc.maxAge)); + EXPECT_EQ(false, cc.mustRevalidate); + + cc = http::CacheControl::parse(R"#(private, max-age=0, no-cache)#"); + ASSERT_TRUE(bool(cc.maxAge)); + EXPECT_EQ(0, *cc.maxAge); + EXPECT_EQ(false, cc.mustRevalidate); + + cc = http::CacheControl::parse(R"#(max-age=0, no-cache, no-store)#"); + ASSERT_TRUE(bool(cc.maxAge)); + EXPECT_EQ(0, *cc.maxAge); + EXPECT_EQ(false, cc.mustRevalidate); + + cc = http::CacheControl::parse(R"#(, private , max-bar=3 , no-cache, "\,",,foo=",",,max-age=32)#"); + ASSERT_TRUE(bool(cc.maxAge)); + EXPECT_EQ(32, *cc.maxAge); + EXPECT_EQ(false, cc.mustRevalidate); + + cc = http::CacheControl::parse(R"#(max-age=3600, must-revalidate)#"); + ASSERT_TRUE(bool(cc.maxAge)); + EXPECT_EQ(3600, *cc.maxAge); + EXPECT_EQ(true, cc.mustRevalidate); + + cc = http::CacheControl::parse(R"#(no-cache="Expires,Via",max-age=3600, must-revalidate)#"); + ASSERT_TRUE(bool(cc.maxAge)); + EXPECT_EQ(3600, *cc.maxAge); + EXPECT_EQ(true, cc.mustRevalidate); +} diff --git a/test/test.gypi b/test/test.gypi index 88448cc807..583474a988 100644 --- a/test/test.gypi +++ b/test/test.gypi @@ -72,6 +72,7 @@ 'storage/database.cpp', 'storage/directory_reading.cpp', 'storage/file_reading.cpp', + 'storage/headers.cpp', 'storage/http_cancel.cpp', 'storage/http_coalescing.cpp', 'storage/http_error.cpp', |