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.
This commit is contained in:
@@ -21,6 +21,7 @@ zcash_gtest_SOURCES += \
|
|||||||
gtest/test_tautology.cpp \
|
gtest/test_tautology.cpp \
|
||||||
gtest/test_deprecation.cpp \
|
gtest/test_deprecation.cpp \
|
||||||
gtest/test_equihash.cpp \
|
gtest/test_equihash.cpp \
|
||||||
|
gtest/test_httprpc.cpp \
|
||||||
gtest/test_joinsplit.cpp \
|
gtest/test_joinsplit.cpp \
|
||||||
gtest/test_keystore.cpp \
|
gtest/test_keystore.cpp \
|
||||||
gtest/test_noteencryption.cpp \
|
gtest/test_noteencryption.cpp \
|
||||||
|
|||||||
62
src/gtest/test_httprpc.cpp
Normal file
62
src/gtest/test_httprpc.cpp
Normal file
@@ -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();
|
||||||
|
}
|
||||||
@@ -56,11 +56,14 @@ class HTTPRequest
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
struct evhttp_request* req;
|
struct evhttp_request* req;
|
||||||
|
|
||||||
|
// For test access
|
||||||
|
protected:
|
||||||
bool replySent;
|
bool replySent;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HTTPRequest(struct evhttp_request* req);
|
HTTPRequest(struct evhttp_request* req);
|
||||||
~HTTPRequest();
|
virtual ~HTTPRequest();
|
||||||
|
|
||||||
enum RequestMethod {
|
enum RequestMethod {
|
||||||
UNKNOWN,
|
UNKNOWN,
|
||||||
@@ -76,17 +79,17 @@ public:
|
|||||||
|
|
||||||
/** Get CService (address:ip) for the origin of the http request.
|
/** Get CService (address:ip) for the origin of the http request.
|
||||||
*/
|
*/
|
||||||
CService GetPeer();
|
virtual CService GetPeer();
|
||||||
|
|
||||||
/** Get request method.
|
/** Get request method.
|
||||||
*/
|
*/
|
||||||
RequestMethod GetRequestMethod();
|
virtual RequestMethod GetRequestMethod();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the request header specified by hdr, or an empty string.
|
* Get the request header specified by hdr, or an empty string.
|
||||||
* Return an pair (isPresent,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.
|
* Read request body.
|
||||||
@@ -101,7 +104,7 @@ public:
|
|||||||
*
|
*
|
||||||
* @note call this before calling WriteErrorReply or Reply.
|
* @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.
|
* Write HTTP reply.
|
||||||
@@ -111,7 +114,7 @@ public:
|
|||||||
* @note Can be called only once. As this will give the request back to the
|
* @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.
|
* 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.
|
/** Event handler closure.
|
||||||
|
|||||||
Reference in New Issue
Block a user