This project demonstrates a simple XML-RPC client-server architecture in Python. The server exposes remote math procedures over plain HTTP and over HTTPS (with a self-signed certificate), and the client invokes them from the command line.
On top of stock XML-RPC it adds two things:
- kwargs support β XML-RPC has no notion of keyword arguments, so calls are wrapped in a
Dataenvelope carrying bothargsandkwargs. - Exact numbers β XML-RPC's
<int>is 32-bit and<double>loses precision, so integers and floats travel as tagged strings (__INT__42,__FLOAT__3.14) and are decoded on arrival. This keeps arbitrary-precision integers intact end to end.
server.py: XML-RPC server implementation (HTTP and HTTPS).client.py: XML-RPC client implementation and CLI.utils.py:Dataenvelope, value conversion helpers, certificate generation.conftest.py: puts the repository root onsys.pathfor the test suite.requirements.txt: Python dependencies.server.crt,server.key: SSL certificate and key β auto-generated on first HTTPS start, not checked in.logs/: Directory for server and client logs (auto-created).tests/: Contains test cases.
- Python 3.8+
- Packages listed in
requirements.txt
- Install dependencies:
pip install -r requirements.txt
| Command | Description | Default |
|---|---|---|
python server.py http |
HTTP only | localhost:8000 |
python server.py https |
HTTPS only | localhost:8443 |
python server.py both |
Both, in separate threads | 8000 + 8443 |
python server.py bothOverride the bind address with --host / --port (or --http-host, --http-port, --https-host, --https-port for both):
python server.py http --host 0.0.0.0 --port 9000
python server.py both --https-port 9443On the first HTTPS start a self-signed certificate for localhost / 127.0.0.1 is written to server.crt and server.key (the key with 0600 permissions). Delete both files to force regeneration.
In a separate terminal:
python client.py add 2 2 # add(2, 2) = 4
python client.py divide 22.5 4.5 # divide(22.5, 4.5) = 5.0
python client.py multiply 7 6 --url https://localhost:8443
python client.py list-methods
python client.py test --url https://localhost:8443Available commands: add, subtract, multiply, divide, list-methods, test. All accept --url (default http://localhost:8000).
Integers keep full precision β they are not coerced to floats:
$ python client.py add 9223372036854775807 1
add(9223372036854775807, 1) = 9223372036854775808The client exits non-zero when a call fails, so it composes with shell scripts:
$ python client.py divide 10 0
Error calling divide(10, 0): Cannot divide by zero (Code: 400)
$ echo $?
1pytest tests/tests/test_conversion.pyβ unit tests for the conversion layer andData. No server needed.tests/test_client.pyβ end-to-end tests. These are skipped unless servers are listening onlocalhost:8000andlocalhost:8443; start them withpython server.py bothto run the full suite.
Logs go to stderr and to logs/server.log / logs/client.log (rotated at 1 MB). Both sinks honour the LOG_LEVEL environment variable, which defaults to INFO:
LOG_LEVEL=DEBUG python client.py add 1 1This is a demonstration project, not a hardened service:
- The HTTPS certificate is self-signed. The client passes
verify_ssl=Falseby default, which accepts any certificate and therefore gives no protection against an active attacker. It logs a warning when it does so. - There is no authentication or authorization β any client that can reach the port can call any registered method.
- The server binds to
localhostby default. Think carefully before exposing it on0.0.0.0.
MIT License