xref: /spdk/scripts/rpc_http_proxy.py (revision bb488d2829a9b7863daab45917dd2174905cc0ae)
1#!/usr/bin/env python3
2
3import base64
4import errno
5import json
6import socket
7import sys
8try:
9    from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
10except ImportError:
11    from http.server import HTTPServer
12    from http.server import BaseHTTPRequestHandler
13
14rpc_sock = None
15
16
17def print_usage_and_exit(status):
18    print('Usage: rpc_http_proxy.py <server IP> <server port> <user name>' +
19          ' <password> <SPDK RPC socket (optional, default: /var/tmp/spdk.sock)>')
20    sys.exit(status)
21
22
23def rpc_call(req):
24    global rpc_sock
25
26    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
27    sock.connect(rpc_sock)
28    sock.sendall(req)
29
30    if 'id' not in json.loads(req.decode('ascii')):
31        sock.close()
32        return None
33
34    buf = ''
35    closed = False
36    response = None
37
38    while not closed:
39        newdata = sock.recv(1024)
40        if (newdata == b''):
41            closed = True
42        buf += newdata.decode('ascii')
43        try:
44            response = json.loads(buf)
45        except ValueError:
46            continue  # incomplete response; keep buffering
47        break
48
49    sock.close()
50
51    if not response and len(buf) > 0:
52        raise
53
54    return buf
55
56
57class ServerHandler(BaseHTTPRequestHandler):
58
59    key = ""
60
61    def do_HEAD(self):
62        self.send_response(200)
63        self.send_header('Content-type', 'text/html')
64        self.end_headers()
65
66    def do_AUTHHEAD(self):
67        self.send_response(401)
68        self.send_header('WWW-Authenticate', 'text/html')
69        self.send_header('Content-type', 'text/html')
70        self.end_headers()
71
72    def do_INTERNALERROR(self):
73        self.send_response(500)
74        self.send_header('Content-type', 'text/html')
75        self.end_headers()
76
77    def do_POST(self):
78        if self.headers['Authorization'] != 'Basic ' + self.key:
79            self.do_AUTHHEAD()
80        else:
81            data_string = self.rfile.read(int(self.headers['Content-Length']))
82
83            try:
84                response = rpc_call(data_string)
85                if response is not None:
86                    self.do_HEAD()
87                    self.wfile.write(bytes(response.encode(encoding='ascii')))
88            except ValueError:
89                self.do_INTERNALERROR()
90
91
92def main():
93    global rpc_sock
94
95    if len(sys.argv) == 1 or sys.argv[1] == '-h':
96        print_usage_and_exit(0)
97    elif len(sys.argv) < 5:
98        print('Not enough arguments')
99        print_usage_and_exit(errno.EINVAL)
100    elif len(sys.argv) > 6:
101        print('Too many arguments')
102        print_usage_and_exit(errno.E2BIG)
103
104    if len(sys.argv) == 6:
105        rpc_sock = sys.argv[5]
106    else:
107        rpc_sock = '/var/tmp/spdk.sock'
108
109    # encoding user name and password
110    key = base64.b64encode((sys.argv[3]+':'+sys.argv[4]).encode(encoding='ascii')).decode('ascii')
111
112    try:
113        ServerHandler.key = key
114        httpd = HTTPServer((sys.argv[1], int(sys.argv[2])), ServerHandler)
115        print('Started RPC http proxy server')
116        httpd.serve_forever()
117    except KeyboardInterrupt:
118        print('Shutting down server')
119        httpd.socket.close()
120
121
122if __name__ == '__main__':
123    main()
124