1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
import cgi
import os
import sys
import types
import StringIO
from twisted.internet import defer
from twisted.internet import reactor
from twisted.web import error
from twisted.web import resource
from twisted.web import server
from xen.xend import sxp
from xen.xend import PrettyPrint
def uri_pathlist(p):
"""Split a path into a list.
p path
return list of path elements
"""
l = []
for x in p.split('/'):
if x == '': continue
l.append(x)
return l
class SrvBase(resource.Resource):
"""Base class for services.
"""
def parse_form(self, req, method):
"""Parse the data for a request, GET using the URL, POST using encoded data.
Posts should use enctype='multipart/form-data' in the <form> tag,
rather than 'application/x-www-form-urlencoded'. Only 'multipart/form-data'
handles file upload.
req request
returns a cgi.FieldStorage instance
"""
env = {}
env['REQUEST_METHOD'] = method
if self.query:
env['QUERY_STRING'] = self.query
val = cgi.FieldStorage(fp=req.rfile, headers=req.headers, environ=env)
return val
def use_sxp(self, req):
"""Determine whether to send an SXP response to a request.
Uses SXP if there is no User-Agent, no Accept, or application/sxp is in Accept.
req request
returns 1 for SXP, 0 otherwise
"""
ok = 0
user_agent = req.getHeader('User-Agent')
accept = req.getHeader('Accept')
if (not user_agent) or (not accept) or (accept.find(sxp.mime_type) >= 0):
ok = 1
return ok
def get_op_method(self, op):
"""Get the method for an operation.
For operation 'foo' looks for 'op_foo'.
op operation name
returns method or None
"""
op_method_name = 'op_' + op
return getattr(self, op_method_name, None)
def perform(self, req):
"""General operation handler for posted operations.
For operation 'foo' looks for a method op_foo and calls
it with op_foo(op, req). Replies with code 500 if op_foo
is not found.
The method must return a list when req.use_sxp is true
and an HTML string otherwise (or list).
Methods may also return a Deferred (for incomplete processing).
req request
"""
op = req.args.get('op')
if op is None or len(op) != 1:
req.setResponseCode(404, "Invalid")
return ''
op = op[0]
op_method = self.get_op_method(op)
if op_method is None:
req.setResponseCode(501, "Not implemented")
req.setHeader("Content-Type", "text/plain")
req.write("Not implemented: " + op)
return ''
else:
val = op_method(op, req)
if isinstance(val, defer.Deferred):
val.addCallback(self._cb_perform, req, 1)
return server.NOT_DONE_YET
else:
self._cb_perform(val, req, 0)
return ''
def _cb_perform(self, val, req, dfr):
"""Callback to complete the request.
May be called from a Deferred.
"""
if isinstance(val, error.ErrorPage):
req.write(val.render(req))
elif self.use_sxp(req):
req.setHeader("Content-Type", sxp.mime_type)
sxp.show(val, req)
else:
req.write('<html><head></head><body>')
self.print_path(req)
if isinstance(val, types.ListType):
req.write('<code><pre>')
PrettyPrint.prettyprint(val, out=req)
req.write('</pre></code>')
else:
req.write(str(val))
req.write('</body></html>')
if dfr:
req.finish()
def print_path(self, req):
"""Print the path with hyperlinks.
"""
pathlist = [x for x in req.prepath if x != '' ]
s = "/"
req.write('<h1><a href="/">/</a>')
for x in pathlist:
s += x + "/"
req.write(' <a href="%s">%s</a>/' % (s, x))
req.write("</h1>")
|