Skip to content

Latest commit

Β 

History

History
105 lines (78 loc) Β· 4.13 KB

File metadata and controls

105 lines (78 loc) Β· 4.13 KB

πŸ” XML-RPC Client-Server Example with SSL

πŸ“ Overview

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 Data envelope carrying both args and kwargs.
  • 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.

πŸ“ Project Structure

  • server.py: XML-RPC server implementation (HTTP and HTTPS).
  • client.py: XML-RPC client implementation and CLI.
  • utils.py: Data envelope, value conversion helpers, certificate generation.
  • conftest.py: puts the repository root on sys.path for 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.

πŸ“¦ Requirements

  • Python 3.8+
  • Packages listed in requirements.txt

βš™οΈ Setup

  1. Install dependencies:
    pip install -r requirements.txt

πŸ–₯️ Running the Server

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 both

Override 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 9443

On 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.

πŸ’» Running the Client

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:8443

Available 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) = 9223372036854775808

The 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 $?
1

πŸ§ͺ Testing

pytest tests/
  • tests/test_conversion.py β€” unit tests for the conversion layer and Data. No server needed.
  • tests/test_client.py β€” end-to-end tests. These are skipped unless servers are listening on localhost:8000 and localhost:8443; start them with python server.py both to run the full suite.

πŸ”Š Logging

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 1

⚠️ Security Notes

This is a demonstration project, not a hardened service:

  • The HTTPS certificate is self-signed. The client passes verify_ssl=False by 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 localhost by default. Think carefully before exposing it on 0.0.0.0.

πŸ“„ License

MIT License