def __call__(self, *args, **kwargs): msg = SoapMessage(self.service.serviceType, self.name) # see it there is an async flag, defaults to False async = bool('async' in kwargs and kwargs.pop('async')) # there may be a starting deferred also; only relevant # if in async mode deferred = (async and 'deferred' in kwargs) and kwargs.pop('deferred') or None # update the message with input argument values for arg in self.inargs: val = kwargs.get(arg.name) if val is None: raise KeyError('Missing IN argument: %s' % (arg.name, )) msg.set_arg(arg.name, val) # send the message result = self._soap_sender(self.service.device, self.service.controlURL, msg, async=async, deferred=deferred) if async: # assume it's a Deferred result.addCallback(decode_soap, self.outargs) return result else: return decode_soap(result, self.outargs)
def send_soap_message(url, msg, mpost=False): """ Send a SOAP message to the given URL. The HTTP headers mandated by the UPnP specification are added. Also, if posting fails with a 405 error, another attempt is made with slightly different headers and method set to M-POST. Return a SoapMessage or a SoapError, depending on the outcome of the call. Raise a urllib2.URLError or a urllib2.HTTPError if something goes wrong. """ req = MPOSTRequest(url) if mpost else urllib2.Request(url) # add headers to the request req.add_header('CONTENT-TYPE', 'text/xml; charset="utf-8"') req.add_header('USER-AGENT', 'OS/1.0 UPnP/1.0 airpnp/1.0') if mpost: req.add_header('MAN', '"http://schemas.xmlsoap.org/soap/envelope/"; ns=01') req.add_header('01-SOAPACTION', msg.get_header()) else: req.add_header('SOAPACTION', msg.get_header()) # add the SOAP message as data req.add_data(msg.tostring().encode("utf-8")) try: handle = urllib2.urlopen(req) response = SoapMessage.parse(handle) except urllib2.HTTPError, err: if err.code == 405 and not mpost: log.msg('Got 405 response in response to SOAP message, trying' + 'the M-POST way', ll=2) return send_soap_message(url, msg, True) elif err.code == 500: # SOAP error response = SoapError.parse(err.read()) else: log.err(err, 'Failed to send SOAP message') raise err