You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by be...@apache.org on 2014/01/17 23:10:06 UTC
git commit: Add post function to http.hpp of libprocess.
Updated Branches:
refs/heads/master b3ec466fa -> 115ab9450
Add post function to http.hpp of libprocess.
This adds the post equivalent of the get function to http.hpp.
The existing get method is refactored into internal::request with
arguments for method, path, query, contentType, and body.
The get and post functions can then be implemented as simple wrappers
of internal::request.
The new post function has all required arguments of path, contentType,
and body.
The get function's query argument is also changed to be Option<string>
to better indicate that it is optional.
That change requires adding a forwarding overload with the old
signature (but w/o the default parameter value) for back-compat.
There are also new unit tests to verify the existing behavior of get
and the new post behavior.
From: Charlie Carson <cc...@twitter.com>
Review: https://reviews.apache.org/r/16839
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/115ab945
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/115ab945
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/115ab945
Branch: refs/heads/master
Commit: 115ab94501c838161dd3b35dd1c889314408daf9
Parents: b3ec466
Author: Benjamin Hindman <be...@gmail.com>
Authored: Fri Jan 17 14:07:47 2014 -0800
Committer: Benjamin Hindman <be...@gmail.com>
Committed: Fri Jan 17 14:09:43 2014 -0800
----------------------------------------------------------------------
3rdparty/libprocess/include/process/http.hpp | 20 ++++-
3rdparty/libprocess/src/process.cpp | 56 ++++++++++---
3rdparty/libprocess/src/tests/http_tests.cpp | 95 +++++++++++++++++++++++
3 files changed, 161 insertions(+), 10 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/115ab945/3rdparty/libprocess/include/process/http.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/include/process/http.hpp b/3rdparty/libprocess/include/process/http.hpp
index 5bdd520..a8b1636 100644
--- a/3rdparty/libprocess/include/process/http.hpp
+++ b/3rdparty/libprocess/include/process/http.hpp
@@ -482,7 +482,25 @@ inline Try<std::string> decode(const std::string& s)
Future<Response> get(
const UPID& upid,
const std::string& path = "",
- const std::string& query = "");
+ const Option<std::string>& query = None());
+
+
+// Backwards compatible wrapper for the above.
+// There are clients who pass in string literals to query that cannot be
+// converted automatically to Option<string>.
+Future<Response> get(
+ const UPID& upid,
+ const std::string& path,
+ const std::string& query);
+
+
+// Sends a blocking HTTP POST request to the process with the given upid.
+// Returns the HTTP response from the process, read asyncronously.
+Future<Response> post(
+ const UPID& upid,
+ const std::string& path,
+ const std::string& contentType,
+ const std::string& body);
// Status code reason strings, from the HTTP1.1 RFC:
http://git-wip-us.apache.org/repos/asf/mesos/blob/115ab945/3rdparty/libprocess/src/process.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/process.cpp b/3rdparty/libprocess/src/process.cpp
index 8cad696..936f118 100644
--- a/3rdparty/libprocess/src/process.cpp
+++ b/3rdparty/libprocess/src/process.cpp
@@ -67,6 +67,7 @@
#include <stout/lambda.hpp>
#include <stout/memory.hpp> // TODO(benh): Replace shared_ptr with unique_ptr.
#include <stout/net.hpp>
+#include <stout/option.hpp>
#include <stout/os.hpp>
#include <stout/strings.hpp>
#include <stout/thread.hpp>
@@ -3616,10 +3617,14 @@ Future<Response> decode(const string& buffer)
return response;
}
-} // namespace internal {
-
-Future<Response> get(const UPID& upid, const string& path, const string& query)
+Future<Response> request(
+ const UPID& upid,
+ const string& method,
+ const string& path,
+ const Option<string>& query,
+ const Option<string>& contentType,
+ const Option<string>& body)
{
int s = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
@@ -3645,19 +3650,30 @@ Future<Response> get(const UPID& upid, const string& path, const string& query)
std::ostringstream out;
- if (query.empty()) {
- out << "GET /" << upid.id << "/" << path << " HTTP/1.1\r\n";
- } else {
- out << "GET /" << upid.id << "/" << path << "?" << query << " HTTP/1.1\r\n";
+ out << method << " /" << upid.id << "/" << path;
+ if (query.isSome()) {
+ out << "?" << query.get();
}
+ out << " HTTP/1.1\r\n";
// Call inet_ntop since inet_ntoa is not thread-safe!
char ip[INET_ADDRSTRLEN];
PCHECK(inet_ntop(AF_INET, (in_addr *) &upid.ip, ip, INET_ADDRSTRLEN) != NULL);
out << "Host: " << ip << ":" << upid.port << "\r\n"
- << "Connection: close\r\n"
- << "\r\n";
+ << "Connection: close\r\n";
+
+ if (contentType.isSome()) {
+ out << "Content-Type: " << contentType.get() << "\r\n";
+ }
+
+ if (body.isNone()) {
+ out << "\r\n";
+ } else {
+ out << "Content-Length: " << body.get().length() << "\r\n"
+ << "\r\n"
+ << body.get();
+ }
// TODO(bmahler): Use benh's async write when it gets committed.
const string& data = out.str();
@@ -3689,6 +3705,28 @@ Future<Response> get(const UPID& upid, const string& path, const string& query)
.onAny(lambda::bind(&os::close, s));
}
+} // namespace internal {
+
+
+Future<Response> get(const UPID& upid, const string& path, const Option<string>& query)
+{
+ return internal::request(upid, "GET", path, query, None(), None());
+}
+
+
+// Overload for back-compat.
+Future<Response> get(const UPID& upid, const string& path, const string& query)
+{
+ //In this overload empty string means no query.
+ return get(upid, path, query.empty() ? Option<string>::none() : Some(query));
+}
+
+
+Future<Response> post(const UPID& upid, const string& path, const string& contentType, const string& body)
+{
+ return internal::request(upid, "POST", path, None(), contentType, body);
+}
+
} // namespace http {
namespace internal {
http://git-wip-us.apache.org/repos/asf/mesos/blob/115ab945/3rdparty/libprocess/src/tests/http_tests.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/tests/http_tests.cpp b/3rdparty/libprocess/src/tests/http_tests.cpp
index 68d1a1b..c27e027 100644
--- a/3rdparty/libprocess/src/tests/http_tests.cpp
+++ b/3rdparty/libprocess/src/tests/http_tests.cpp
@@ -25,6 +25,8 @@ using namespace process;
using testing::_;
using testing::Assign;
using testing::DoAll;
+using testing::EndsWith;
+using testing::Invoke;
using testing::Return;
@@ -35,10 +37,14 @@ public:
{
route("/body", None(), &HttpProcess::body);
route("/pipe", None(), &HttpProcess::pipe);
+ route("/get", None(), &HttpProcess::get);
+ route("/post", None(), &HttpProcess::post);
}
MOCK_METHOD1(body, Future<http::Response>(const http::Request&));
MOCK_METHOD1(pipe, Future<http::Response>(const http::Request&));
+ MOCK_METHOD1(get, Future<http::Response>(const http::Request&));
+ MOCK_METHOD1(post, Future<http::Response>(const http::Request&));
};
@@ -178,3 +184,92 @@ TEST(HTTP, PathParse)
EXPECT_ERROR(parse);
EXPECT_EQ("Not expecting suffix 'foo/bar'", parse.error());
}
+
+
+http::Response validateGetWithoutQuery(const http::Request& request)
+{
+ EXPECT_EQ("GET", request.method);
+ EXPECT_THAT(request.path, EndsWith("get"));
+ EXPECT_EQ("", request.body);
+ EXPECT_EQ("", request.fragment);
+ EXPECT_TRUE(request.query.empty());
+
+ return http::OK();
+}
+
+
+http::Response validateGetWithQuery(const http::Request& request)
+{
+ EXPECT_EQ("GET", request.method);
+ EXPECT_THAT(request.path, EndsWith("get"));
+ EXPECT_EQ("", request.body);
+ EXPECT_EQ("frag", request.fragment);
+ EXPECT_EQ("bar", request.query.at("foo"));
+ EXPECT_EQ(1, request.query.size());
+
+ return http::OK();
+}
+
+
+TEST(HTTP, Get)
+{
+ ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
+ HttpProcess process;
+
+ spawn(process);
+
+ EXPECT_CALL(process, get(_))
+ .WillOnce(Invoke(validateGetWithoutQuery));
+
+ Future<http::Response> noQueryFuture = http::get(process.self(), "get");
+
+ AWAIT_READY(noQueryFuture);
+ ASSERT_EQ(http::statuses[200], noQueryFuture.get().status);
+
+ EXPECT_CALL(process, get(_))
+ .WillOnce(Invoke(validateGetWithQuery));
+
+ Future<http::Response> queryFuture =
+ http::get(process.self(), "get", Some("foo=bar#frag"));
+
+ AWAIT_READY(queryFuture);
+ ASSERT_EQ(http::statuses[200], queryFuture.get().status);
+
+ terminate(process);
+ wait(process);
+}
+
+
+http::Response validatePost(const http::Request& request)
+{
+ EXPECT_EQ("POST", request.method);
+ EXPECT_THAT(request.path, EndsWith("post"));
+ EXPECT_EQ("This is the payload.", request.body);
+ EXPECT_EQ("", request.fragment);
+ EXPECT_TRUE(request.query.empty());
+
+ return http::OK();
+}
+
+
+TEST(HTTP, Post)
+{
+ ASSERT_TRUE(GTEST_IS_THREADSAFE);
+
+ HttpProcess process;
+
+ spawn(process);
+
+ EXPECT_CALL(process, post(_))
+ .WillOnce(Invoke(validatePost));
+
+ Future<http::Response> future =
+ http::post(process.self(), "post", "text/plain", "This is the payload.");
+
+ AWAIT_READY(future);
+ ASSERT_EQ(http::statuses[200], future.get().status);
+
+ terminate(process);
+ wait(process);
+}