def __decode_soap_request(self, http_env, http_payload): # decode body using information in the http header # # fyi, here's what the parse_header function returns: # >>> import cgi; cgi.parse_header("text/xml; charset=utf-8") # ('text/xml', {'charset': 'utf-8'}) content_type = cgi.parse_header(http_env.get("CONTENT_TYPE")) charset = content_type[1].get('charset',None) if charset is None: charset = 'ascii' http_payload = collapse_swa(content_type, http_payload) # deserialize the body of the message req_payload, req_header = from_soap(http_payload, charset) return req_header, req_payload
def __decode_soap_request(self, http_env, http_payload): """ Decode http payload using information in the http header """ # fyi, here's what the parse_header function returns: # >>> import cgi; cgi.parse_header("text/xml; charset=utf-8") # ('text/xml', {'charset': 'utf-8'}) content_type = cgi.parse_header(http_env.get("CONTENT_TYPE")) charset = content_type[1].get('charset',None) if charset is None: charset = 'ascii' http_payload = collapse_swa(content_type, http_payload) # deserialize the body of the message req_payload, req_header = from_soap(http_payload, charset) return req_header, req_payload
def _on_request(self, request, response): if self.path is not None and self.path != request.path.rstrip("/"): return try: # Test if this is a SOAP request. SOAP 1.1 specifies special # header, SOAP 1.2 special Content-Type soapAction = request.headers["SOAPAction"] import cgi contentType = cgi.parse_header(request.headers["Content-Type"]) if not soapAction and contentType[0] != "application/soap+xml": return # Get body data of request body = request.body.read() # Use soaplib to separate header and payload charset = contentType[1].get("charset", None) if charset is None: charset = "ascii" payload, soapheader = from_soap(body, charset) from soaplib.soap import collapse_swa payload = collapse_swa(contentType, payload) if payload is not None: soapAction = payload.tag for node in payload: print node response.headers["Content-Type"] = "text/xml" # value = self.push(SoapOperation(*params), c, t) # value.response = response # value.onSet = ("value_changed", self) except Exception as e: # TODO: r = self._error(1, "%s: %s" % (type(e), e)) return r else: return True
def _on_request(self, request, response): if self.path is not None and self.path != request.path.rstrip("/"): return try: # Test if this is a SOAP request. SOAP 1.1 specifies special # header, SOAP 1.2 special Content-Type soapAction = request.headers["SOAPAction"] import cgi contentType = cgi.parse_header(request.headers["Content-Type"]) if (not soapAction and contentType[0] != "application/soap+xml"): return # Get body data of request body = request.body.read() # Use soaplib to separate header and payload charset = contentType[1].get('charset', None) if charset is None: charset = 'ascii' payload, soapheader = from_soap(body, charset) from soaplib.soap import collapse_swa payload = collapse_swa(contentType, payload) if payload is not None: soapAction = payload.tag for node in payload: six.print_(node) response.headers["Content-Type"] = "text/xml" #value = self.push(SoapOperation(*params), c, t) #value.response = response #value.onSet = ("value_changed", self) except Exception as e: # TODO: r = self._error(1, "%s: %s" % (type(e), e)) return r else: return True
def __call__(self, *args, **kwargs): ''' This method executes the http request to the remote web service. With the exception of 'headers', 'msgid', and 'mtom'; all keyword arguments to this method are put in the http header. The 'headers' keyword is to denote a list of elements to be included in the soap header, 'msgid' is a convenience keyword used in async web services which creates a WS-Addressing messageid header to be included in the soap headers, and 'mtom' enables the Message Transmission Optimization Mechanism. @param the arguments to the remote method @param the keyword arguments ''' if len(args) != len(self.descriptor.inMessage.params): argstring = '\r\n'.join([' ' + str(arg) for arg in args]) paramstring = '\r\n'.join([' ' + str(p[0]) for p in self.descriptor.inMessage.params]) err_msg = _err_format % (argstring, paramstring) raise Exception(err_msg) msg = self.descriptor.inMessage.to_xml(*args) # grab the soap headers passed into this call headers = kwargs.get('headers', []) mtom = kwargs.get('mtom', False) msgid = kwargs.get('msgid') if msgid: # special case for the msgid field as a convenience # when dealing with async callback methods headers.append(create_relates_to_header(msgid)) tns = self.descriptor.inMessage.ns envelope = make_soap_envelope(msg, tns, header_elements=headers) body = ElementTree.tostring(envelope) methodName = '\"%s\"' % self.descriptor.soapAction httpHeaders = {'Content-Length': len(body), 'Content-type': 'text/xml; charset="UTF-8"', 'Accept': ('application/soap+xml, application/dime, ' 'multipart/related, text/*'), 'User-Agent': 'Soaplib/1.0', 'SOAPAction': methodName, } for k, v in kwargs.items(): # add all the other keywords to the http headers if k not in ('headers', 'msgid', 'mtom'): httpHeaders[k] = v if mtom: httpHeaders, body = apply_mtom(httpHeaders, body, self.descriptor.inMessage.params, args) dump(self.host, self.path, httpHeaders, body) if self.scheme == "http": conn = httplib.HTTPConnection(self.host) elif self.scheme == "https": conn = httplib.HTTPSConnection(self.host) else: raise RuntimeError("Unsupported URI connection scheme: %s" % self.scheme) conn.request("POST", self.path, body=body, headers=httpHeaders) response = conn.getresponse() data = response.read() dump(self.host, self.path, dict(response.getheaders()), data) contenttype = response.getheader('Content-Type') data = collapse_swa(contenttype, data) conn.close() if str(response.status) not in['200', '202']: # consider everything NOT 200 or 202 as an error response if str(response.status) == '500': fault = None try: payload, headers = from_soap(data) fault = Fault.from_xml(payload) except: trace = StringIO() import traceback traceback.print_exc(file=trace) fault = Exception("Unable to read response \n" "%s %s \n %s \n %s" % (response.status, response.reason, trace.getvalue(), data)) raise fault else: raise Exception("%s %s" % (response.status, response.reason)) if not self.descriptor.outMessage.params: return payload, headers = from_soap(data) results = self.descriptor.outMessage.from_xml(payload) return results[0]
def __call__(self, environ, start_response, address_url=None): ''' This method conforms to the WSGI spec for callable wsgi applications (PEP 333). It looks in environ['wsgi.input'] for a fully formed soap request envelope, will deserialize the request parameters and call the method on the object returned by the getHandler() method. @param the http environment @param a callable that begins the response message @returns the string representation of the soap call ''' methodname = '' try: reset_request() request.environ = environ # implementation hook self.onCall(environ) serviceName = environ['PATH_INFO'].split('/')[-1] service = self.getHandler(environ) if ((environ['QUERY_STRING'].endswith('wsdl') or environ['PATH_INFO'].endswith('wsdl')) and environ['REQUEST_METHOD'].lower() == 'get'): # get the wsdl for the service # # Assume path_info matches pattern # /stuff/stuff/stuff/serviceName.wsdl or ?WSDL # serviceName = serviceName.split('.')[0] if address_url: url = address_url else: url = reconstruct_url(environ).split('.wsdl')[0] start_response('200 OK', [('Content-type', 'text/xml')]) try: wsdl_content = service.wsdl(url) # implementation hook self.onWsdl(environ, wsdl_content) except Exception, e: # implementation hook buffer = cStringIO.StringIO() traceback.print_exc(file=buffer) buffer.seek(0) stacktrace = str(buffer.read()) faultStr = ElementTree.tostring(make_soap_fault(str(e), detail=stacktrace), encoding=string_encoding) exceptions(faultStr) self.onWsdlException(environ, e, faultStr) # initiate the response start_response('500 Internal Server Error', [('Content-type', 'text/xml'), ('Content-length', str(len(faultStr)))]) return [faultStr] reset_request() return [wsdl_content] if environ['REQUEST_METHOD'].lower() != 'post': start_response('405 Method Not Allowed', [('Allow', 'POST')]) return '' input = environ.get('wsgi.input') length = environ.get("CONTENT_LENGTH") body = input.read(int(length)) methodname = environ.get("HTTP_SOAPACTION") debug('\033[92m'+ methodname +'\033[0m') debug(body) body = collapse_swa(environ.get("CONTENT_TYPE"), body) # deserialize the body of the message try: payload, header = from_soap(body) except SyntaxError, e: payload = None header = None
def __call__(self, environ, start_response, address_url=None): ''' This method conforms to the WSGI spec for callable wsgi applications (PEP 333). It looks in environ['wsgi.input'] for a fully formed soap request envelope, will deserialize the request parameters and call the method on the object returned by the getHandler() method. @param the http environment @param a callable that begins the response message @returns the string representation of the soap call ''' methodname = '' try: reset_request() request.environ = environ # implementation hook self.onCall(environ) serviceName = environ['PATH_INFO'].split('/')[-1] service = self.getHandler(environ) if ((environ['QUERY_STRING'].endswith('wsdl') or environ['PATH_INFO'].endswith('wsdl')) and environ['REQUEST_METHOD'].lower() == 'get'): # get the wsdl for the service # # Assume path_info matches pattern # /stuff/stuff/stuff/serviceName.wsdl or ?WSDL # serviceName = serviceName.split('.')[0] if address_url: url = address_url else: url = reconstruct_url(environ).split('.wsdl')[0] start_response('200 OK', [('Content-type', 'text/xml')]) try: wsdl_content = service.wsdl(url) # implementation hook self.onWsdl(environ, wsdl_content) except Exception, e: # implementation hook buffer = cStringIO.StringIO() traceback.print_exc(file=buffer) buffer.seek(0) stacktrace = str(buffer.read()) faultStr = ElementTree.tostring(make_soap_fault( str(e), detail=stacktrace), encoding=string_encoding) exceptions(faultStr) self.onWsdlException(environ, e, faultStr) # initiate the response start_response('500', [('Content-type', 'text/xml'), ('Content-length', str(len(faultStr)))]) return [faultStr] reset_request() return [wsdl_content] if environ['REQUEST_METHOD'].lower() != 'post': start_response('405 Method Not Allowed', [('Allow', 'POST')]) return '' input = environ.get('wsgi.input') length = environ.get("CONTENT_LENGTH") body = input.read(int(length)) debug(body) body = collapse_swa(environ.get("CONTENT_TYPE"), body) # deserialize the body of the message try: payload, header = from_soap(body) except SyntaxError, e: payload = None header = None
def __call__(self, *args, **kwargs): ''' This method executes the http request to the remote web service. With the exception of 'headers', 'msgid', and 'mtom'; all keyword arguments to this method are put in the http header. The 'headers' keyword is to denote a list of elements to be included in the soap header, 'msgid' is a convenience keyword used in async web services which creates a WS-Addressing messageid header to be included in the soap headers, and 'mtom' enables the Message Transmission Optimization Mechanism. @param the arguments to the remote method @param the keyword arguments ''' if len(args) != len(self.descriptor.inMessage.params): argstring = '\r\n'.join([' ' + str(arg) for arg in args]) paramstring = '\r\n'.join( [' ' + str(p[0]) for p in self.descriptor.inMessage.params]) err_msg = _err_format % (argstring, paramstring) raise Exception(err_msg) msg = self.descriptor.inMessage.to_xml(*args) # grab the soap headers passed into this call headers = kwargs.get('headers', []) mtom = kwargs.get('mtom', False) msgid = kwargs.get('msgid') if msgid: # special case for the msgid field as a convenience # when dealing with async callback methods headers.append(create_relates_to_header(msgid)) tns = self.descriptor.inMessage.ns envelope = make_soap_envelope(msg, tns, header_elements=headers) body = ElementTree.tostring(envelope) methodName = '\"%s\"' % self.descriptor.soapAction httpHeaders = { 'Content-Length': len(body), 'Content-type': 'text/xml; charset="UTF-8"', 'Accept': ('application/soap+xml, application/dime, ' 'multipart/related, text/*'), 'User-Agent': 'Soaplib/1.0', 'SOAPAction': methodName, } for k, v in kwargs.items(): # add all the other keywords to the http headers if k not in ('headers', 'msgid', 'mtom'): httpHeaders[k] = v if mtom: httpHeaders, body = apply_mtom(httpHeaders, body, self.descriptor.inMessage.params, args) dump(self.host, self.path, httpHeaders, body) if self.scheme == "http": conn = httplib.HTTPConnection(self.host) elif self.scheme == "https": conn = httplib.HTTPSConnection(self.host) else: raise RuntimeError("Unsupported URI connection scheme: %s" % self.scheme) conn.request("POST", self.path, body=body, headers=httpHeaders) response = conn.getresponse() data = response.read() dump(self.host, self.path, dict(response.getheaders()), data) contenttype = response.getheader('Content-Type') data = collapse_swa(contenttype, data) conn.close() if str(response.status) not in ['200', '202']: # consider everything NOT 200 or 202 as an error response if str(response.status) == '500': fault = None try: payload, headers = from_soap(data) fault = Fault.from_xml(payload) except: trace = StringIO() import traceback traceback.print_exc(file=trace) fault = Exception("Unable to read response \n" "%s %s \n %s \n %s" % (response.status, response.reason, trace.getvalue(), data)) raise fault else: raise Exception("%s %s" % (response.status, response.reason)) if not self.descriptor.outMessage.params: return payload, headers = from_soap(data) results = self.descriptor.outMessage.from_xml(payload) #TODO: consider supporting multiple return types in a better manner if len(results) > 1: return results return results[0]
def __call__(self, environ, start_response): ''' This method conforms to the WSGI spec for callable wsgi applications (PEP 333). This method looks in environ['wsgi.input'] for a fully formed soap request envelope, will deserialize the request parameters and call the method on the object returned by the getHandler() method. @param the http environment @param a callable that begins the response message @returns the string representation of the soap call ''' methodname = '' try: reset_request() request.environ = environ # implementation hook self.onCall(environ) serviceName = environ['PATH_INFO'].split('/')[-1] service = self.getHandler(environ) if serviceName.lower().endswith('wsdl'): # get the wsdl for the service # # Assume path_info matches pattern # /stuff/stuff/stuff/serviceName.wsdl or ?WSDL # serviceName = serviceName.split('.')[0] url = reconstruct_url(environ).split('.wsdl')[0] start_response('200 OK',[('Content-type','text/xml')]) try: wsdl_content = service.wsdl(url) # implementation hook self.onWsdl(environ,wsdl_content) except Exception, e: # implementation hook buffer = cStringIO.StringIO() traceback.print_exc(file=buffer) buffer.seek(0) stacktrace = str(buffer.read()) faultStr = ElementTree.tostring(make_soap_fault( str(e), detail=stacktrace), encoding=string_encoding) exceptions(faultStr) self.onWsdlException(environ,e,faultStr) # initiate the response start_response('500',[('Content-type','text/xml'),('Content-length',str(len(faultStr)))]) return [faultStr] reset_request() return [wsdl_content] if environ['REQUEST_METHOD'].lower() != 'post': start_response('405 Method Not Allowed',[('Allow','POST')]) return '' input = environ.get('wsgi.input') length = environ.get("CONTENT_LENGTH") body = input.read(int(length)) debug(body) body = collapse_swa( environ.get("CONTENT_TYPE"), body) # deserialize the body of the message payload, header = from_soap(body) if payload: methodname = payload.tag.split('}')[-1] else: # check HTTP_SOAPACTION methodname = environ.get("HTTP_SOAPACTION") if methodname.startswith('"') and methodname.endswith('"'): methodname = methodname[1:-1] request.header = header # call the method func = getattr(service, methodname) # retrieve the method descriptor descriptor = func(_soap_descriptor=True) if payload: params = descriptor.inMessage.from_xml(*[payload]) else: params = () # implementation hook self.onMethodExec(environ,body,params,descriptor.inMessage.params) # call the method retval = func(*params) # transform the results into an element # only expect a single element results = None if not (descriptor.isAsync or descriptor.isCallback): results = descriptor.outMessage.to_xml(*[retval]) # implementation hook self.onResults(environ,results,retval) # grab any headers that were included in the request response_headers = None if hasattr(request,'response_headers'): response_headers = request.response_headers # construct the soap response, and serialize it envelope = make_soap_envelope(results,tns=service.__tns__,header_elements=response_headers) resp = ElementTree.tostring(envelope, encoding=string_encoding) headers = {'Content-Type': 'text/xml'} if descriptor.mtom: headers, resp = apply_mtom( headers, resp, descriptor.outMessage.params, (retval,) ) if environ.has_key('CONTENT_LENGTH'): del(environ['CONTENT_LENGTH']) # initiate the response start_response('200 OK',headers.items()) self.onReturn(environ,resp) debug(resp) # return the serialized results reset_request() return [resp]
def __call__(self, environ, start_response): ''' This method conforms to the WSGI spec for callable wsgi applications (PEP 333). This method looks in environ['wsgi.input'] for a fully formed soap request envelope, will deserialize the request parameters and call the method on the object returned by the getHandler() method. @param the http environment @param a callable that begins the response message @returns the string representation of the soap call ''' methodname = '' try: reset_request() request.environ = environ # implementation hook self.onCall(environ) serviceName = environ['PATH_INFO'].split('/')[-1] service = self.getHandler(environ) if serviceName.lower().endswith('wsdl'): # get the wsdl for the service # # Assume path_info matches pattern # /stuff/stuff/stuff/serviceName.wsdl or ?WSDL # serviceName = serviceName.split('.')[0] url = reconstruct_url(environ).split('.wsdl')[0] start_response('200 OK',[('Content-type','text/xml')]) try: wsdl_content = service.wsdl(url) # implementation hook self.onWsdl(environ,wsdl_content) except Exception, e: # implementation hook buffer = cStringIO.StringIO() traceback.print_exc(file=buffer) buffer.seek(0) stacktrace = str(buffer.read()) faultStr = ElementTree.tostring(make_soap_fault( str(e), detail=stacktrace), encoding=string_encoding) exceptions(faultStr) self.onWsdlException(environ,e,faultStr) # initiate the response start_response('500',[('Content-type','text/xml'),('Content-length',str(len(faultStr)))]) return [faultStr] reset_request() return [wsdl_content] if environ['REQUEST_METHOD'].lower() != 'post': start_response('405 Method Not Allowed',[('Allow','POST')]) return '' input = environ.get('wsgi.input') length = environ.get("CONTENT_LENGTH") body = input.read(int(length)) debug(body) body = collapse_swa( environ.get("CONTENT_TYPE"), body) # deserialize the body of the message payload, header = from_soap(body) methodname = payload.tag.split('}')[-1] request.header = header # call the method func = getattr(service, methodname) # retrieve the method descriptor descriptor = func(_soap_descriptor=True) params = descriptor.inMessage.from_xml(*[payload]) # implementation hook self.onMethodExec(environ,body,params,descriptor.inMessage.params) # call the method retval = func(*params) # transform the results into an element # only expect a single element results = None if not (descriptor.isAsync or descriptor.isCallback): results = descriptor.outMessage.to_xml(*[retval]) # implementation hook self.onResults(environ,results,retval) # grab any headers that were included in the request response_headers = None if hasattr(request,'response_headers'): response_headers = request.response_headers # construct the soap response, and serialize it envelope = make_soap_envelope(results,tns=service.__tns__,header_elements=response_headers) resp = ElementTree.tostring(envelope, encoding=string_encoding) headers = {'Content-Type': 'text/xml'} if descriptor.mtom: headers, resp = apply_mtom( headers, resp, descriptor.outMessage.params, (retval,) ) if environ.has_key('CONTENT_LENGTH'): del(environ['CONTENT_LENGTH']) # initiate the response start_response('200 OK',headers.items()) self.onReturn(environ,resp) debug(resp) # return the serialized results reset_request() return [resp]
def post(self): ''' This method conforms to the WSGI spec for callable wsgi applications (PEP 333). This method looks in environ['wsgi.input'] for a fully formed soap request envelope, will deserialize the request parameters and call the method on the object returned by the getHandler() method. @param the http environment @param a callable that begins the response message @returns the string representation of the soap call ''' methodname = '' container = tornado.wsgi.WSGIContainer(self.application) environ = container.environ(self.request) try: # implementation hook self.onCall(environ) serviceName = environ['PATH_INFO'].split('/')[-1] service = self.getHandler(environ) if (environ['QUERY_STRING'].endswith('wsdl') or environ['PATH_INFO'].endswith('wsdl') ) and environ['REQUEST_METHOD'].lower() == 'get': # get the wsdl for the service # # Assume path_info matches pattern # /stuff/stuff/stuff/serviceName.wsdl or ?WSDL # serviceName = serviceName.split('.')[0] url = reconstruct_url(environ).split('.wsdl')[0] try: wsdl_content = service.wsdl(url) # implementation hook self.onWsdl(environ, wsdl_content) except Exception, e: # implementation hook buffer = cStringIO.StringIO() traceback.print_exc(file=buffer) buffer.seek(0) stacktrace = str(buffer.read()) faultStr = ElementTree.tostring(make_soap_fault( str(e), detail=stacktrace), encoding=string_encoding) exceptions(faultStr) self.onWsdlException(environ, e, faultStr) # initiate the response #return Response(faultStr, '500 Internal Server Error', [('Content-type','text/xml;charset=utf-8')]) self.set_header('Content-Type', 'text/xml;charset=utf-8') return self.write(faultStr) #return Response(wsdl_content, '200 OK', [('Content-type','text/xml;charset=utf-8')]) self.set_header('Content-Type', 'text/xml;charset=utf-8') return self.write(wsdl_content) if environ['REQUEST_METHOD'].lower() != 'post': #return Response('', '405 Method Not Allowed',[('Allow','POST')]) self.set_header('Content-Type', 'text/html;charset=utf-8') return self.write_error(status_code=405) input = environ.get('wsgi.input') length = environ.get("CONTENT_LENGTH") body = input.read(int(length)) debug(body) # body, _unmentioned_attachs = collapse_swa( environ.get("CONTENT_TYPE"), body) # collapse_swa has some problem try: body, _unmentioned_attachs = collapse_swa( environ.get("CONTENT_TYPE"), body) except: body = collapse_swa(environ.get("CONTENT_TYPE"), body) _unmentioned_attachs = [] pass # deserialize the body of the message try: payload, header = from_soap(body) except SyntaxError, e: payload = None header = None
def post(self): ''' This method conforms to the WSGI spec for callable wsgi applications (PEP 333). This method looks in environ['wsgi.input'] for a fully formed soap request envelope, will deserialize the request parameters and call the method on the object returned by the getHandler() method. @param the http environment @param a callable that begins the response message @returns the string representation of the soap call ''' methodname = '' container = tornado.wsgi.WSGIContainer(self.application) environ = container.environ(self.request) try: # implementation hook self.onCall(environ) serviceName = environ['PATH_INFO'].split('/')[-1] service = self.getHandler(environ) if (environ['QUERY_STRING'].endswith('wsdl') or environ['PATH_INFO'].endswith('wsdl')) and environ['REQUEST_METHOD'].lower() == 'get': # get the wsdl for the service # # Assume path_info matches pattern # /stuff/stuff/stuff/serviceName.wsdl or ?WSDL # serviceName = serviceName.split('.')[0] url = reconstruct_url(environ).split('.wsdl')[0] try: wsdl_content = service.wsdl(url) # implementation hook self.onWsdl(environ,wsdl_content) except Exception, e: # implementation hook buffer = cStringIO.StringIO() traceback.print_exc(file=buffer) buffer.seek(0) stacktrace = str(buffer.read()) faultStr = ElementTree.tostring(make_soap_fault( str(e), detail=stacktrace), encoding=string_encoding) exceptions(faultStr) self.onWsdlException(environ,e,faultStr) # initiate the response #return Response(faultStr, '500 Internal Server Error', [('Content-type','text/xml;charset=utf-8')]) self.set_header('Content-Type', 'text/xml;charset=utf-8') return self.write(faultStr) #return Response(wsdl_content, '200 OK', [('Content-type','text/xml;charset=utf-8')]) self.set_header('Content-Type', 'text/xml;charset=utf-8') return self.write(wsdl_content) if environ['REQUEST_METHOD'].lower() != 'post': #return Response('', '405 Method Not Allowed',[('Allow','POST')]) self.set_header('Content-Type', 'text/html;charset=utf-8') return self.write_error(status_code=405) input = environ.get('wsgi.input') length = environ.get("CONTENT_LENGTH") body = input.read(int(length)) debug(body) # body, _unmentioned_attachs = collapse_swa( environ.get("CONTENT_TYPE"), body) # collapse_swa has some problem try: body, _unmentioned_attachs = collapse_swa( environ.get("CONTENT_TYPE"), body) except: body = collapse_swa( environ.get("CONTENT_TYPE"), body) _unmentioned_attachs = [] pass # deserialize the body of the message try: payload, header = from_soap(body) except SyntaxError,e: payload = None header = None