Remove http version; refine sending request and error handling.

master
Adam Gu 8 years ago
parent ab4555d58d
commit f43b1d0c36

@ -15,6 +15,7 @@ if(MSVC)
add_definitions(-D_WIN32_WINNT=0x0601)
endif()
# Boost version: 1.66+
set(Boost_USE_STATIC_LIBS ON)
find_package(Boost)
if(Boost_FOUND)

@ -2,6 +2,9 @@ if(UNIX)
add_definitions(-D_GLIBCXX_USE_WCHAR_T -std=c++11)
endif()
# Don't use any deprecated definitions (e.g., io_service).
add_definitions(-DBOOST_ASIO_NO_DEPRECATED)
file(GLOB SRCS *.cc *.h)
add_library(csoap ${SRCS})

@ -7,8 +7,10 @@ namespace csoap {
// NOTE:
// Field names are case-insensitive.
// See: https://stackoverflow.com/a/5259004
const std::string kContentTypeName = "Content-Type";
const std::string kContentLengthName = "Content-Length";
const std::string kContentType = "Content-Type";
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
// Content-type header must be chosen as "application/soap+xml" [RFC 3902].

@ -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.
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 kContentTypeName;
extern const std::string kContentLengthName;
extern const std::string kContentType;
extern const std::string kContentLength;
extern const std::string kSOAPAction;
extern const std::string kHost;
extern const std::string kTextXmlUtf8;
const std::size_t kInvalidLength = std::string::npos;
////////////////////////////////////////////////////////////////////////////////
// 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.
// NOTE: Only support the listed status codes.
enum HttpStatus {
@ -80,12 +62,6 @@ enum HttpStatus {
SERVICE_UNAVAILABLE = 503,
};
enum HeaderField {
kHeaderContentType,
kHeaderContentLength,
kHeaderHost,
};
////////////////////////////////////////////////////////////////////////////////
// XML namespace name/url pair.

@ -56,7 +56,6 @@ void Connection::HandleRead(boost::system::error_code ec,
// Bad request.
response_ = HttpResponse::Fault(HttpStatus::BAD_REQUEST);
DoWrite();
return;
}
@ -67,7 +66,8 @@ void Connection::HandleRead(boost::system::error_code ec,
}
// Handle request.
request_handler_.HandleRequest(request_, response_);
// TODO: Time consuming
request_handler_.HandleRequest(request_, &response_);
// Send back the response.
DoWrite();

@ -57,7 +57,7 @@ private:
HttpRequestHandler& request_handler_;
// Buffer for incoming data.
std::array<char, 8192> buffer_;
std::array<char, BUF_SIZE> buffer_;
// The incoming request.
HttpRequest request_;

@ -4,10 +4,6 @@
#include <iostream>
#endif
#include "boost/algorithm/string.hpp"
#include "boost/bind.hpp"
#include "boost/lexical_cast.hpp"
#if 0
#include "boost/asio.hpp"
#else
@ -20,7 +16,10 @@
#include "csoap/http_response_parser.h"
#include "csoap/http_request.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 {
@ -71,10 +70,9 @@ Error HttpClient::SendRequest(const HttpRequest& request,
port = "80";
}
// TODO: IPv4 or both IPv4 and IPv6
boost::system::error_code ec;
tcp::resolver::results_type endpoints =
resolver.resolve(/*tcp::v4(), */request.host(), port, ec);
resolver.resolve(tcp::v4(), request.host(), port, ec);
if (ec) {
return kHostResolveError;
}
@ -88,23 +86,20 @@ Error HttpClient::SendRequest(const HttpRequest& 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
std::cout << request << std::endl;
std::cout << "# REQUEST" << std::endl << request << std::endl;
#endif
try {
boost::asio::write(socket, buffers);
boost::asio::write(socket, request.ToBuffers());
} catch (boost::system::system_error&) {
return kSocketWriteError;
}
#if CSOAP_ENABLE_OUTPUT
std::cout << "# RESPONSE" << std::endl;
#endif
// Read and parse HTTP response.
HttpResponseParser parser(response);
@ -139,10 +134,9 @@ Error HttpClient::SendRequest(const HttpRequest& request,
}
#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 << "# RESPONSE (PARSED)" << std::endl;
std::cout << *response << std::endl;
#endif
return kNoError;

@ -2,12 +2,7 @@
#define CSOAP_HTTP_CLIENT_H_
#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 "csoap/common.h"
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

@ -16,31 +16,36 @@ public:
// Base class for HTTP request and response messages.
class HttpMessage {
public:
void set_version(HttpVersion version) {
version_ = version;
const std::string& start_line() const {
return start_line_;
}
void set_start_line(const std::string& start_line) {
start_line_ = start_line;
}
size_t content_length() const {
return content_length_;
}
void set_content_length(size_t length) {
content_length_ = length;
const std::string& content() const {
return content_;
}
void SetHeader(const std::string& name, const std::string& value);
// E.g., "text/xml; charset=utf-8"
void set_content_type(const std::string& content_type) {
content_type_ = content_type;
void SetContentType(const std::string& content_type) {
SetHeader(kContentType, content_type);
}
void AddHeader(const std::string& name, const std::string& value) {
headers_.push_back({ name, value });
void SetContentLength(size_t content_length) {
content_length_ = content_length;
SetHeader(kContentLength, std::to_string(content_length));
}
const std::string& content() const {
return content_;
}
void set_content(const std::string& content) {
content_ = content;
// Use move semantics to avoid copy.
void set_content(std::string&& content) {
content_ = std::move(content);
}
void AppendContent(const char* data, size_t count) {
@ -52,19 +57,23 @@ public:
}
bool IsContentFull() const {
assert(content_length_ != kInvalidLength);
assert(IsContentLengthValid());
return content_.length() >= content_length_;
}
bool IsContentLengthValid() const {
return content_length_ != kInvalidLength;
}
protected:
HttpMessage() {
}
protected:
HttpVersion version_ = kHttpV11;
// Start line with trailing "\r\n".
std::string start_line_;
size_t content_length_ = kInvalidLength;
std::string content_type_;
std::vector<HttpHeader> headers_;

@ -8,14 +8,10 @@
namespace csoap {
HttpParser::HttpParser(HttpMessage* message)
: message_(message)
, start_line_parsed_(false)
, header_parsed_(false)
, finished_(false) {
}
void HttpParser::Reset() {
// TODO: Reset parsing state.
: message_(message)
, start_line_parsed_(false)
, header_parsed_(false)
, finished_(false) {
}
Error HttpParser::Parse(const char* data, size_t len) {
@ -35,13 +31,13 @@ Error HttpParser::Parse(const char* data, size_t len) {
size_t off = 0;
while (true) {
size_t pos = pending_data_.find(kCRLF, off);
size_t pos = pending_data_.find("\r\n", off);
if (pos == std::string::npos) {
break;
}
if (pos == off) { // End of headers.
off = pos + 2; // Skip CRLF.
if (pos == off) { // End of headers.
off = pos + 2; // Skip CRLF.
header_parsed_ = true;
break;
}
@ -57,8 +53,7 @@ Error HttpParser::Parse(const char* data, size_t len) {
} else {
// Currently, only Content-Length is important to us.
// Other fields are ignored.
if (message_->content_length() == kInvalidLength) {
// Not parsed yet.
if (!message_->IsContentLengthValid()) {
ParseContentLength(line);
}
}
@ -69,7 +64,7 @@ Error HttpParser::Parse(const char* data, size_t len) {
if (header_parsed_) {
// Headers just ended.
if (message_->content_length() == kInvalidLength) {
if (!message_->IsContentLengthValid()) {
// No Content-Length?
return kHttpContentLengthError;
}
@ -96,7 +91,7 @@ void HttpParser::ParseContentLength(const std::string& line) {
std::string name = line.substr(0, pos);
if (boost::iequals(name, kContentLengthName)) {
if (boost::iequals(name, kContentLength)) {
++pos; // Skip ':'.
while (line[pos] == ' ') { // Skip spaces.
++pos;
@ -105,7 +100,7 @@ void HttpParser::ParseContentLength(const std::string& line) {
std::string value = line.substr(pos);
try {
message_->set_content_length(boost::lexical_cast<size_t>(value));
message_->SetContentLength(boost::lexical_cast<size_t>(value));
} catch (boost::bad_lexical_cast&) {
// TODO
}

@ -2,7 +2,6 @@
#define CSOAP_HTTP_PARSER_H_
#include <string>
#include "csoap/common.h"
namespace csoap {
@ -18,9 +17,6 @@ public:
return finished_;
}
// Reset parsing state.
void Reset();
Error Parse(const char* data, size_t len);
protected:

@ -4,63 +4,66 @@
namespace csoap {
////////////////////////////////////////////////////////////////////////////////
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;
}
std::string HttpRequest::GetHeaders() const {
std::string headers;
os << std::endl;
// Start line
os << request.content() << std::endl;
headers += "POST ";
headers += url_;
headers += " ";
return os;
}
if (version_ == kHttpV10) {
headers += "HTTP/1.0";
} else {
headers += "HTTP/1.1";
}
headers += kCRLF;
void HttpRequest::SetURL(const std::string& url) {
url_ = url;
// Header fields
start_line_ = "POST ";
start_line_ += url_;
start_line_ += " HTTP/1.1\r\n";
}
headers += kContentTypeName;
headers += ": ";
void HttpRequest::SetHost(const std::string& host, const std::string& port) {
host_ = host;
port_ = port;
if (!content_type_.empty()) {
headers += content_type_;
if (port.empty()) {
SetHeader(kHost, host);
} else {
headers += kTextXmlUtf8;
SetHeader(kHost, host + ":" + port);
}
}
namespace misc_strings {
headers += kCRLF;
const char NAME_VALUE_SEPARATOR[] = { ':', ' ' };
const char CRLF[] = { '\r', '\n' };
headers += kContentLengthName;
headers += ": ";
headers += std::to_string(content_length_);
headers += kCRLF;
} // misc_strings
headers += "SOAPAction: ";
headers += soap_action_;
headers += kCRLF;
// ATTENTION: The buffers don't hold the memory!
std::vector<boost::asio::const_buffer> HttpRequest::ToBuffers() const {
assert(IsContentLengthValid());
headers += "Host: ";
headers += host_;
if (!port_.empty()) {
headers += ":";
headers += port_;
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;
headers += kCRLF; // End of Headers.
buffers.push_back(boost::asio::buffer(misc_strings::CRLF));
buffers.push_back(boost::asio::buffer(content_));
return headers;
return buffers;
}
} // namespace csoap

@ -2,21 +2,15 @@
#define CSOAP_HTTP_REQUEST_H_
#include <string>
#include <vector>
#include "csoap/common.h"
#include "boost/asio/buffer.hpp" // for const_buffer
#include "csoap/http_message.h"
namespace csoap {
////////////////////////////////////////////////////////////////////////////////
class HttpRequest;
std::ostream& operator<<(std::ostream& os, const HttpRequest& request);
////////////////////////////////////////////////////////////////////////////////
// HTTP request.
// NOTE:
// - Only POST method is supported.
@ -27,18 +21,6 @@ class HttpRequest : public HttpMessage {
const HttpRequest& request);
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 {
return host_;
}
@ -47,19 +29,21 @@ public:
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 port Numeric port number, "80" will be used if it's empty.
void set_host(const std::string& host, const std::string& port) {
host_ = host;
port_ = port;
}
void SetHost(const std::string& host, const std::string& port);
// SOAP specific.
void set_soap_action(const std::string& soap_action) {
soap_action_ = soap_action;
}
std::string GetHeaders() const;
// Convert the response into a vector of buffers. The buffers do not own the
// underlying memory blocks, therefore the response object must remain valid
// and not be changed until the write operation has completed.
std::vector<boost::asio::const_buffer> ToBuffers() const;
private:
// Request URL.
@ -69,8 +53,6 @@ private:
std::string host_;
std::string port_;
std::string soap_action_;
};
} // namespace csoap

@ -57,20 +57,18 @@ bool HttpRequestHandler::RegisterService(SoapServicePtr soap_service) {
return true;
}
void HttpRequestHandler::HandleRequest(const HttpRequest& request,
HttpResponse& response) {
void HttpRequestHandler::HandleRequest(const HttpRequest& http_request,
HttpResponse* http_response) {
// Parse the SOAP request XML.
SoapRequest soap_request;
if (!soap_request.FromXml(request.content())) {
// TODO: Bad request
if (!soap_request.FromXml(http_request.content())) {
http_response->set_status(HttpStatus::BAD_REQUEST);
return;
}
// TEST
SoapResponse soap_response;
// Get service by URL.
// TODO: Get service by URL.
for (SoapServicePtr& service : soap_services_) {
service->Handle(soap_request, &soap_response);
@ -79,10 +77,10 @@ void HttpRequestHandler::HandleRequest(const HttpRequest& request,
std::string content;
soap_response.ToXml(&content);
response.set_status(HttpStatus::OK);
response.AddHeader(kContentTypeName, kTextXmlUtf8);
response.AddHeader(kContentLengthName, std::to_string(content.length()));
response.set_content(content);
http_response->set_status(HttpStatus::OK);
http_response->SetContentType(kTextXmlUtf8);
http_response->SetContentLength(content.length());
http_response->set_content(std::move(content));
#if 0
// Decode URL to path.

@ -1,9 +1,7 @@
#ifndef CSOAP_HTTP_REQUEST_HANDLER_H_
#define CSOAP_HTTP_REQUEST_HANDLER_H_
#include <string>
#include <vector>
#include "csoap/soap_service.h"
namespace csoap {
@ -21,8 +19,9 @@ public:
bool RegisterService(SoapServicePtr soap_service);
// Handle a request and produce a reply.
void HandleRequest(const HttpRequest& request, HttpResponse& response);
// Handle a request and produce a response.
void HandleRequest(const HttpRequest& http_request,
HttpResponse* http_response);
private:
std::vector<SoapServicePtr> soap_services_;

@ -27,7 +27,7 @@ Error HttpRequestParser::ParseStartLine(const std::string& line) {
return kHttpStartLineError;
}
request_->set_url(strs[1]);
request_->SetURL(strs[1]);
// TODO: strs[2];

@ -8,8 +8,13 @@ namespace csoap {
////////////////////////////////////////////////////////////////////////////////
std::ostream& operator<<(std::ostream& os, const HttpResponse& response) {
// TODO
os << response.status() << std::endl;
os << response.start_line();
for (const HttpHeader& h : response.headers_) {
os << h.name << ": " << h.value << std::endl;
}
os << std::endl;
// Pretty print the SOAP response XML.
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> buffers;
// Status line
buffers.push_back(status_strings::ToBuffer(status_));
// Header fields
// Header fields (optional)
for (const HttpHeader& h : headers_) {
buffers.push_back(boost::asio::buffer(h.name));
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(content_));
// Content (optional)
if (IsContentLengthValid()) {
buffers.push_back(boost::asio::buffer(content_));
}
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) {
assert(status != HttpStatus::OK);
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);
return response; // TODO: Output parameter?
return response;
}
} // namespace csoap

@ -5,12 +5,14 @@
namespace csoap {
HttpResponseParser::HttpResponseParser(HttpResponse* response)
: HttpParser(response)
, response_(response) {
: HttpParser(response)
, response_(response) {
}
// TODO: Use split.
Error HttpResponseParser::ParseStartLine(const std::string& line) {
response_->set_start_line(line + "\r\n");
size_t off = 0;
size_t pos = line.find(' ');
@ -37,7 +39,6 @@ Error HttpResponseParser::ParseStartLine(const std::string& line) {
}
off = pos + 1; // Skip space.
//response_->set_reason(line.substr(off));
if (response_->status() != HttpStatus::OK) {
return kHttpStatusError;

@ -1,9 +1,6 @@
#include "csoap/soap_client.h"
#include <cassert>
#include <iostream>
#include "boost/lexical_cast.hpp"
#include "csoap/http_client.h"
#include "csoap/http_request.h"
@ -33,17 +30,17 @@ Error SoapClient::Call(const std::string& operation,
soap_request.AddParameter(parameters[i]);
}
std::string http_request_body;
soap_request.ToXml(&http_request_body);
std::string http_content;
soap_request.ToXml(&http_content);
HttpRequest http_request;
http_request.set_version(kHttpV11); // TODO
http_request.set_url(url_);
http_request.set_content_length(http_request_body.size());
http_request.set_content(http_request_body); // TODO: move
http_request.set_host(host_, port_);
http_request.set_soap_action(operation);
http_request.SetURL(url_);
http_request.SetContentType(kTextXmlUtf8);
http_request.SetContentLength(http_content.size());
http_request.SetHost(host_, port_);
http_request.SetHeader(kSOAPAction, operation);
http_request.set_content(std::move(http_content));
HttpResponse http_response;

@ -3,7 +3,6 @@
#include <string>
#include "pugixml/pugixml.hpp"
#include "csoap/common.h"
namespace csoap {
@ -12,27 +11,27 @@ namespace csoap {
class SoapMessage {
public:
// 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;
}
CLIENT_API void set_service_ns(const Namespace& service_ns) {
void set_service_ns(const Namespace& service_ns) {
service_ns_ = service_ns;
}
SERVER_API const std::string& operation() const {
const std::string& operation() const {
return operation_;
}
CLIENT_API void set_operation(const std::string& operation) {
void set_operation(const std::string& operation) {
operation_ = operation;
}
// Convert to SOAP request XML.
CLIENT_API void ToXml(std::string* xml_string);
void ToXml(std::string* xml_string);
// Parse from SOAP request XML.
SERVER_API bool FromXml(const std::string& xml_string);
bool FromXml(const std::string& xml_string);
protected:
SoapMessage() {

@ -2,7 +2,6 @@
#define CSOAP_SOAP_REQUEST_H_
#include <vector>
#include "csoap/soap_message.h"
namespace csoap {
@ -12,11 +11,11 @@ namespace csoap {
// request body.
class SoapRequest : public SoapMessage {
public:
CLIENT_API void AddParameter(const std::string& key, const std::string& value);
CLIENT_API void AddParameter(const Parameter& parameter);
void AddParameter(const std::string& key, const std::string& value);
void AddParameter(const Parameter& parameter);
// Get parameter value by key.
SERVER_API std::string GetParameter(const std::string& key) const;
std::string GetParameter(const std::string& key) const;
protected:
void ToXmlBody(pugi::xml_node xbody) override;

@ -11,15 +11,15 @@ public:
// Could be "Price" for an operation/method like "GetXyzPrice".
// Really depend on the service.
// 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;
}
CLIENT_API const std::string& result() const {
const std::string& result() const {
return result_;
}
SERVER_API void set_result(const std::string& result) {
void set_result(const std::string& result) {
result_ = result;
}
@ -29,7 +29,9 @@ protected:
bool FromXmlBody(pugi::xml_node xbody) override;
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.
// 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.
virtual bool Handle(const SoapRequest& request,
virtual bool Handle(const SoapRequest& soap_request,
SoapResponse* soap_response) = 0;
protected:

@ -65,7 +65,7 @@ std::string GetNSAttr(pugi::xml_node& xnode,
// ...
// std::string 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 {
public:
explicit XmlStrRefWriter(std::string* result)

@ -2,28 +2,28 @@
#include "csoap/http_server.h"
#include "calculator_service.h"
// TODO: Why need an address for a server?
static void PrintHelp(const char* argv0) {
std::cout << "Usage: " << argv0 << " <address> <port>" << std::endl;
std::cout << " For IPv4, try:" << std::endl;
std::cout << " " << argv0 << " 0.0.0.0 80" << std::endl;
std::cout << " For IPv6, try:" << std::endl;
std::cout << " " << argv0 << " 0::0 80" << std::endl;
std::cout << "Usage: " << argv0 << " <port>" << std::endl;
std::cout << " E.g.," << std::endl;
std::cout << " " << argv0 << " 8080" << std::endl;
}
int main(int argc, char* argv[]) {
if (argc != 3) {
if (argc != 2) {
PrintHelp(argv[0]);
return 1;
}
const char* host = "0.0.0.0"; // TODO
try {
csoap::HttpServer server(argv[1], argv[2]);
csoap::HttpServer server(host, argv[1]);
csoap::SoapServicePtr service(new CalculatorService);
server.RegisterService(service);
server.Run();
} catch (std::exception& e) {
std::cerr << "exception: " << e.what() << "\n";
return 1;

Loading…
Cancel
Save