def handle_error(fail): if fail.check(error.Error): err = fail.value status = int(err.status) if not mpost and status == http.NOT_ALLOWED: # new attempt # don't pass the deferred here, because we're already # within the callback/errback chain return send_soap_message_deferred(url, msg, mpost=True) elif status == http.INTERNAL_SERVER_ERROR: # return to the callback chain return SoapError.parse(err.response) log.err(fail, "Failed to send SOAP message to %s" % (url, )) fail.raiseException()
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