Remove http version; refine sending request and error handling.
This commit is contained in:
@@ -15,6 +15,7 @@ if(MSVC)
|
|||||||
add_definitions(-D_WIN32_WINNT=0x0601)
|
add_definitions(-D_WIN32_WINNT=0x0601)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Boost version: 1.66+
|
||||||
set(Boost_USE_STATIC_LIBS ON)
|
set(Boost_USE_STATIC_LIBS ON)
|
||||||
find_package(Boost)
|
find_package(Boost)
|
||||||
if(Boost_FOUND)
|
if(Boost_FOUND)
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ if(UNIX)
|
|||||||
add_definitions(-D_GLIBCXX_USE_WCHAR_T -std=c++11)
|
add_definitions(-D_GLIBCXX_USE_WCHAR_T -std=c++11)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Don't use any deprecated definitions (e.g., io_service).
|
||||||
|
add_definitions(-DBOOST_ASIO_NO_DEPRECATED)
|
||||||
|
|
||||||
file(GLOB SRCS *.cc *.h)
|
file(GLOB SRCS *.cc *.h)
|
||||||
|
|
||||||
add_library(csoap ${SRCS})
|
add_library(csoap ${SRCS})
|
||||||
|
|||||||
+4
-2
@@ -7,8 +7,10 @@ namespace csoap {
|
|||||||
// NOTE:
|
// NOTE:
|
||||||
// Field names are case-insensitive.
|
// Field names are case-insensitive.
|
||||||
// See: https://stackoverflow.com/a/5259004
|
// See: https://stackoverflow.com/a/5259004
|
||||||
const std::string kContentTypeName = "Content-Type";
|
const std::string kContentType = "Content-Type";
|
||||||
const std::string kContentLengthName = "Content-Length";
|
const std::string kContentLength = "Content-Length";
|
||||||
|
const std::string kSOAPAction = "SOAPAction";
|
||||||
|
const std::string kHost = "Host";
|
||||||
|
|
||||||
// According to www.w3.org when placing SOAP messages in HTTP bodies, the HTTP
|
// According to www.w3.org when placing SOAP messages in HTTP bodies, the HTTP
|
||||||
// Content-type header must be chosen as "application/soap+xml" [RFC 3902].
|
// Content-type header must be chosen as "application/soap+xml" [RFC 3902].
|
||||||
|
|||||||
+5
-29
@@ -10,29 +10,17 @@ namespace csoap {
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// API decorators.
|
|
||||||
// For a given class, e.g., SoapRequest, some APIs are for client while others
|
|
||||||
// are for server. In order to make it clear to the user, use the following
|
|
||||||
// macros to decorate.
|
|
||||||
#define SERVER_API
|
|
||||||
#define CLIENT_API
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
|
|
||||||
// Buffer size for sending HTTP request and receiving HTTP response.
|
// Buffer size for sending HTTP request and receiving HTTP response.
|
||||||
const std::size_t BUF_SIZE = 1024;
|
const std::size_t BUF_SIZE = 1024;
|
||||||
|
const std::size_t kInvalidLength = std::string::npos;
|
||||||
|
|
||||||
static const std::string kCRLF = "\r\n";
|
extern const std::string kContentType;
|
||||||
|
extern const std::string kContentLength;
|
||||||
extern const std::string kContentTypeName;
|
extern const std::string kSOAPAction;
|
||||||
extern const std::string kContentLengthName;
|
extern const std::string kHost;
|
||||||
|
|
||||||
extern const std::string kTextXmlUtf8;
|
extern const std::string kTextXmlUtf8;
|
||||||
|
|
||||||
const std::size_t kInvalidLength = std::string::npos;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Error codes.
|
// Error codes.
|
||||||
@@ -64,12 +52,6 @@ const char* GetErrorMessage(Error error);
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// TODO: No 1.1 feature has been used or supported yet.
|
|
||||||
enum HttpVersion {
|
|
||||||
kHttpV10,
|
|
||||||
kHttpV11,
|
|
||||||
};
|
|
||||||
|
|
||||||
// HTTP response status.
|
// HTTP response status.
|
||||||
// NOTE: Only support the listed status codes.
|
// NOTE: Only support the listed status codes.
|
||||||
enum HttpStatus {
|
enum HttpStatus {
|
||||||
@@ -80,12 +62,6 @@ enum HttpStatus {
|
|||||||
SERVICE_UNAVAILABLE = 503,
|
SERVICE_UNAVAILABLE = 503,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum HeaderField {
|
|
||||||
kHeaderContentType,
|
|
||||||
kHeaderContentLength,
|
|
||||||
kHeaderHost,
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// XML namespace name/url pair.
|
// XML namespace name/url pair.
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ void Connection::HandleRead(boost::system::error_code ec,
|
|||||||
// Bad request.
|
// Bad request.
|
||||||
response_ = HttpResponse::Fault(HttpStatus::BAD_REQUEST);
|
response_ = HttpResponse::Fault(HttpStatus::BAD_REQUEST);
|
||||||
DoWrite();
|
DoWrite();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +66,8 @@ void Connection::HandleRead(boost::system::error_code ec,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle request.
|
// Handle request.
|
||||||
request_handler_.HandleRequest(request_, response_);
|
// TODO: Time consuming
|
||||||
|
request_handler_.HandleRequest(request_, &response_);
|
||||||
|
|
||||||
// Send back the response.
|
// Send back the response.
|
||||||
DoWrite();
|
DoWrite();
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ private:
|
|||||||
HttpRequestHandler& request_handler_;
|
HttpRequestHandler& request_handler_;
|
||||||
|
|
||||||
// Buffer for incoming data.
|
// Buffer for incoming data.
|
||||||
std::array<char, 8192> buffer_;
|
std::array<char, BUF_SIZE> buffer_;
|
||||||
|
|
||||||
// The incoming request.
|
// The incoming request.
|
||||||
HttpRequest request_;
|
HttpRequest request_;
|
||||||
|
|||||||
+13
-19
@@ -4,10 +4,6 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "boost/algorithm/string.hpp"
|
|
||||||
#include "boost/bind.hpp"
|
|
||||||
#include "boost/lexical_cast.hpp"
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
#include "boost/asio.hpp"
|
#include "boost/asio.hpp"
|
||||||
#else
|
#else
|
||||||
@@ -20,7 +16,10 @@
|
|||||||
#include "csoap/http_response_parser.h"
|
#include "csoap/http_response_parser.h"
|
||||||
#include "csoap/http_request.h"
|
#include "csoap/http_request.h"
|
||||||
#include "csoap/http_response.h"
|
#include "csoap/http_response.h"
|
||||||
#include "csoap/xml.h"
|
|
||||||
|
#if CSOAP_ENABLE_OUTPUT
|
||||||
|
#include "csoap/xml.h" // For pretty print response XML.
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace csoap {
|
namespace csoap {
|
||||||
|
|
||||||
@@ -71,10 +70,9 @@ Error HttpClient::SendRequest(const HttpRequest& request,
|
|||||||
port = "80";
|
port = "80";
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: IPv4 or both IPv4 and IPv6
|
|
||||||
boost::system::error_code ec;
|
boost::system::error_code ec;
|
||||||
tcp::resolver::results_type endpoints =
|
tcp::resolver::results_type endpoints =
|
||||||
resolver.resolve(/*tcp::v4(), */request.host(), port, ec);
|
resolver.resolve(tcp::v4(), request.host(), port, ec);
|
||||||
if (ec) {
|
if (ec) {
|
||||||
return kHostResolveError;
|
return kHostResolveError;
|
||||||
}
|
}
|
||||||
@@ -88,23 +86,20 @@ Error HttpClient::SendRequest(const HttpRequest& request,
|
|||||||
|
|
||||||
// Send HTTP request.
|
// Send HTTP request.
|
||||||
|
|
||||||
std::string headers = request.GetHeaders();
|
|
||||||
|
|
||||||
std::vector<boost::asio::const_buffer> buffers{
|
|
||||||
boost::asio::buffer(headers),
|
|
||||||
boost::asio::buffer(request.content()),
|
|
||||||
};
|
|
||||||
|
|
||||||
#if CSOAP_ENABLE_OUTPUT
|
#if CSOAP_ENABLE_OUTPUT
|
||||||
std::cout << request << std::endl;
|
std::cout << "# REQUEST" << std::endl << request << std::endl;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
try {
|
try {
|
||||||
boost::asio::write(socket, buffers);
|
boost::asio::write(socket, request.ToBuffers());
|
||||||
} catch (boost::system::system_error&) {
|
} catch (boost::system::system_error&) {
|
||||||
return kSocketWriteError;
|
return kSocketWriteError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CSOAP_ENABLE_OUTPUT
|
||||||
|
std::cout << "# RESPONSE" << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Read and parse HTTP response.
|
// Read and parse HTTP response.
|
||||||
|
|
||||||
HttpResponseParser parser(response);
|
HttpResponseParser parser(response);
|
||||||
@@ -139,10 +134,9 @@ Error HttpClient::SendRequest(const HttpRequest& request,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if CSOAP_ENABLE_OUTPUT
|
#if CSOAP_ENABLE_OUTPUT
|
||||||
std::cout << std::endl << std::endl;
|
|
||||||
std::cout << "[ PRETTY PRINT ]" << std::endl;
|
|
||||||
xml::PrettyPrintXml(std::cout, response->content());
|
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
|
std::cout << "# RESPONSE (PARSED)" << std::endl;
|
||||||
|
std::cout << *response << std::endl;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return kNoError;
|
return kNoError;
|
||||||
|
|||||||
@@ -2,12 +2,7 @@
|
|||||||
#define CSOAP_HTTP_CLIENT_H_
|
#define CSOAP_HTTP_CLIENT_H_
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <string>
|
|
||||||
|
|
||||||
// Don't use any deprecated definitions (e.g., io_service).
|
|
||||||
#define BOOST_ASIO_NO_DEPRECATED
|
|
||||||
#include "boost/asio/io_context.hpp"
|
#include "boost/asio/io_context.hpp"
|
||||||
|
|
||||||
#include "csoap/common.h"
|
#include "csoap/common.h"
|
||||||
|
|
||||||
namespace csoap {
|
namespace csoap {
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#include "csoap/http_message.h"
|
||||||
|
|
||||||
|
namespace csoap {
|
||||||
|
|
||||||
|
void HttpMessage::SetHeader(const std::string& name, const std::string& value) {
|
||||||
|
for (HttpHeader& h : headers_) {
|
||||||
|
if (h.name == name) { // TODO: Ignore case?
|
||||||
|
h.value = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
headers_.push_back({ name, value });
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace csoap
|
||||||
+28
-19
@@ -16,31 +16,36 @@ public:
|
|||||||
// Base class for HTTP request and response messages.
|
// Base class for HTTP request and response messages.
|
||||||
class HttpMessage {
|
class HttpMessage {
|
||||||
public:
|
public:
|
||||||
void set_version(HttpVersion version) {
|
const std::string& start_line() const {
|
||||||
version_ = version;
|
return start_line_;
|
||||||
|
}
|
||||||
|
void set_start_line(const std::string& start_line) {
|
||||||
|
start_line_ = start_line;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t content_length() const {
|
size_t content_length() const {
|
||||||
return content_length_;
|
return content_length_;
|
||||||
}
|
}
|
||||||
void set_content_length(size_t length) {
|
|
||||||
content_length_ = length;
|
|
||||||
}
|
|
||||||
|
|
||||||
// E.g., "text/xml; charset=utf-8"
|
|
||||||
void set_content_type(const std::string& content_type) {
|
|
||||||
content_type_ = content_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddHeader(const std::string& name, const std::string& value) {
|
|
||||||
headers_.push_back({ name, value });
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& content() const {
|
const std::string& content() const {
|
||||||
return content_;
|
return content_;
|
||||||
}
|
}
|
||||||
void set_content(const std::string& content) {
|
|
||||||
content_ = content;
|
void SetHeader(const std::string& name, const std::string& value);
|
||||||
|
|
||||||
|
// E.g., "text/xml; charset=utf-8"
|
||||||
|
void SetContentType(const std::string& content_type) {
|
||||||
|
SetHeader(kContentType, content_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetContentLength(size_t content_length) {
|
||||||
|
content_length_ = content_length;
|
||||||
|
SetHeader(kContentLength, std::to_string(content_length));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use move semantics to avoid copy.
|
||||||
|
void set_content(std::string&& content) {
|
||||||
|
content_ = std::move(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppendContent(const char* data, size_t count) {
|
void AppendContent(const char* data, size_t count) {
|
||||||
@@ -52,19 +57,23 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool IsContentFull() const {
|
bool IsContentFull() const {
|
||||||
assert(content_length_ != kInvalidLength);
|
assert(IsContentLengthValid());
|
||||||
return content_.length() >= content_length_;
|
return content_.length() >= content_length_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsContentLengthValid() const {
|
||||||
|
return content_length_ != kInvalidLength;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
HttpMessage() {
|
HttpMessage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
HttpVersion version_ = kHttpV11;
|
// Start line with trailing "\r\n".
|
||||||
|
std::string start_line_;
|
||||||
|
|
||||||
size_t content_length_ = kInvalidLength;
|
size_t content_length_ = kInvalidLength;
|
||||||
std::string content_type_;
|
|
||||||
|
|
||||||
std::vector<HttpHeader> headers_;
|
std::vector<HttpHeader> headers_;
|
||||||
|
|
||||||
|
|||||||
@@ -14,10 +14,6 @@ HttpParser::HttpParser(HttpMessage* message)
|
|||||||
, finished_(false) {
|
, finished_(false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpParser::Reset() {
|
|
||||||
// TODO: Reset parsing state.
|
|
||||||
}
|
|
||||||
|
|
||||||
Error HttpParser::Parse(const char* data, size_t len) {
|
Error HttpParser::Parse(const char* data, size_t len) {
|
||||||
if (header_parsed_) {
|
if (header_parsed_) {
|
||||||
// Add the data to the content.
|
// Add the data to the content.
|
||||||
@@ -35,7 +31,7 @@ Error HttpParser::Parse(const char* data, size_t len) {
|
|||||||
size_t off = 0;
|
size_t off = 0;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
size_t pos = pending_data_.find(kCRLF, off);
|
size_t pos = pending_data_.find("\r\n", off);
|
||||||
if (pos == std::string::npos) {
|
if (pos == std::string::npos) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -57,8 +53,7 @@ Error HttpParser::Parse(const char* data, size_t len) {
|
|||||||
} else {
|
} else {
|
||||||
// Currently, only Content-Length is important to us.
|
// Currently, only Content-Length is important to us.
|
||||||
// Other fields are ignored.
|
// Other fields are ignored.
|
||||||
if (message_->content_length() == kInvalidLength) {
|
if (!message_->IsContentLengthValid()) {
|
||||||
// Not parsed yet.
|
|
||||||
ParseContentLength(line);
|
ParseContentLength(line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -69,7 +64,7 @@ Error HttpParser::Parse(const char* data, size_t len) {
|
|||||||
if (header_parsed_) {
|
if (header_parsed_) {
|
||||||
// Headers just ended.
|
// Headers just ended.
|
||||||
|
|
||||||
if (message_->content_length() == kInvalidLength) {
|
if (!message_->IsContentLengthValid()) {
|
||||||
// No Content-Length?
|
// No Content-Length?
|
||||||
return kHttpContentLengthError;
|
return kHttpContentLengthError;
|
||||||
}
|
}
|
||||||
@@ -96,7 +91,7 @@ void HttpParser::ParseContentLength(const std::string& line) {
|
|||||||
|
|
||||||
std::string name = line.substr(0, pos);
|
std::string name = line.substr(0, pos);
|
||||||
|
|
||||||
if (boost::iequals(name, kContentLengthName)) {
|
if (boost::iequals(name, kContentLength)) {
|
||||||
++pos; // Skip ':'.
|
++pos; // Skip ':'.
|
||||||
while (line[pos] == ' ') { // Skip spaces.
|
while (line[pos] == ' ') { // Skip spaces.
|
||||||
++pos;
|
++pos;
|
||||||
@@ -105,7 +100,7 @@ void HttpParser::ParseContentLength(const std::string& line) {
|
|||||||
std::string value = line.substr(pos);
|
std::string value = line.substr(pos);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
message_->set_content_length(boost::lexical_cast<size_t>(value));
|
message_->SetContentLength(boost::lexical_cast<size_t>(value));
|
||||||
} catch (boost::bad_lexical_cast&) {
|
} catch (boost::bad_lexical_cast&) {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
#define CSOAP_HTTP_PARSER_H_
|
#define CSOAP_HTTP_PARSER_H_
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "csoap/common.h"
|
#include "csoap/common.h"
|
||||||
|
|
||||||
namespace csoap {
|
namespace csoap {
|
||||||
@@ -18,9 +17,6 @@ public:
|
|||||||
return finished_;
|
return finished_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset parsing state.
|
|
||||||
void Reset();
|
|
||||||
|
|
||||||
Error Parse(const char* data, size_t len);
|
Error Parse(const char* data, size_t len);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
+45
-42
@@ -4,63 +4,66 @@
|
|||||||
|
|
||||||
namespace csoap {
|
namespace csoap {
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, const HttpRequest& request) {
|
std::ostream& operator<<(std::ostream& os, const HttpRequest& request) {
|
||||||
return os << request.GetHeaders() << request.content();
|
os << request.start_line();
|
||||||
|
|
||||||
|
for (const HttpHeader& h : request.headers_) {
|
||||||
|
os << h.name << ": " << h.value << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
os << std::endl;
|
||||||
|
|
||||||
|
os << request.content() << std::endl;
|
||||||
|
|
||||||
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
void HttpRequest::SetURL(const std::string& url) {
|
||||||
|
url_ = url;
|
||||||
|
|
||||||
std::string HttpRequest::GetHeaders() const {
|
start_line_ = "POST ";
|
||||||
std::string headers;
|
start_line_ += url_;
|
||||||
|
start_line_ += " HTTP/1.1\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
// Start line
|
void HttpRequest::SetHost(const std::string& host, const std::string& port) {
|
||||||
|
host_ = host;
|
||||||
|
port_ = port;
|
||||||
|
|
||||||
headers += "POST ";
|
if (port.empty()) {
|
||||||
headers += url_;
|
SetHeader(kHost, host);
|
||||||
headers += " ";
|
|
||||||
|
|
||||||
if (version_ == kHttpV10) {
|
|
||||||
headers += "HTTP/1.0";
|
|
||||||
} else {
|
} else {
|
||||||
headers += "HTTP/1.1";
|
SetHeader(kHost, host + ":" + port);
|
||||||
}
|
}
|
||||||
headers += kCRLF;
|
}
|
||||||
|
|
||||||
// Header fields
|
namespace misc_strings {
|
||||||
|
|
||||||
headers += kContentTypeName;
|
const char NAME_VALUE_SEPARATOR[] = { ':', ' ' };
|
||||||
headers += ": ";
|
const char CRLF[] = { '\r', '\n' };
|
||||||
|
|
||||||
if (!content_type_.empty()) {
|
} // misc_strings
|
||||||
headers += content_type_;
|
|
||||||
} else {
|
// ATTENTION: The buffers don't hold the memory!
|
||||||
headers += kTextXmlUtf8;
|
std::vector<boost::asio::const_buffer> HttpRequest::ToBuffers() const {
|
||||||
|
assert(IsContentLengthValid());
|
||||||
|
|
||||||
|
std::vector<boost::asio::const_buffer> buffers;
|
||||||
|
|
||||||
|
buffers.push_back(boost::asio::buffer(start_line_));
|
||||||
|
|
||||||
|
for (const HttpHeader& h : headers_) {
|
||||||
|
buffers.push_back(boost::asio::buffer(h.name));
|
||||||
|
buffers.push_back(boost::asio::buffer(misc_strings::NAME_VALUE_SEPARATOR));
|
||||||
|
buffers.push_back(boost::asio::buffer(h.value));
|
||||||
|
buffers.push_back(boost::asio::buffer(misc_strings::CRLF));
|
||||||
}
|
}
|
||||||
|
|
||||||
headers += kCRLF;
|
buffers.push_back(boost::asio::buffer(misc_strings::CRLF));
|
||||||
|
|
||||||
headers += kContentLengthName;
|
buffers.push_back(boost::asio::buffer(content_));
|
||||||
headers += ": ";
|
|
||||||
headers += std::to_string(content_length_);
|
|
||||||
headers += kCRLF;
|
|
||||||
|
|
||||||
headers += "SOAPAction: ";
|
return buffers;
|
||||||
headers += soap_action_;
|
|
||||||
headers += kCRLF;
|
|
||||||
|
|
||||||
headers += "Host: ";
|
|
||||||
headers += host_;
|
|
||||||
if (!port_.empty()) {
|
|
||||||
headers += ":";
|
|
||||||
headers += port_;
|
|
||||||
}
|
|
||||||
headers += kCRLF;
|
|
||||||
|
|
||||||
headers += kCRLF; // End of Headers.
|
|
||||||
|
|
||||||
return headers;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace csoap
|
} // namespace csoap
|
||||||
|
|||||||
+13
-31
@@ -2,21 +2,15 @@
|
|||||||
#define CSOAP_HTTP_REQUEST_H_
|
#define CSOAP_HTTP_REQUEST_H_
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include "boost/asio/buffer.hpp" // for const_buffer
|
||||||
|
|
||||||
#include "csoap/common.h"
|
|
||||||
#include "csoap/http_message.h"
|
#include "csoap/http_message.h"
|
||||||
|
|
||||||
namespace csoap {
|
namespace csoap {
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
class HttpRequest;
|
class HttpRequest;
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, const HttpRequest& request);
|
std::ostream& operator<<(std::ostream& os, const HttpRequest& request);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// HTTP request.
|
// HTTP request.
|
||||||
// NOTE:
|
// NOTE:
|
||||||
// - Only POST method is supported.
|
// - Only POST method is supported.
|
||||||
@@ -27,18 +21,6 @@ class HttpRequest : public HttpMessage {
|
|||||||
const HttpRequest& request);
|
const HttpRequest& request);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HttpRequest() {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the URL for the HTTP request start line.
|
|
||||||
// Either a complete URL or the path component it is acceptable.
|
|
||||||
// E.g., both of the following URLs are OK:
|
|
||||||
// - http://ws1.parasoft.com/glue/calculator
|
|
||||||
// - /glue/calculator
|
|
||||||
void set_url(const std::string& url) {
|
|
||||||
url_ = url;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& host() const {
|
const std::string& host() const {
|
||||||
return host_;
|
return host_;
|
||||||
}
|
}
|
||||||
@@ -47,19 +29,21 @@ public:
|
|||||||
return port_;
|
return port_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the URL for the HTTP request start line.
|
||||||
|
// Either a complete URL or the path component it is acceptable.
|
||||||
|
// E.g., both of the following URLs are OK:
|
||||||
|
// - http://ws1.parasoft.com/glue/calculator
|
||||||
|
// - /glue/calculator
|
||||||
|
void SetURL(const std::string& url);
|
||||||
|
|
||||||
// \param host Descriptive host name or numeric IP address.
|
// \param host Descriptive host name or numeric IP address.
|
||||||
// \param port Numeric port number, "80" will be used if it's empty.
|
// \param port Numeric port number, "80" will be used if it's empty.
|
||||||
void set_host(const std::string& host, const std::string& port) {
|
void SetHost(const std::string& host, const std::string& port);
|
||||||
host_ = host;
|
|
||||||
port_ = port;
|
|
||||||
}
|
|
||||||
|
|
||||||
// SOAP specific.
|
// Convert the response into a vector of buffers. The buffers do not own the
|
||||||
void set_soap_action(const std::string& soap_action) {
|
// underlying memory blocks, therefore the response object must remain valid
|
||||||
soap_action_ = soap_action;
|
// and not be changed until the write operation has completed.
|
||||||
}
|
std::vector<boost::asio::const_buffer> ToBuffers() const;
|
||||||
|
|
||||||
std::string GetHeaders() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Request URL.
|
// Request URL.
|
||||||
@@ -69,8 +53,6 @@ private:
|
|||||||
|
|
||||||
std::string host_;
|
std::string host_;
|
||||||
std::string port_;
|
std::string port_;
|
||||||
|
|
||||||
std::string soap_action_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace csoap
|
} // namespace csoap
|
||||||
|
|||||||
@@ -57,20 +57,18 @@ bool HttpRequestHandler::RegisterService(SoapServicePtr soap_service) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpRequestHandler::HandleRequest(const HttpRequest& request,
|
void HttpRequestHandler::HandleRequest(const HttpRequest& http_request,
|
||||||
HttpResponse& response) {
|
HttpResponse* http_response) {
|
||||||
// Parse the SOAP request XML.
|
// Parse the SOAP request XML.
|
||||||
SoapRequest soap_request;
|
SoapRequest soap_request;
|
||||||
if (!soap_request.FromXml(request.content())) {
|
if (!soap_request.FromXml(http_request.content())) {
|
||||||
// TODO: Bad request
|
http_response->set_status(HttpStatus::BAD_REQUEST);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST
|
|
||||||
|
|
||||||
SoapResponse soap_response;
|
SoapResponse soap_response;
|
||||||
|
|
||||||
// Get service by URL.
|
// TODO: Get service by URL.
|
||||||
|
|
||||||
for (SoapServicePtr& service : soap_services_) {
|
for (SoapServicePtr& service : soap_services_) {
|
||||||
service->Handle(soap_request, &soap_response);
|
service->Handle(soap_request, &soap_response);
|
||||||
@@ -79,10 +77,10 @@ void HttpRequestHandler::HandleRequest(const HttpRequest& request,
|
|||||||
std::string content;
|
std::string content;
|
||||||
soap_response.ToXml(&content);
|
soap_response.ToXml(&content);
|
||||||
|
|
||||||
response.set_status(HttpStatus::OK);
|
http_response->set_status(HttpStatus::OK);
|
||||||
response.AddHeader(kContentTypeName, kTextXmlUtf8);
|
http_response->SetContentType(kTextXmlUtf8);
|
||||||
response.AddHeader(kContentLengthName, std::to_string(content.length()));
|
http_response->SetContentLength(content.length());
|
||||||
response.set_content(content);
|
http_response->set_content(std::move(content));
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// Decode URL to path.
|
// Decode URL to path.
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
#ifndef CSOAP_HTTP_REQUEST_HANDLER_H_
|
#ifndef CSOAP_HTTP_REQUEST_HANDLER_H_
|
||||||
#define CSOAP_HTTP_REQUEST_HANDLER_H_
|
#define CSOAP_HTTP_REQUEST_HANDLER_H_
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "csoap/soap_service.h"
|
#include "csoap/soap_service.h"
|
||||||
|
|
||||||
namespace csoap {
|
namespace csoap {
|
||||||
@@ -21,8 +19,9 @@ public:
|
|||||||
|
|
||||||
bool RegisterService(SoapServicePtr soap_service);
|
bool RegisterService(SoapServicePtr soap_service);
|
||||||
|
|
||||||
// Handle a request and produce a reply.
|
// Handle a request and produce a response.
|
||||||
void HandleRequest(const HttpRequest& request, HttpResponse& response);
|
void HandleRequest(const HttpRequest& http_request,
|
||||||
|
HttpResponse* http_response);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<SoapServicePtr> soap_services_;
|
std::vector<SoapServicePtr> soap_services_;
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ Error HttpRequestParser::ParseStartLine(const std::string& line) {
|
|||||||
return kHttpStartLineError;
|
return kHttpStartLineError;
|
||||||
}
|
}
|
||||||
|
|
||||||
request_->set_url(strs[1]);
|
request_->SetURL(strs[1]);
|
||||||
|
|
||||||
// TODO: strs[2];
|
// TODO: strs[2];
|
||||||
|
|
||||||
|
|||||||
+14
-42
@@ -8,8 +8,13 @@ namespace csoap {
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, const HttpResponse& response) {
|
std::ostream& operator<<(std::ostream& os, const HttpResponse& response) {
|
||||||
// TODO
|
os << response.start_line();
|
||||||
os << response.status() << std::endl;
|
|
||||||
|
for (const HttpHeader& h : response.headers_) {
|
||||||
|
os << h.name << ": " << h.value << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
os << std::endl;
|
||||||
|
|
||||||
// Pretty print the SOAP response XML.
|
// Pretty print the SOAP response XML.
|
||||||
if (!xml::PrettyPrintXml(os, response.content())) {
|
if (!xml::PrettyPrintXml(os, response.content())) {
|
||||||
@@ -66,9 +71,10 @@ const char CRLF[] = { '\r', '\n' };
|
|||||||
std::vector<boost::asio::const_buffer> HttpResponse::ToBuffers() const {
|
std::vector<boost::asio::const_buffer> HttpResponse::ToBuffers() const {
|
||||||
std::vector<boost::asio::const_buffer> buffers;
|
std::vector<boost::asio::const_buffer> buffers;
|
||||||
|
|
||||||
|
// Status line
|
||||||
buffers.push_back(status_strings::ToBuffer(status_));
|
buffers.push_back(status_strings::ToBuffer(status_));
|
||||||
|
|
||||||
// Header fields
|
// Header fields (optional)
|
||||||
for (const HttpHeader& h : headers_) {
|
for (const HttpHeader& h : headers_) {
|
||||||
buffers.push_back(boost::asio::buffer(h.name));
|
buffers.push_back(boost::asio::buffer(h.name));
|
||||||
buffers.push_back(boost::asio::buffer(misc_strings::NAME_VALUE_SEPARATOR));
|
buffers.push_back(boost::asio::buffer(misc_strings::NAME_VALUE_SEPARATOR));
|
||||||
@@ -77,56 +83,22 @@ std::vector<boost::asio::const_buffer> HttpResponse::ToBuffers() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buffers.push_back(boost::asio::buffer(misc_strings::CRLF));
|
buffers.push_back(boost::asio::buffer(misc_strings::CRLF));
|
||||||
|
|
||||||
|
// Content (optional)
|
||||||
|
if (IsContentLengthValid()) {
|
||||||
buffers.push_back(boost::asio::buffer(content_));
|
buffers.push_back(boost::asio::buffer(content_));
|
||||||
|
}
|
||||||
|
|
||||||
return buffers;
|
return buffers;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Move to SoapResponse
|
|
||||||
static void CreateSoapFaultResponse(HttpStatus status,
|
|
||||||
std::string* xml_string) {
|
|
||||||
Namespace soapenv_ns{
|
|
||||||
"soap",
|
|
||||||
"http://schemas.xmlsoap.org/soap/envelope/"
|
|
||||||
};
|
|
||||||
|
|
||||||
pugi::xml_document xdoc;
|
|
||||||
pugi::xml_node xroot = xml::AddChild(xdoc, soapenv_ns.name, "Envelope");
|
|
||||||
|
|
||||||
xml::AddNSAttr(xroot, soapenv_ns.name, soapenv_ns.url);
|
|
||||||
|
|
||||||
// FIXME: Body
|
|
||||||
// See https://www.w3schools.com/XML/xml_soap.asp
|
|
||||||
|
|
||||||
pugi::xml_node xfault = xml::AddChild(xroot, soapenv_ns.name, "Fault");
|
|
||||||
|
|
||||||
pugi::xml_node xfaultcode = xfault.append_child("faultcode");
|
|
||||||
xfaultcode.text().set(std::to_string(HttpStatus::BAD_REQUEST).c_str()); // TODO
|
|
||||||
|
|
||||||
pugi::xml_node xfaultstring = xfault.append_child("faultstring");
|
|
||||||
xfaultstring.text().set("Bad Request"); // TODO
|
|
||||||
|
|
||||||
// TODO: faultactor
|
|
||||||
|
|
||||||
xml::XmlStrRefWriter writer(xml_string);
|
|
||||||
xdoc.save(writer, "\t", pugi::format_default, pugi::encoding_utf8);
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpResponse HttpResponse::Fault(HttpStatus status) {
|
HttpResponse HttpResponse::Fault(HttpStatus status) {
|
||||||
assert(status != HttpStatus::OK);
|
assert(status != HttpStatus::OK);
|
||||||
|
|
||||||
HttpResponse response;
|
HttpResponse response;
|
||||||
|
|
||||||
std::string content;
|
|
||||||
CreateSoapFaultResponse(status, &content);
|
|
||||||
|
|
||||||
response.set_content(content);
|
|
||||||
response.set_content_length(content.length());
|
|
||||||
response.set_content_type("text/xml");
|
|
||||||
|
|
||||||
response.set_status(status);
|
response.set_status(status);
|
||||||
|
|
||||||
return response; // TODO: Output parameter?
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace csoap
|
} // namespace csoap
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ HttpResponseParser::HttpResponseParser(HttpResponse* response)
|
|||||||
|
|
||||||
// TODO: Use split.
|
// TODO: Use split.
|
||||||
Error HttpResponseParser::ParseStartLine(const std::string& line) {
|
Error HttpResponseParser::ParseStartLine(const std::string& line) {
|
||||||
|
response_->set_start_line(line + "\r\n");
|
||||||
|
|
||||||
size_t off = 0;
|
size_t off = 0;
|
||||||
|
|
||||||
size_t pos = line.find(' ');
|
size_t pos = line.find(' ');
|
||||||
@@ -37,7 +39,6 @@ Error HttpResponseParser::ParseStartLine(const std::string& line) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
off = pos + 1; // Skip space.
|
off = pos + 1; // Skip space.
|
||||||
//response_->set_reason(line.substr(off));
|
|
||||||
|
|
||||||
if (response_->status() != HttpStatus::OK) {
|
if (response_->status() != HttpStatus::OK) {
|
||||||
return kHttpStatusError;
|
return kHttpStatusError;
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
#include "csoap/soap_client.h"
|
#include "csoap/soap_client.h"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include "boost/lexical_cast.hpp"
|
|
||||||
|
|
||||||
#include "csoap/http_client.h"
|
#include "csoap/http_client.h"
|
||||||
#include "csoap/http_request.h"
|
#include "csoap/http_request.h"
|
||||||
@@ -33,17 +30,17 @@ Error SoapClient::Call(const std::string& operation,
|
|||||||
soap_request.AddParameter(parameters[i]);
|
soap_request.AddParameter(parameters[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string http_request_body;
|
std::string http_content;
|
||||||
soap_request.ToXml(&http_request_body);
|
soap_request.ToXml(&http_content);
|
||||||
|
|
||||||
HttpRequest http_request;
|
HttpRequest http_request;
|
||||||
|
|
||||||
http_request.set_version(kHttpV11); // TODO
|
http_request.SetURL(url_);
|
||||||
http_request.set_url(url_);
|
http_request.SetContentType(kTextXmlUtf8);
|
||||||
http_request.set_content_length(http_request_body.size());
|
http_request.SetContentLength(http_content.size());
|
||||||
http_request.set_content(http_request_body); // TODO: move
|
http_request.SetHost(host_, port_);
|
||||||
http_request.set_host(host_, port_);
|
http_request.SetHeader(kSOAPAction, operation);
|
||||||
http_request.set_soap_action(operation);
|
http_request.set_content(std::move(http_content));
|
||||||
|
|
||||||
HttpResponse http_response;
|
HttpResponse http_response;
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "pugixml/pugixml.hpp"
|
#include "pugixml/pugixml.hpp"
|
||||||
|
|
||||||
#include "csoap/common.h"
|
#include "csoap/common.h"
|
||||||
|
|
||||||
namespace csoap {
|
namespace csoap {
|
||||||
@@ -12,27 +11,27 @@ namespace csoap {
|
|||||||
class SoapMessage {
|
class SoapMessage {
|
||||||
public:
|
public:
|
||||||
// E.g., set as kSoapEnvNamespace.
|
// E.g., set as kSoapEnvNamespace.
|
||||||
CLIENT_API void set_soapenv_ns(const Namespace& soapenv_ns) {
|
void set_soapenv_ns(const Namespace& soapenv_ns) {
|
||||||
soapenv_ns_ = soapenv_ns;
|
soapenv_ns_ = soapenv_ns;
|
||||||
}
|
}
|
||||||
|
|
||||||
CLIENT_API void set_service_ns(const Namespace& service_ns) {
|
void set_service_ns(const Namespace& service_ns) {
|
||||||
service_ns_ = service_ns;
|
service_ns_ = service_ns;
|
||||||
}
|
}
|
||||||
|
|
||||||
SERVER_API const std::string& operation() const {
|
const std::string& operation() const {
|
||||||
return operation_;
|
return operation_;
|
||||||
}
|
}
|
||||||
|
|
||||||
CLIENT_API void set_operation(const std::string& operation) {
|
void set_operation(const std::string& operation) {
|
||||||
operation_ = operation;
|
operation_ = operation;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert to SOAP request XML.
|
// Convert to SOAP request XML.
|
||||||
CLIENT_API void ToXml(std::string* xml_string);
|
void ToXml(std::string* xml_string);
|
||||||
|
|
||||||
// Parse from SOAP request XML.
|
// Parse from SOAP request XML.
|
||||||
SERVER_API bool FromXml(const std::string& xml_string);
|
bool FromXml(const std::string& xml_string);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SoapMessage() {
|
SoapMessage() {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
#define CSOAP_SOAP_REQUEST_H_
|
#define CSOAP_SOAP_REQUEST_H_
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "csoap/soap_message.h"
|
#include "csoap/soap_message.h"
|
||||||
|
|
||||||
namespace csoap {
|
namespace csoap {
|
||||||
@@ -12,11 +11,11 @@ namespace csoap {
|
|||||||
// request body.
|
// request body.
|
||||||
class SoapRequest : public SoapMessage {
|
class SoapRequest : public SoapMessage {
|
||||||
public:
|
public:
|
||||||
CLIENT_API void AddParameter(const std::string& key, const std::string& value);
|
void AddParameter(const std::string& key, const std::string& value);
|
||||||
CLIENT_API void AddParameter(const Parameter& parameter);
|
void AddParameter(const Parameter& parameter);
|
||||||
|
|
||||||
// Get parameter value by key.
|
// Get parameter value by key.
|
||||||
SERVER_API std::string GetParameter(const std::string& key) const;
|
std::string GetParameter(const std::string& key) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void ToXmlBody(pugi::xml_node xbody) override;
|
void ToXmlBody(pugi::xml_node xbody) override;
|
||||||
|
|||||||
@@ -11,15 +11,15 @@ public:
|
|||||||
// Could be "Price" for an operation/method like "GetXyzPrice".
|
// Could be "Price" for an operation/method like "GetXyzPrice".
|
||||||
// Really depend on the service.
|
// Really depend on the service.
|
||||||
// Most services use a general name "Result".
|
// Most services use a general name "Result".
|
||||||
CLIENT_API void set_result_name(const std::string& result_name) {
|
void set_result_name(const std::string& result_name) {
|
||||||
result_name_ = result_name;
|
result_name_ = result_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
CLIENT_API const std::string& result() const {
|
const std::string& result() const {
|
||||||
return result_;
|
return result_;
|
||||||
}
|
}
|
||||||
|
|
||||||
SERVER_API void set_result(const std::string& result) {
|
void set_result(const std::string& result) {
|
||||||
result_ = result;
|
result_ = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,7 +29,9 @@ protected:
|
|||||||
bool FromXmlBody(pugi::xml_node xbody) override;
|
bool FromXmlBody(pugi::xml_node xbody) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// TODO: Support multiple results.
|
// NOTE:
|
||||||
|
// Multiple results might be necessary. But for most cases, single result
|
||||||
|
// should be enough, because an API normally returns only one value.
|
||||||
|
|
||||||
// Result XML node name.
|
// Result XML node name.
|
||||||
// Used to parse the response XML from client side.
|
// Used to parse the response XML from client side.
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
#include "csoap/soap_service.h"
|
|
||||||
@@ -19,7 +19,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle SOAP request, output the response.
|
// Handle SOAP request, output the response.
|
||||||
virtual bool Handle(const SoapRequest& request,
|
virtual bool Handle(const SoapRequest& soap_request,
|
||||||
SoapResponse* soap_response) = 0;
|
SoapResponse* soap_response) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
+1
-1
@@ -65,7 +65,7 @@ std::string GetNSAttr(pugi::xml_node& xnode,
|
|||||||
// ...
|
// ...
|
||||||
// std::string xml_string;
|
// std::string xml_string;
|
||||||
// XmlStrRefWriter writer(&xml_string);
|
// XmlStrRefWriter writer(&xml_string);
|
||||||
// xdoc.print(writer, " ", pugi::format_default, pugi::encoding_utf8);
|
// xdoc.save(writer, "\t", pugi::format_default, pugi::encoding_utf8);
|
||||||
class XmlStrRefWriter : public pugi::xml_writer {
|
class XmlStrRefWriter : public pugi::xml_writer {
|
||||||
public:
|
public:
|
||||||
explicit XmlStrRefWriter(std::string* result)
|
explicit XmlStrRefWriter(std::string* result)
|
||||||
|
|||||||
@@ -2,28 +2,28 @@
|
|||||||
#include "csoap/http_server.h"
|
#include "csoap/http_server.h"
|
||||||
#include "calculator_service.h"
|
#include "calculator_service.h"
|
||||||
|
|
||||||
// TODO: Why need an address for a server?
|
|
||||||
static void PrintHelp(const char* argv0) {
|
static void PrintHelp(const char* argv0) {
|
||||||
std::cout << "Usage: " << argv0 << " <address> <port>" << std::endl;
|
std::cout << "Usage: " << argv0 << " <port>" << std::endl;
|
||||||
std::cout << " For IPv4, try:" << std::endl;
|
std::cout << " E.g.," << std::endl;
|
||||||
std::cout << " " << argv0 << " 0.0.0.0 80" << std::endl;
|
std::cout << " " << argv0 << " 8080" << std::endl;
|
||||||
std::cout << " For IPv6, try:" << std::endl;
|
|
||||||
std::cout << " " << argv0 << " 0::0 80" << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
if (argc != 3) {
|
if (argc != 2) {
|
||||||
PrintHelp(argv[0]);
|
PrintHelp(argv[0]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* host = "0.0.0.0"; // TODO
|
||||||
|
|
||||||
try {
|
try {
|
||||||
csoap::HttpServer server(argv[1], argv[2]);
|
csoap::HttpServer server(host, argv[1]);
|
||||||
|
|
||||||
csoap::SoapServicePtr service(new CalculatorService);
|
csoap::SoapServicePtr service(new CalculatorService);
|
||||||
server.RegisterService(service);
|
server.RegisterService(service);
|
||||||
|
|
||||||
server.Run();
|
server.Run();
|
||||||
|
|
||||||
} catch (std::exception& e) {
|
} catch (std::exception& e) {
|
||||||
std::cerr << "exception: " << e.what() << "\n";
|
std::cerr << "exception: " << e.what() << "\n";
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user