summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Käfer <mail@kkaefer.com>2015-11-19 21:47:15 +0100
committerKonstantin Käfer <mail@kkaefer.com>2015-11-20 14:39:44 +0100
commitb5f7cafab45471bd7d714fb2972e33603a4baaae (patch)
treeaff2a9125627105e1bd977105df5175f332b89dc
parent94e2d8a02c321380e650d055e7e7d6d6ed1c529d (diff)
downloadqtlocation-mapboxgl-b5f7cafab45471bd7d714fb2972e33603a4baaae.tar.gz
[core] more robust max-age parsing
-rw-r--r--src/mbgl/storage/http_request_base.cpp10
-rw-r--r--src/mbgl/util/http_header.cpp29
-rw-r--r--src/mbgl/util/http_header.hpp22
-rw-r--r--test/storage/headers.cpp71
-rw-r--r--test/test.gypi1
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',