diff --git a/README.md b/README.md
index f8c72f8..288c143 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,16 @@
# csoap
-A lightweight C++ SOAP client library.
[中文版介绍](https://segmentfault.com/a/1190000009874151)
-## Usage
+A lightweight C++ SOAP client & server library based on Boost.Asio.
+
+NOTE: The server part is currently under development, not stable enough to be used in a real production.
+
+## Client Usage
Firstly, please install SoapUI if you don't have it. We need SoapUI to generate sample requests for each web service operation. The open source version is good enough.
-Take the calculator web service provided by ParaSoft as an example. Download the WSDL from http://ws1.parasoft.com/glue/calculator.wsdl, create a SOAP project within SoapUI (remember to check "Create sample requests for all operations?"), you will see the sample request for "add" operation as the following:
+Take the calculator web service provided by ParaSoft as an example. Download the WSDL from http://ws1.parasoft.com/glue/calculator.wsdl, create a SOAP project within SoapUI (remember to check "**Create sample requests for all operations?**"), you will see the sample request for "add" operation as the following:
```xml
@@ -20,72 +23,96 @@ Take the calculator web service provided by ParaSoft as an example. Download the
```
-In order to call the "add" operation, we have to send a HTTP request with the above SOAP envelope as the content. Let's see how to do this with csoap.
-
-```cpp
-bool Add() {
- // Create a SOAP request.
- csoap::SoapRequest soap_request("add");
-
- // Set the service namespace.
- csoap::Namespace service_ns = { "cal", "http://www.parasoft.com/wsdl/calculator/" };
- soap_request.set_service_ns(service_ns);
-
- // Add parameters for the operation.
- soap_request.AddParameter("x", "1.0");
- soap_request.AddParameter("y", "2.0");
-
- // Generate the XML string for the SOAP envelope.
- std::string http_request_body;
- soap_request.ToXmlString(&http_request_body);
+In order to call the "add" operation, we have to send a HTTP request with the above SOAP envelope as the content. Let's see how to do this with *csoap*.
- // Create a HTTP request.
- csoap::HttpRequest http_request(csoap::kHttpV11);
+Firstly, create a class `CalculatorClient` which is derived from `csoap::SoapClient`:
- // Set the HTTP request headers.
- http_request.set_url("/glue/calculator");
- http_request.set_content_length(http_request_body.size());
- http_request.set_host("ws1.parasoft.com", "");
- http_request.set_soap_action("add");
-
- // Send the HTTP request and get the HTTP response.
-
- csoap::HttpResponse http_response;
+```cpp
+#include
+#include "csoap/soap_client.h"
- csoap::HttpClient http_client;
- csoap::ErrorCode ec = http_client.SendRequest(http_request,
- http_request_body,
- &http_response);
+class CalculatorClient : public csoap::SoapClient {
+public:
+ CalculatorClient() {
+ Init();
+ }
+```
- // Error handling.
- if (ec != csoap::kNoError) {
- std::cerr << csoap::GetErrorMessage(ec) << std::endl;
+Initialize the URL, host, port, etc. in `Init()`:
+```cpp
+private:
+ void Init() {
+ url_ = "/glue/calculator";
+ host_ = "ws1.parasoft.com";
+ port_ = ""; // Default to "80".
+ service_ns_ = { "cal", "http://www.parasoft.com/wsdl/calculator/" };
+ result_name_ = "Result";
+ }
+```
+
+Because four calculator operations (*add*, *subtract*, *multiply* and *divide*) all have two parameters, we create a wrapper for `SoapClient::Call()`, name is as `Calc`:
+```cpp
+bool Calc(const std::string& operation,
+ const std::string& x_name,
+ const std::string& y_name,
+ double x,
+ double y,
+ double* result) {
+ // Prepare parameters.
+ csoap::Parameter parameters[] = {
+ { x_name, x },
+ { y_name, y }
+ };
+
+ // Make the call.
+ std::string result_str;
+ if (!Call(operation, parameters, 2, &result_str)) {
return false;
}
- // Parse the SOAP response.
- std::string result;
- csoap::SoapResponse soap_response;
- if (!soap_response.Parse(http_response.content(), "addResponse", "Result", &result)) {
+ // Convert the result from string to double.
+ try {
+ *result = boost::lexical_cast(result_str);
+ } catch (boost::bad_lexical_cast&) {
return false;
}
- std::cout << result << std::endl;
-
return true;
}
```
-It's not that complicated. But you can't code like this for each operation. You have to do some encapsulation, make a general function, add a base class, and so on. Check the "demo" folder for the detailed example.
+Finally, we implement the four operations simply as the following:
+```cpp
+bool Add(double x, double y, double* result) {
+ return Calc("add", "x", "y", x, y, result);
+}
+
+bool Subtract(double x, double y, double* result) {
+ return Calc("subtract", "x", "y", x, y, result);
+}
+
+bool Multiply(double x, double y, double* result) {
+ return Calc("multiply", "x", "y", x, y, result);
+}
+
+bool Divide(double x, double y, double* result) {
+ return Calc("divide", "numerator", "denominator", x, y, result);
+}
+```
+See? It's not that complicated. Check folder ***demo/calculator_client*** for the full example.
+
+## Server Usage
+TODO
## Limitations
-- Only support HTTP 1.1.
- Only support `int`, `double`, `bool` and `string` parameters.
- Only support UTF-8 encoded content.
+- One connection one call.
+- Connection is in synchronous (or blocking) mode; timeout (default to 30s) is configurable.
## Dependencies
-- The TCP socket client is based on Boost.Asio.
-- The XML parsing is based on TinyXml or PugiXml, a macro `CSOAP_USE_TINYXML` controls which one to use.
-- Build system is CMake, but it should be easy to integrate into your project.
+- Boost.Asio is used for both client and server.
+- XML processing is based on PugiXml, which is already included in the source tree.
+- Build system is CMake, but it should be quite easy to integrate into your own project.
diff --git a/src/demo/calculator_client/calculator_client.h b/src/demo/calculator_client/calculator_client.h
index 7828b54..9d0f401 100644
--- a/src/demo/calculator_client/calculator_client.h
+++ b/src/demo/calculator_client/calculator_client.h
@@ -7,7 +7,7 @@
#include
#include "csoap/soap_client.h"
-class CalculatorClient : csoap::SoapClient {
+class CalculatorClient : public csoap::SoapClient {
public:
CalculatorClient();