Changeset 0a20ef8
- Timestamp:
- Nov 29, 2008 10:22:17 PM (16 years ago)
- Branches:
- axis_example, compt_changes, info-ops, master, version-1.30, version-2.00, version-3.01, version-3.02
- Children:
- 2729e48
- Parents:
- 1b57352
- Location:
- fedd
- Files:
-
- 2 added
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
fedd/fedd.py
r1b57352 r0a20ef8 3 3 import sys 4 4 5 from socket import error as socket_error6 from BaseHTTPServer import BaseHTTPRequestHandler7 8 from ZSI import Fault, ParseException, FaultFromNotUnderstood, \9 FaultFromZSIException, FaultFromException, ParsedSoap, SoapWriter10 11 from M2Crypto import SSL12 from M2Crypto.SSL.SSLServer import ThreadingSSLServer13 import xmlrpclib14 15 5 from optparse import OptionParser 16 6 7 from fedd_server import fedd_server, fedd_xmlrpc_handler, fedd_soap_handler 8 from fedd_config_parser import fedd_config_parser 17 9 from fedd_util import fedd_ssl_context 18 from fedid import fedid19 10 from fedd_deter_impl import new_feddservice 20 from fedd_services import ns021 from service_error import *22 11 23 12 from threading import * … … 26 15 from time import sleep 27 16 import logging 28 from ConfigParser import *29 30 # The SSL server here is based on the implementation described at31 # http://www.xml.com/pub/a/ws/2004/01/20/salz.html32 33 # Turn off the matching of hostname to certificate ID34 SSL.Connection.clientPostConnectionCheck = None35 36 class fedd_config_parser(SafeConfigParser):37 """38 A SafeConfig parser with a more forgiving get attribute39 """40 41 def safe_get(self, sect, opt, method, default=None):42 """43 If the option is present, return it, otherwise the default.44 """45 if self.has_option(sect, opt): return method(self, sect, opt)46 else: return default47 48 def get(self, sect, opt, default=None):49 """50 This returns the requested option or a given default.51 52 It's more like getattr than get.53 """54 55 return self.safe_get(sect, opt, SafeConfigParser.get, default)56 57 def getint(self, sect, opt, default=0):58 """59 Returns the selected option as an int or a default.60 """61 62 return self.safe_get(sect, opt, SafeConfigParser.getint, default)63 64 def getfloat(self, sect, opt, default=0.0):65 """66 Returns the selected option as an int or a default.67 """68 69 return self.safe_get(sect, opt, SafeConfigParser.getfloat, default)70 71 def getboolean(self, sect, opt, default=False):72 """73 Returns the selected option as a boolean or a default.74 """75 76 return self.safe_get(sect, opt, SafeConfigParser.getboolean, default)77 78 class fedd_server(ThreadingSSLServer):79 """80 Interface the fedd services to the XMLRPC and SOAP interfaces81 """82 def __init__(self, ME, handler, ssl_ctx, impl):83 """84 Create an SSL server that handles the transport in handler using the85 credentials in ssl_ctx, and interfacing to the implementation of fedd86 services in fedd. ME is the host port pair on which to bind.87 """88 ThreadingSSLServer.__init__(self, ME, handler, ssl_ctx)89 self.impl = impl90 self.soap_methods = impl.soap_services91 self.xmlrpc_methods = impl.xmlrpc_services92 self.log = logging.getLogger("fedd")93 94 def handle_error(self, request, address):95 """96 The default SSLServer prints a stack trace here. This is a little97 friendlier.98 """99 if request or address:100 self.log.warn("[fedd] Error on incoming connection: %s %s" % \101 (request, address))102 else:103 self.log.warn("[fedd] Error on incoming connection " + \104 "(Likely SSL error)")105 106 class fedd_soap_handler(BaseHTTPRequestHandler):107 """108 Standard connection between SOAP and the fedd services in impl.109 110 Much of this is boilerplate from111 http://www.xml.com/pub/a/ws/2004/01/20/salz.html112 """113 server_version = "ZSI/2.0 fedd/0.1 " + BaseHTTPRequestHandler.server_version114 115 def send_xml(self, text, code=200):116 """Send an XML document as reply"""117 self.send_response(code)118 self.send_header('Content-type', 'text/xml; charset="utf-8"')119 self.send_header('Content-Length', str(len(text)))120 self.end_headers()121 self.wfile.write(text)122 self.wfile.flush()123 self.request.socket.close()124 125 def send_fault(self, f, code=500):126 """Send a SOAP encoded fault as reply"""127 self.send_xml(f.AsSOAP(processContents="lax"), code)128 129 def check_headers(self, ps):130 """Send a fault for any required envelope headers"""131 for (uri, localname) in ps.WhatMustIUnderstand():132 self.send_fault(FaultFromNotUnderstood(uri, lname, 'fedd'))133 return False134 return True135 136 def check_method(self, ps):137 """Confirm that this class implements the namespace and SOAP method"""138 root = ps.body_root139 if root.namespaceURI not in self.server.impl.soap_namespaces:140 self.send_fault(Fault(Fault.Client,141 'Unknown namespace "%s"' % root.namespaceURI))142 return False143 144 if getattr(root, 'localName', None) == None:145 self.send_fault(Fault(Fault.Client, 'No method"'))146 return False147 return True148 149 def do_POST(self):150 """Treat an HTTP POST request as a SOAP service call"""151 try:152 cl = int(self.headers['content-length'])153 data = self.rfile.read(cl)154 ps = ParsedSoap(data)155 except ParseException, e:156 self.send_fault(Fault(Fault.Client, str(e)))157 return158 except Exception, e:159 self.send_fault(FaultFromException(e, 0, sys.exc_info()[2]))160 return161 if not self.check_headers(ps): return162 if not self.check_method(ps): return163 try:164 resp = self.soap_dispatch(ps.body_root.localName, ps,165 fedid(cert=self.request.get_peer_cert()))166 except Fault, f:167 self.send_fault(f)168 resp = None169 170 if resp != None:171 sw = SoapWriter()172 sw.serialize(resp)173 self.send_xml(str(sw))174 175 def log_request(self, code=0, size=0):176 """177 Log request to the fedd logger178 """179 self.server.log.info("Successful SOAP request code %d" % code)180 181 def soap_dispatch(self, method, req, fid):182 """183 The connection to the implementation, using the method maps184 185 The implementation provides a mapping from SOAP method name to the186 method in the implementation that provides the service.187 """188 if self.server.soap_methods.has_key(method):189 try:190 return self.server.soap_methods[method](req, fid)191 except service_error, e:192 de = ns0.faultType_Def(193 (ns0.faultType_Def.schema,194 "FeddFaultBody")).pyclass()195 de._code=e.code196 de._errstr=e.code_string()197 de._desc=e.desc198 if e.is_server_error():199 raise Fault(Fault.Server, e.code_string(), detail=de)200 else:201 raise Fault(Fault.Client, e.code_string(), detail=de)202 else:203 raise Fault(Fault.Client, "Unknown method: %s" % method)204 205 206 class fedd_xmlrpc_handler(BaseHTTPRequestHandler):207 """208 Standard connection between XMLRPC and the fedd services in impl.209 210 Much of this is boilerplate from211 http://www.xml.com/pub/a/ws/2004/01/20/salz.html212 """213 server_version = "ZSI/2.0 fedd/0.1 " + BaseHTTPRequestHandler.server_version214 215 def send_xml(self, text, code=200):216 """Send an XML document as reply"""217 self.send_response(code)218 self.send_header('Content-type', 'text/xml; charset="utf-8"')219 self.send_header('Content-Length', str(len(text)))220 self.end_headers()221 self.wfile.write(text)222 self.wfile.flush()223 # Make sure to close the socket when we're done224 self.request.socket.close()225 226 def do_POST(self):227 """Treat an HTTP POST request as an XMLRPC service call"""228 # NB: XMLRPC faults are not HTTP errors, so the code is always 200,229 # unless an HTTP error occurs, which we don't handle.230 231 resp = None232 data = None233 method = None234 cl = int(self.headers['content-length'])235 data = self.rfile.read(cl)236 237 try:238 params, method = xmlrpclib.loads(data)239 except xmlrpclib.ResponseError:240 data = xmlrpclib.dumps(xmlrpclib.Fault("Client",241 "Malformed request"), methodresponse=True)242 243 if method != None:244 try:245 resp = self.xmlrpc_dispatch(method, params,246 fedid(cert=self.request.get_peer_cert()))247 data = xmlrpclib.dumps((resp,), encoding='UTF-8',248 methodresponse=True)249 except xmlrpclib.Fault, f:250 data = xmlrpclib.dumps(f, methodresponse=True)251 resp = None252 253 self.send_xml(data)254 255 def log_request(self, code=0, size=0):256 """257 Log request to the fedd logger258 """259 self.server.log.info("Successful XMLRPC request code %d" % code)260 261 262 def xmlrpc_dispatch(self, method, req, fid):263 """264 The connection to the implementation, using the method maps265 266 The implementation provides a mapping from XMLRPC method name to the267 method in the implementation that provides the service.268 """269 if self.server.xmlrpc_methods.has_key(method):270 try:271 return self.server.xmlrpc_methods[method](req, fid)272 except service_error, e:273 raise xmlrpclib.Fault(e.code_string(), e.desc)274 else:275 raise xmlrpclib.Fault(100, "Unknown method: %s" % method)276 17 277 18 class fedd_opts(OptionParser):
Note: See TracChangeset
for help on using the changeset viewer.