#!/usr/bin/env python3 from http.server import BaseHTTPRequestHandler, HTTPServer from subprocess import Popen, PIPE from shlex import quote import argparse import sys def server_class_factory(command): class MyServer(BaseHTTPRequestHandler): def do_GET(self): self.handle_all() def do_POST(self): self.handle_all() def do_PUT(self): self.handle_all() def handle_all(self): self.send_response(200) self.send_header("Content-type", "text/html") self.end_headers() content = self.rfile.read(int(self.headers.get('Content-Length', 0))) p = Popen(command + [quote(self.command), quote(self.path)], stdin=PIPE, shell=False) p.communicate(input=content) def log_message(self, format, *args): return return MyServer if __name__ == "__main__": parser = argparse.ArgumentParser(description='shellsrv - Translate HTTP requests to command invocations on the host system.\n\n\nEach GET request results in the execution of COMMAND ARGS GET . Other HTTP verbs might be added later.', prog='shellsrv') parser.add_argument('--host', '-H', type=str, help='HTTP server host, default 0.0.0.0', default="0.0.0.0") parser.add_argument('--port', '-p', type=int, help='HTTP server port, default 8080', default=8080) parser.add_argument('--limit', '-n', type=int, help='Close the server after limit requests', default=-1) parser.add_argument('command', metavar='COMMAND', type=str, nargs=1, help='command to call') parser.add_argument('args', metavar='ARG', type=str, nargs='*', help='args of the command to call') args = parser.parse_args() command = args.command + args.args request_limit = args.limit server = HTTPServer((args.host, args.port), server_class_factory(command)) print("Server started http://%s:%s" % (args.host, args.port), file=sys.stderr) if request_limit < 0: try: server.serve_forever() except KeyboardInterrupt: pass else: for _ in range(request_limit): server.handle_request() server.server_close()