本文转自:http://xiaoxia.org/2011/08/16/a-small-python-program-serverinformation/


需求:

监听一个端口,提供HTTP接口,通过访问Web地址,调用程序获取各种信息。


例如,想在远程服务器上执行free命令查看远程服务器的内存使用情况,

free -m 的base64编码为 ZnJlZSAtbQ== (可以在bash下使用命令生成base64编码  echo -n "free -m"|base64 )

则访问下面的地址:

http://xiaoxia.org:10000/ZnJlZSAtbQ==

提交之后返回类似于下面的结果,

             total       used       free     shared    buffers     cached
Mem:         16053      10521       5532          0        871       7874
-/+ buffers/cache:       1776      14277
Swap:        16002          0      16002


为了安全使用,在CommandList文本文件里保存着一个命令列表,即可以允许调用的程序。

ps aux
free -m
netstat -na
cat /proc/meminfo
cat /proc/cpuinfo


 
  

代码实现:

1.原始版本源代码:

from BaseHTTPServer import * 
import base64, os 
          
decorator = lambda x: x.rstrip("\n") + " (" + base64.b64encode(x.rstrip("\n")) + ")\n" 
          
class Handler(BaseHTTPRequestHandler): 
    def process(self): 
        path = self.path.split('?')[0].split('#')[0][1:] 
        try: 
            cmd = base64.decodestring(path) 
            if cmd == "": 
                return "Command List: \n\n" + "".join(map(decorator, file("CommandList").readlines())) 
        except: 
            return "Try to access /[Base64 String]" 
        if cmd+"\n" in file("CommandList").readlines(): 
            return os.popen(cmd, "r").read() 
        else: 
            return cmd + " is not permitted" 
    def do_GET(self): 
        self.send_response(200) 
        buf = self.process() 
        self.send_header("Content-Type", "text/plain; charset=utf8") 
        self.send_header("Content-Length", str(len(buf))) 
        self.end_headers() 
        self.wfile.write(buf) 
          
httpd = HTTPServer(("", 10000), Handler) 
print "Server starting ..." 
try: 
    httpd.serve_forever() 
except KeyboardInterrupt: exit()


2.多线程版本源代码:

from BaseHTTPServer import * 
from SocketServer import ThreadingMixIn 
import base64, os 
    
decorator = lambda x: x.rstrip("\n") + " (" + base64.b64encode(x.rstrip("\n")) + ")\n" 
    
class Handler(BaseHTTPRequestHandler): 
    def process(self): 
        path = self.path.split('?')[0].split('#')[0][1:] 
        try: 
            cmd = base64.decodestring(path) 
            if cmd == "": 
                return "Command List: \n\n" + "".join(map(decorator, file("CommandList").readlines())) 
        except: 
            return "Try to access /[Base64 String]" 
        if cmd+"\n" in file("CommandList").readlines(): 
            return os.popen(cmd, "r").read() 
        else: 
            return cmd + " is not permitted" 
    def do_GET(self): 
        self.send_response(200) 
        buf = self.process() 
        self.send_header("Content-Type", "text/plain; charset=utf8") 
        self.send_header("Content-Length", str(len(buf))) 
        self.end_headers() 
        self.wfile.write(buf) 
            
class ThreadingHTTPServer(ThreadingMixIn, HTTPServer): pass 
    
httpd = ThreadingHTTPServer(("", 10000), Handler) 
print "Server starting ..." 
try: 
    httpd.serve_forever() 
except KeyboardInterrupt: exit()