Browse Source

Add test for issue #2444

A WWW-Authenticate header must be present in the 401 response to make clients
know that they can authenticate, and how.
v1.0.12-rc
Jack Grigg 7 years ago
parent
commit
689264bbff
No known key found for this signature in database GPG Key ID: 665DBCD284F7DAFF
  1. 1
      src/Makefile.gtest.include
  2. 62
      src/gtest/test_httprpc.cpp
  3. 15
      src/httpserver.h

1
src/Makefile.gtest.include

@ -21,6 +21,7 @@ zcash_gtest_SOURCES += \
gtest/test_tautology.cpp \
gtest/test_deprecation.cpp \
gtest/test_equihash.cpp \
gtest/test_httprpc.cpp \
gtest/test_joinsplit.cpp \
gtest/test_keystore.cpp \
gtest/test_noteencryption.cpp \

62
src/gtest/test_httprpc.cpp

@ -0,0 +1,62 @@
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "httprpc.cpp"
#include "httpserver.h"
using ::testing::Return;
class MockHTTPRequest : public HTTPRequest {
public:
MOCK_METHOD0(GetPeer, CService());
MOCK_METHOD0(GetRequestMethod, HTTPRequest::RequestMethod());
MOCK_METHOD1(GetHeader, std::pair<bool, std::string>(const std::string& hdr));
MOCK_METHOD2(WriteHeader, void(const std::string& hdr, const std::string& value));
MOCK_METHOD2(WriteReply, void(int nStatus, const std::string& strReply));
MockHTTPRequest() : HTTPRequest(nullptr) {}
void CleanUp() {
// So the parent destructor doesn't try to send a reply
replySent = true;
}
};
TEST(HTTPRPC, FailsOnGET) {
MockHTTPRequest req;
EXPECT_CALL(req, GetRequestMethod())
.WillRepeatedly(Return(HTTPRequest::GET));
EXPECT_CALL(req, WriteReply(HTTP_BAD_METHOD, "JSONRPC server handles only POST requests"))
.Times(1);
EXPECT_FALSE(HTTPReq_JSONRPC(&req, ""));
req.CleanUp();
}
TEST(HTTPRPC, FailsWithoutAuthHeader) {
MockHTTPRequest req;
EXPECT_CALL(req, GetRequestMethod())
.WillRepeatedly(Return(HTTPRequest::POST));
EXPECT_CALL(req, GetHeader("authorization"))
.WillRepeatedly(Return(std::make_pair(false, "")));
EXPECT_CALL(req, WriteHeader("WWW-Authenticate", "Basic realm=\"jsonrpc\""))
.Times(1);
EXPECT_CALL(req, WriteReply(HTTP_UNAUTHORIZED, ""))
.Times(1);
EXPECT_FALSE(HTTPReq_JSONRPC(&req, ""));
req.CleanUp();
}
TEST(HTTPRPC, FailsWithBadAuth) {
MockHTTPRequest req;
EXPECT_CALL(req, GetRequestMethod())
.WillRepeatedly(Return(HTTPRequest::POST));
EXPECT_CALL(req, GetHeader("authorization"))
.WillRepeatedly(Return(std::make_pair(true, "Basic spam:eggs")));
EXPECT_CALL(req, GetPeer())
.WillRepeatedly(Return(CService("127.0.0.1:1337")));
EXPECT_CALL(req, WriteHeader("WWW-Authenticate", "Basic realm=\"jsonrpc\""))
.Times(1);
EXPECT_CALL(req, WriteReply(HTTP_UNAUTHORIZED, ""))
.Times(1);
EXPECT_FALSE(HTTPReq_JSONRPC(&req, ""));
req.CleanUp();
}

15
src/httpserver.h

@ -56,11 +56,14 @@ class HTTPRequest
{
private:
struct evhttp_request* req;
// For test access
protected:
bool replySent;
public:
HTTPRequest(struct evhttp_request* req);
~HTTPRequest();
virtual ~HTTPRequest();
enum RequestMethod {
UNKNOWN,
@ -76,17 +79,17 @@ public:
/** Get CService (address:ip) for the origin of the http request.
*/
CService GetPeer();
virtual CService GetPeer();
/** Get request method.
*/
RequestMethod GetRequestMethod();
virtual RequestMethod GetRequestMethod();
/**
* Get the request header specified by hdr, or an empty string.
* Return an pair (isPresent,string).
*/
std::pair<bool, std::string> GetHeader(const std::string& hdr);
virtual std::pair<bool, std::string> GetHeader(const std::string& hdr);
/**
* Read request body.
@ -101,7 +104,7 @@ public:
*
* @note call this before calling WriteErrorReply or Reply.
*/
void WriteHeader(const std::string& hdr, const std::string& value);
virtual void WriteHeader(const std::string& hdr, const std::string& value);
/**
* Write HTTP reply.
@ -111,7 +114,7 @@ public:
* @note Can be called only once. As this will give the request back to the
* main thread, do not call any other HTTPRequest methods after calling this.
*/
void WriteReply(int nStatus, const std::string& strReply = "");
virtual void WriteReply(int nStatus, const std::string& strReply = "");
};
/** Event handler closure.

Loading…
Cancel
Save