Contact: fumanchu@aminus.org

Log in as guest/misc to create tickets

root/httprepl.py

Revision 121 (checked in by fumanchu, 2 years ago)

HTTPREPL: Improved overflow in tipbar, plus a CP 3 fix.

Line 
1 import codeop
2 import inspect
3 import os
4 localDir = os.path.dirname(__file__)
5 import re
6
7 try:
8     from cStringIO import StringIO
9 except ImportError:
10     from StringIO import StringIO
11
12 import sys
13 import traceback
14
15
16 class HTTPREPL:
17    
18     def __init__(self, locals=None):
19         self.locals = {}
20         if locals:
21             self.locals.update(locals)
22         self.buffer = []
23    
24     def push(self, line):
25         """Push 'line' and return exec results (None if more input needed)."""
26         if line == "help":
27             return "Type help(object) for help about object."
28         if line == "help()":
29             return "You cannot call help() without an argument."
30        
31         self.buffer.append(line)
32         source = "\n".join(self.buffer)
33        
34         try:
35             code = codeop.compile_command(source, "<HTTP input>", 'single')
36         except (OverflowError, SyntaxError, ValueError):
37             self.buffer = []
38             return traceback.format_exc()
39        
40         if code is None:
41             # More lines needed.
42             return None
43        
44         self.buffer = []
45         return self.execute(code)
46    
47     def execute(self, code):
48         """Execute the given code in self.locals and return any stdout/sterr."""
49         out = StringIO()
50         oldout = sys.stdout
51         olderr = sys.stderr
52         sys.stdout = sys.stderr = out
53         try:
54             try:
55                 exec code in self.locals
56             except:
57                 result = traceback.format_exc()
58             else:
59                 result = out.getvalue()
60         finally:
61             sys.stdout = oldout
62             sys.stderr = olderr
63         out.close()
64         return result
65    
66     def dir(self, line):
67         """Examine a partial line and provide attr list of final expr."""
68         line = re.split(r"\s", line)[-1].strip()
69         # Support lines like "thing.attr" as "thing.", because the browser
70         # may not finish calculating the partial line until after the user
71         # has clicked on a few more keys.
72         line = ".".join(line.split(".")[:-1])
73         try:
74             result = eval("dir(%s)" % line, {}, self.locals)
75         except:
76             return []
77         return result
78    
79     def doc(self, line):
80         """Examine a partial line and provide sig+doc of final expr."""
81         line = re.split(r"\s", line)[-1].strip()
82         # Support lines like "func(text" as "func(", because the browser
83         # may not finish calculating the partial line until after the user
84         # has clicked on a few more keys.
85         line = "(".join(line.split("(")[:-1])
86         try:
87             result = eval(line, {}, self.locals)
88             try:
89                 if isinstance(result, type):
90                     func = result.__init__
91                 else:
92                     func = result
93                 args, varargs, varkw, defaults = inspect.getargspec(func)
94             except TypeError:
95                 if callable(result):
96                     doc = getattr(result, "__doc__", "") or ""
97                     return "%s\n\n%s" % (line, doc)
98                 return None
99         except:
100             return None
101        
102         if args and args[0] == 'self':
103             args.pop(0)
104         missing = object()
105         defaults = defaults or []
106         defaults = ([missing] * (len(args) - len(defaults))) + list(defaults)
107         arglist = []
108         for a, d in zip(args, defaults):
109             if d is missing:
110                 arglist.append(a)
111             else:
112                 arglist.append("%s=%s" % (a, d))
113         if varargs:
114             arglist.append("*%s" % varargs)
115         if varkw:
116             arglist.append("**%s" % varkw)
117         doc = getattr(result, "__doc__", "") or ""
118         return "%s(%s)\n%s" % (line, ", ".join(arglist), doc)
119    
120    
121
122
123 class Root:
124    
125     def __init__(self, locals=None):
126         self.repl = HTTPREPL(locals)
127    
128     def index(self):
129         """Return an HTTP-based Read-Eval-Print-Loop terminal."""
130         return open(os.path.join(localDir, "httprepl.html")).read()
131     index.exposed = True
132    
133     def push(self, line):
134         """Push 'line' and return exec results as a bare response."""
135         result = self.repl.push(line)
136         if result is None:
137             # More input lines needed.
138             import cherrypy
139             cherrypy.response.status = 204
140         return result
141     push.exposed = True
142    
143     def dir(self, line):
144         """Push 'line' and return result of eval on the final expr."""
145         result = self.repl.dir(line)
146         if not result:
147             import cherrypy
148             cherrypy.response.status = 204
149             return
150         return repr(result)
151     dir.exposed = True
152    
153     def doc(self, line):
154         """Push 'line' and return result of getargspec on the final expr."""
155         result = self.repl.doc(line)
156         if not result:
157             import cherrypy
158             cherrypy.response.status = 204
159         return result
160     doc.exposed = True
161
162
163 if __name__ == '__main__':
164     argv = list(sys.argv[1:])
165     if argv:
166         target = argv[0]
167         print "CherryPy is the only server supported at the moment. Care to add yours?"
168         sys.exit(1)
169    
170     import cherrypy
171     cherrypy.config.update({"server.environment": "production",
172                             # CP 3 syntax:
173                             "environment": "production",
174                             })
175     cherrypy.tree.mount(Root(globals()))
176     cherrypy.server.start()
177     cherrypy.engine.start()
Note: See TracBrowser for help on using the browser.