From 3d08ef43f2f14c589ef90b3e8c9394acf71b7691 Mon Sep 17 00:00:00 2001 From: Veloman Yunkan Date: Thu, 14 May 2020 16:21:06 +0400 Subject: [PATCH] HEAD request is not rejected libmicrohttpd handles HEAD requests by dropping the body of the response (if any). Hence letting a HEAD request through into the code that processes GET requests is safe. Also added server unit-tests related to the handling of HEAD requests. --- src/server.cpp | 3 ++- test/server.cpp | 53 ++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/src/server.cpp b/src/server.cpp index 4a99a9609..e940b7924 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -301,7 +301,8 @@ int InternalServer::handlerCallback(struct MHD_Connection* connection, } /* Unexpected method */ if (request.get_method() != RequestMethod::GET - && request.get_method() != RequestMethod::POST) { + && request.get_method() != RequestMethod::POST + && request.get_method() != RequestMethod::HEAD) { printf("Reject request because of unhandled request method.\n"); printf("----------------------\n"); return MHD_NO; diff --git a/test/server.cpp b/test/server.cpp index 58c8450d5..26a9b603f 100644 --- a/test/server.cpp +++ b/test/server.cpp @@ -6,10 +6,25 @@ #include "./httplib.h" +template +T1 concat(T1 a, const T2& b) +{ + a.insert(a.end(), b.begin(), b.end()); + return a; +} + +typedef httplib::Headers Headers; + +Headers invariantHeaders(Headers headers) +{ + headers.erase("Date"); + return headers; +} + + class ZimFileServer { public: // types - typedef httplib::Headers Headers; typedef std::shared_ptr Response; public: // functions @@ -88,7 +103,9 @@ std::ostream& operator<<(std::ostream& out, const Resource& r) return out; } -Resource resources200Compressible[] = { +typedef std::vector ResourceCollection; + +const ResourceCollection resources200Compressible{ { "/" }, { "/skin/jquery-ui/jquery-ui.structure.min.css" }, @@ -110,7 +127,7 @@ Resource resources200Compressible[] = { { "/zimfile/A/Ray_Charles" }, }; -Resource resources200Uncompressible[] = { +const ResourceCollection resources200Uncompressible{ { "/skin/jquery-ui/images/ui-bg_flat_0_aaaaaa_40x100.png" }, { "/skin/jquery-ui/images/ui-bg_flat_75_ffffff_40x100.png" }, { "/skin/jquery-ui/images/ui-icons_222222_256x240.png" }, @@ -144,13 +161,14 @@ Resource resources200Uncompressible[] = { { "/zimfile/I/m/Ray_Charles_classic_piano_pose.jpg" }, }; +ResourceCollection all200Resources() +{ + return concat(resources200Compressible, resources200Uncompressible); +} TEST_F(ServerTest, 200) { - for ( const Resource& res : resources200Compressible ) - EXPECT_EQ(200, zfs1_->GET(res.url)->status) << "res.url: " << res.url; - - for ( const Resource& res : resources200Uncompressible ) + for ( const Resource& res : all200Resources() ) EXPECT_EQ(200, zfs1_->GET(res.url)->status) << "res.url: " << res.url; } @@ -221,3 +239,24 @@ TEST_F(ServerTest, BookMainPageIsRedirectedToArticleIndex) ASSERT_TRUE(g->has_header("Location")); ASSERT_EQ("/zimfile/A/index", g->get_header_value("Location")); } + +TEST_F(ServerTest, HeadMethodIsSupported) +{ + for ( const Resource& res : all200Resources() ) + EXPECT_EQ(200, zfs1_->HEAD(res.url)->status) << res; +} + +TEST_F(ServerTest, TheResponseToHeadRequestHasNoBody) +{ + for ( const Resource& res : all200Resources() ) + EXPECT_TRUE(zfs1_->HEAD(res.url)->body.empty()) << res; +} + +TEST_F(ServerTest, HeadersAreTheSameInResponsesToHeadAndGetRequests) +{ + for ( const Resource& res : all200Resources() ) { + httplib::Headers g = zfs1_->GET(res.url)->headers; + httplib::Headers h = zfs1_->HEAD(res.url)->headers; + EXPECT_EQ(invariantHeaders(g), invariantHeaders(h)) << res; + } +}