示例#1
0
文件: event.py 项目: woogiee/sonospy
    def __init__(self, service, subscription_duration, delivery_url, http_version,
                 event_reload_time, force_event_reload):

        self.service = service
        self.subscription_id = uuid.uuid4()
        self.delivery_url = delivery_url
        url = parse_url(delivery_url)
        self.host = '%s:%d' % (url.hostname, url.port)
        self.event_key = 0
        self.subscription_duration = subscription_duration
        self.http_version = http_version
        self.timestamp = datetime.now()

        self.eventing_variables = {}
        for name, state_var in self.service.get_variables().items():
            state_var.subscribe_for_update(self._update_variable)

        self.force_event_reload = force_event_reload
        if not force_event_reload:
            self.looping_call = LoopingCall(self._send_variables)
            reactor.add_after_stop_func(self.looping_call.stop)
            self.looping_call.start(event_reload_time, False)

        sid = str(self.subscription_id)
        log.debug('Creating subscriber with subscription id: %s' % sid)
示例#2
0
    def __init__(self, service, event_host, callback, cargo):
        """ Constructor for the UnsubscribeRequest class.

        @param service: service that is unsubscribing
        @param event_host: 2-tuple (host, port) of the event listener server
        @param callback: callback
        @param cargo: callback parameters

        @type service: Service
        @type event_host: tuple
        @type callback: callable
        """
        self.old_sid = service.event_sid
        service.event_sid = ""
        service.event_timeout = 0

        self.callback = callback
        self.cargo = cargo
        self.service = service

        addr = "%s%s" % (service.url_base, service.event_sub_url)
        Paddr = parse_url(addr)

        headers = {}
        headers["User-agent"] = 'BRISA-CP'
        headers["HOST"] = '%s:%d' % (Paddr.hostname, Paddr.port)
        headers["SID"] = self.old_sid

        run_async_call(http_call,
                       success_callback=self.response,
                       error_callback=self.error,
                       delay=0,
                       method='UNSUBSCRIBE',
                       url=addr,
                       headers=headers)
示例#3
0
    def __init__(self, service, event_host, callback, cargo):
        """ Constructor for the SubscribeRequest class.

        @param service: service that is subscribing
        @param event_host: 2-tuple (host, port) of the event listener server
        @param callback: callback
        @param cargo: callback parameters

        @type service: Service
        @type event_host: tuple
        @type callback: callable
        """
        log.debug("subscribe")
        self.callback = callback
        self.cargo = cargo
        self.service = service

        addr = "%s%s" % (service.url_base, service.event_sub_url)
        Paddr = parse_url(addr)

        headers = {}
        #        headers["Host"] = Paddr.hostname
        headers["User-agent"] = 'BRisa UPnP Framework'
        headers["TIMEOUT"] = 'Second-1800'
        headers["NT"] = 'upnp:event'
        headers["CALLBACK"] = "<http://%s:%d/eventSub>" % event_host
        headers["HOST"] = '%s:%d' % (Paddr.hostname, Paddr.port)

        run_async_call(http_call,
                       success_callback=self.response,
                       error_callback=self.error,
                       delay=0,
                       method='SUBSCRIBE',
                       url=addr,
                       headers=headers)
示例#4
0
def getAlbumArt(service, AlbumArtURI):

#TODO: display a "getting album art" graphic until art is updated

#    log.debug('#### GETALBUMART service: %s' % service)
#    log.debug('#### GETALBUMART AlbumArtURI: %s' % AlbumArtURI)

    if AlbumArtURI == '' or AlbumArtURI == None:
        return (None, "No albumart to display")
    else:
        url_info = parse_url(service.url_base)
#        log.debug('#### GETALBUMART url_info: %s' % str(url_info))
        aa_url = "%s://%s%s" % (url_info[0], url_info[1], AlbumArtURI)
#        log.debug('#### GETALBUMART control_url: %s' % aa_url)
        try:
            fd = url_fetch(aa_url)
#        except HTTPError as detail:
        except HTTPError:
            return (None, HTTPError)

        try:
            data = fd.read()
        except:
            log.debug("#### GETALBUMART fd is invalid")
            return (None, "Error getting albumArt")

        pbl = gtk.gdk.PixbufLoader()
        pbl.write(data)
        pbuf = pbl.get_pixbuf()
#        print "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
#        print pbl.get_format()
#        print "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
        pbl.close()

        return (pbuf, '')
示例#5
0
    def _parse_device(self):
        self.device.device_type = self.tree.\
                                     findtext('.//{%s}deviceType' % self.ns)
        self.device.friendly_name = self.tree.\
                                  findtext('.//{%s}friendlyName' % self.ns)
        self.device.manufacturer = self.tree.\
                                     findtext('.//{%s}manufacturer' % self.ns)
        self.device.manufacturer_url = self.tree.\
                                 findtext('.//{%s}manufacturerURL' % self.ns)
        self.device.model_description = self.tree.\
                              findtext('.//{%s}modelDescription' % self.ns)
        self.device.model_name = self.tree.\
                                   findtext('.//{%s}modelName' % self.ns)
        self.device.model_number = self.tree.\
                                     findtext('.//{%s}modelNumber' % self.ns)
        self.device.model_url = self.tree.\
                                  findtext('.//{%s}modelURL' % self.ns)
        self.device.serial_number = self.tree.\
                                  findtext('.//{%s}serialNumber' % self.ns)
        self.device.udn = self.tree.findtext('.//{%s}UDN' % self.ns)
        self.device.upc = self.tree.findtext('.//{%s}UPC' % self.ns)
        self.device.presentation_url = self.tree.\
                                 findtext('.//{%s}presentationURL' % self.ns)

        self.device.location = self.location
        addr = parse_url(self.location)
        self.device.address = '%s://%s:%d' % (addr.scheme, addr.hostname, addr.port)
        self.device.scheme = addr.scheme
        self.device.ip = addr.hostname
        self.device.port = addr.port
示例#6
0
    def __init__(self, service, event_host, callback, cargo):
        """ Constructor for the SubscribeRequest class.

        @param service: service that is subscribing
        @param event_host: 2-tuple (host, port) of the event listener server
        @param callback: callback
        @param cargo: callback parameters

        @type service: Service
        @type event_host: tuple
        @type callback: callable
        """
        log.debug("subscribe")
        self.callback = callback
        self.cargo = cargo
        self.service = service

        addr = "%s%s" % (service.url_base, service.event_sub_url)
        Paddr = parse_url(addr)

        headers = {}
        headers["User-agent"] = 'BRisa UPnP Framework'
        headers["TIMEOUT"] = 'Second-300'
        headers["NT"] = 'upnp:event'
        headers["CALLBACK"] = "<http://%s:%d/eventSub>" % event_host
        headers["HOST"] = '%s:%d' % (Paddr.hostname, Paddr.port)

        run_async_call(http_call, success_callback=self.response,
                       error_callback=self.error, delay=0,
                       method='SUBSCRIBE', url=addr,
                       headers=headers)
示例#7
0
    def __init__(self, service, event_host, callback, cargo):
        """ Constructor for the UnsubscribeRequest class.

        @param service: service that is unsubscribing
        @param event_host: 2-tuple (host, port) of the event listener server
        @param callback: callback
        @param cargo: callback parameters

        @type service: Service
        @type event_host: tuple
        @type callback: callable
        """
        self.old_sid = service.event_sid
        service.event_sid = ""
        service.event_timeout = 0

        self.callback = callback
        self.cargo = cargo
        self.service = service

        addr = "%s%s" % (service.url_base, service.event_sub_url)
        Paddr = parse_url(addr)

        headers = {}
        headers["User-agent"] = 'BRISA-CP'
        headers["HOST"] = '%s:%d' % (Paddr.hostname, Paddr.port)
        headers["SID"] = self.old_sid

        run_async_call(http_call, success_callback=self.response,
                       error_callback=self.error, delay=0,
                       method='UNSUBSCRIBE', url=addr, headers=headers)
示例#8
0
    def _parse_device(self):
        self.device.device_type = self.tree.\
                                     findtext('.//{%s}deviceType' % self.ns)
        self.device.friendly_name = self.tree.\
                                  findtext('.//{%s}friendlyName' % self.ns)
        self.device.manufacturer = self.tree.\
                                     findtext('.//{%s}manufacturer' % self.ns)
        self.device.manufacturer_url = self.tree.\
                                 findtext('.//{%s}manufacturerURL' % self.ns)
        self.device.model_description = self.tree.\
                              findtext('.//{%s}modelDescription' % self.ns)
        self.device.model_name = self.tree.\
                                   findtext('.//{%s}modelName' % self.ns)
        self.device.model_number = self.tree.\
                                     findtext('.//{%s}modelNumber' % self.ns)
        self.device.model_url = self.tree.\
                                  findtext('.//{%s}modelURL' % self.ns)
        self.device.serial_number = self.tree.\
                                  findtext('.//{%s}serialNumber' % self.ns)
        self.device.udn = self.tree.findtext('.//{%s}UDN' % self.ns)
        self.device.upc = self.tree.findtext('.//{%s}UPC' % self.ns)
        self.device.presentation_url = self.tree.\
                                 findtext('.//{%s}presentationURL' % self.ns)

        self.device.location = self.location
        addr = parse_url(self.location)
        self.device.address = '%s://%s:%d' % (addr.scheme, addr.hostname,
                                              addr.port)
        self.device.scheme = addr.scheme
        self.device.ip = addr.hostname
        self.device.port = addr.port
示例#9
0
    def __init__(self, service, event_host, callback, cargo):
        """ Constructor for the RenewSubscribeRequest class.

        @param service: service that is renewing the subscribe
        @param event_host: 2-tuple (host, port) of the event listener server
        @param callback: callback
        @param cargo: callback parameters

        @type service: Service
        @type event_host: tuple
        @type callback: callable
        """
        log.debug("renew subscribe")

        if not service.event_sid or service.event_sid == "":
            return

        self.callback = callback
        self.cargo = cargo
        self.service = service

        addr = "%s%s" % (service.url_base, service.event_sub_url)
        Paddr = parse_url(addr)

        headers = {}
        headers["HOST"] = '%s:%d' % (Paddr.hostname, Paddr.port)
        headers["SID"] = self.service.event_sid
        headers["TIMEOUT"] = 'Second-300'

        run_async_call(http_call, success_callback=self.response,
                       error_callback=self.error, delay=0,
                       method='SUBSCRIBE', url=addr,
                       headers=headers)
示例#10
0
文件: device.py 项目: jimmy2e/Sonar
    def _create_webserver(self, force_listen_url=''):
        if force_listen_url:
            p = network.parse_url(force_listen_url)
            self.webserver = webserver.WebServer(host=p.hostname, port=p.port)
        else:
            self.webserver = webserver.WebServer()

        self.location = self.webserver.get_listen_url()
示例#11
0
    def _create_webserver(self, force_listen_url=''):
        if force_listen_url:
            p = network.parse_url(force_listen_url)
            self.webserver = webserver.WebServer(host=p.hostname, port=p.port)
        else:
            self.webserver = webserver.WebServer()

        self.location = self.webserver.get_listen_url()
示例#12
0
def getAlbumArtURL(service, albumartURI):

    if albumartURI == '' or albumartURI == None or albumartURI == []:
        return ''
    else:
        art_url = urlparse(albumartURI)
        if art_url.scheme != '' and art_url.netloc != '' and art_url.path != '':
            return albumartURI
        url_info = parse_url(service.url_base)
        aa_url = "%s://%s%s" % (url_info[0], url_info[1], albumartURI)
        return aa_url
示例#13
0
def getAlbumArtURL(service, albumartURI):

    if albumartURI == '' or albumartURI == None or albumartURI == []:
        return ''
    else:
        art_url = urlparse(albumartURI)
        if art_url.scheme != '' and art_url.netloc != '' and art_url.path != '':
            return albumartURI
        url_info = parse_url(service.url_base)
        aa_url = "%s://%s%s" % (url_info[0], url_info[1], albumartURI)
        return aa_url
示例#14
0
    def get_music_services(self):
        """
        """
        service = self.get_ms_service()
        service_response = service.ListAvailableServices()

        if 'AvailableServiceDescriptorList' in service_response:
        
            '''
				<Services>
					<Service Capabilities="31" Id="0" MaxMessagingChars="0" Name="Napster" SecureUri="https://api.napster.com/device/soap/v1" Uri="http://api.napster.com/device/soap/v1" Version="1.0">
						<Policy Auth="UserId" PollInterval="30"/>
						<Presentation>
							<Strings Uri="http://update-services.sonos.com/services/napster/string.xml" Version="1"/>
							<Logos Large="http://www.napster.com/services/Sonos/LargeLogo.png" Small="http://www.napster.com/services/Sonos/SmallLogo.png"/>
						</Presentation>
					</Service>
					<Service Capabilities="0" Id="254" MaxMessagingChars="0" Name="RadioTime" SecureUri="http://legato.radiotime.com/Radio.asmx" Uri="http://legato.radiotime.com/Radio.asmx" Version="1.1">
						<Policy Auth="Anonymous" PollInterval="0"/>
						<Presentation/>
					</Service>
					<Service Capabilities="19" Id="2" MaxMessagingChars="0" Name="Deezer" SecureUri="https://moapi.sonos.com/Deezer/SonosAPI.php" Uri="http://moapi.sonos.com/Deezer/SonosAPI.php" Version="1.1">
						<Policy Auth="UserId" PollInterval="60"/>
						<Presentation/>
					</Service>
				</Services>

            '''

            elt = AvailableServices().from_string(service_response['AvailableServiceDescriptorList'])
            service_response['AvailableServiceDescriptorList'] = elt.get_items()

            for item in service_response['AvailableServiceDescriptorList']:
                # manually create Sonos specific add-on services
                
                serviceversion = 'http://www.sonos.com/Services/' + item.Version

                # TODO: fix params so they are fully dynamic
                
                if item.Name == 'RadioTime':
                    addr = parse_url(item.Uri)
                    port = 80 if addr.port == None else addr.port
                    url_base = '%s://%s:%s' % (addr.scheme, addr.hostname, port)
                    self.rt_service = Service('getMetadata', serviceversion, 
                                               url_base=url_base,
                                               control_url=addr.path,
                                               scpd_url='file:///radiotime-scpd.xml',
                                               build=True)
                elif item.Name == 'Napster':
                    self.np_service = napster(item.SecureUri, item.Uri, serviceversion)
            
        return service_response        
示例#15
0
    def getscpdurl(self, location):
        '''
        Gets the scpd url from a url specifying the device xml location
        '''
        addr = parse_url(location)
        base_url = '%s://%s' % (addr.scheme, addr.netloc)
#        print "---> base_url: " + str(base_url)
        filecontent = url_fetch(location)
        if not filecontent:
            return None
        tree = ElementTree(file=filecontent).getroot()
        for device in tree.findall('{urn:schemas-upnp-org:device-1-0}device'):
            for xml_service_element in device.findall('.//{urn:schemas-upnp-org:device-1-0}service'):
                service_type = xml_service_element.findtext('{urn:schemas-upnp-org:device-1-0}serviceType')
                if service_type == 'urn:schemas-upnp-org:service:ContentDirectory:1':
                    scpd_url = xml_service_element.findtext('{urn:schemas-upnp-org:device-1-0}SCPDURL')
                    if not scpd_url.startswith('/'):
                        scpd_url = '/' + scpd_url
                    scpd_url = base_url + scpd_url
                    return scpd_url
        return None        
示例#16
0
def getAlbumArtFile(service, AlbumArtURI, filename):

    #    log.debug('#### GETALBUMART service: %s' % service)
    #    log.debug('#### GETALBUMART AlbumArtURI: %s' % AlbumArtURI)

    if AlbumArtURI == '' or AlbumArtURI == None:
        return False
    else:
        url_info = parse_url(service.url_base)
        aa_url = "%s://%s%s" % (url_info[0], url_info[1], AlbumArtURI)
        #        log.debug('#### GETALBUMART control_url: %s' % aa_url)
        fd = url_fetch(aa_url)
        try:
            data = fd.read()
        except:
            log.debug("#### GETALBUMART fd is invalid")
            data = ''

    fdout = open(filename, "w")
    fdout.write(data)
    fdout.close()

    return True
示例#17
0
def getAlbumArtFile(service, AlbumArtURI, filename):

#    log.debug('#### GETALBUMART service: %s' % service)
#    log.debug('#### GETALBUMART AlbumArtURI: %s' % AlbumArtURI)

    if AlbumArtURI == '' or AlbumArtURI == None:
        return False
    else:
        url_info = parse_url(service.url_base)
        aa_url = "%s://%s%s" % (url_info[0], url_info[1], AlbumArtURI)
#        log.debug('#### GETALBUMART control_url: %s' % aa_url)
        fd = url_fetch(aa_url)
        try:
            data = fd.read()
        except:
            log.debug("#### GETALBUMART fd is invalid")
            data = ''

    fdout = open(filename,"w")
    fdout.write(data)
    fdout.close()

    return True
示例#18
0
    def __init__(self, service, event_host, callback, cargo):
        """ Constructor for the RenewSubscribeRequest class.

        @param service: service that is renewing the subscribe
        @param event_host: 2-tuple (host, port) of the event listener server
        @param callback: callback
        @param cargo: callback parameters

        @type service: Service
        @type event_host: tuple
        @type callback: callable
        """
        log.debug("renew subscribe")

        if not service.event_sid or service.event_sid == "":
            return

        self.callback = callback
        self.cargo = cargo
        self.service = service

        addr = "%s%s" % (service.url_base, service.event_sub_url)
        Paddr = parse_url(addr)

        headers = {}
        headers["HOST"] = '%s:%d' % (Paddr.hostname, Paddr.port)
        headers["SID"] = self.service.event_sid
        headers["TIMEOUT"] = 'Second-1800'

        run_async_call(http_call,
                       success_callback=self.response,
                       error_callback=self.error,
                       delay=0,
                       method='SUBSCRIBE',
                       url=addr,
                       headers=headers)
示例#19
0
文件: soap.py 项目: michaelnt/sonospy
    def call(self, addr, data, namespace, soapaction=None, encoding=None):
        """ Builds and performs an HTTP request. Returns the response payload.

        @param addr: address to receive the request in the form
        schema://hostname:port
        @param data: data to be sent
        @param soapaction: soap action to be called
        @param encoding: encoding for the message

        @type addr: string
        @type data: string
        @type soapaction: string
        @type encoding: string

        @return: response payload
        @rtype: string
        """

        log.debug('#### HTTPTransport call - addr : %s' % str(addr))
        log.debug('#### HTTPTransport call - data : %s' % str(data))
        log.debug('#### HTTPTransport call - namespace : %s' % str(namespace))
        log.debug('#### HTTPTransport call - soapaction : %s' % str(soapaction))
        log.debug('#### HTTPTransport call - encoding : %s' % str(encoding))

        # Build a request
        
        '''
        addr : http://legato.radiotime.com:80
        data : <?xml version="1.0" encoding="utf-8"?><s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Header><credentials xmlns="http://www.sonos.com/Services/1.1"><deviceProvider>Sonos</deviceProvider></credentials></s:Header><s:Body><ns0:getMetadata xmlns:ns0="http://www.sonos.com/Services/1.1"><count>100</count><index>0</index><recursive>false</recursive><id>root</id></ns0:getMetadata></s:Body></s:Envelope>
        namespace : ('u', 'http://www.sonos.com/Services/1.1')
        soapaction : http://www.sonos.com/Services/1.1#getMetadata
        encoding : utf-8
        real_addr : legato.radiotime.com:80
        real_path : 
        addr.scheme : http
        addr.hostname : legato.radiotime.com

        POST /Radio.asmx HTTP/1.1
        CONNECTION: close
        ACCEPT-ENCODING: gzip
        HOST: legato.radiotime.com
        USER-AGENT: Linux UPnP/1.0 Sonos/11.7-19141a
        CONTENT-LENGTH: 337
        CONTENT-TYPE: text/xml; charset="utf-8"
        ACCEPT-LANGUAGE: en-US
        SOAPACTION: "http://www.sonos.com/Services/1.1#getMetadata"
        '''
        # TODO: tidy up parameters, use saved params from musicservices call, change to gzip
        addr = parse_url(addr)
        real_addr = '%s:%d' % (addr.hostname, addr.port)
        real_path = addr.path

        if addr.scheme == 'https':
            r = httplib.HTTPSConnection(real_addr)
        else:
            r = httplib.HTTPConnection(real_addr)

        log.debug('#### HTTPTransport call - real_addr : %s' % real_addr)
        log.debug('#### HTTPTransport call - real_path : %s' % real_path)
        log.debug('#### HTTPTransport call - addr.scheme : %s' % addr.scheme)
        log.debug('#### HTTPTransport call - addr.hostname : %s' % addr.hostname)

        r.putrequest("POST", real_path, skip_host=1, skip_accept_encoding=1)
        
        r.putheader("ACCEPT-ENCODING", 'gzip')
        r.putheader("CONNECTION", 'close')

        r.putheader("HOST", addr.hostname)
        r.putheader("USER-AGENT", 'Linux UPnP/1.0 Sonos/11.7-19141a')
        t = 'text/xml'
        if encoding:
            t += '; charset="%s"' % encoding
            
            
        r.putheader("CONTENT-TYPE", t)
#        r.putheader("ACCEPT-CHARSET", 'ISO-8859-1,utf-8;q=0.7,*;q=0.7')
        r.putheader("ACCEPT-LANGUAGE", 'en-US')
        r.putheader("CONTENT-LENGTH", str(len(data)))


        # if user is not a user:passwd format
        if addr.username != None:
            val = base64.encodestring(addr.user)
            r.putheader('Authorization', 'Basic ' + val.replace('\012', ''))

        # This fixes sending either "" or "None"
        if soapaction:
            r.putheader("SOAPACTION", '"%s"' % soapaction)
        else:
            r.putheader("SOAPACTION", "")

        r.endheaders()

        log.debug('#### HTTP BEFORE r.send ################################')

        r.send(data)

        log.debug('#### HTTP AFTER r.send ################################')

        #read response line
#        code, msg, headers = r.getreply()
        response = r.getresponse()
        code = response.status
        msg = response.reason
        headers = response.msg

        log.debug('#### HTTP AFTER START #################################')
        log.debug('#### HTTP code        : %s' % str(code))
        log.debug('#### HTTP msg         : %s' % str(msg))
        log.debug('#### HTTP headers     : %s' % str(headers))
        log.debug('#### HTTP AFTER END ###################################')

        content_type = headers.get("content-type", "text/xml")
        content_length = headers.get("Content-length")
        if content_length == None:
#            data = r.getfile().read()
            data = response.read()
            message_len = len(data)
        else:
            message_len = int(content_length)
#            data = r.getfile().read(message_len)
            data = response.read(message_len)

        def startswith(string, val):
            return string[0:len(val)] == val


        if code == 500 and not \
               (startswith(content_type, "text/xml") and message_len > 0):
            raise HTTPError(code, msg)

        if code not in (200, 500):
            raise HTTPError(code, msg)

        import StringIO
        stream = StringIO.StringIO(data)
        import gzip
        gzipper = gzip.GzipFile(fileobj=stream)
        data = gzipper.read()

        # TODO: use the content-type charset to convert the data returned

        #return response payload
        # NAS is sending some non utf-8 data - TODO: fix NAS rather than decoding for all types which is redundant
        try:
            d = data.decode('utf-8', 'replace')
        except UnicodeDecodeError:
            print "UnicodeDecodeError"
            return data
            
        log.debug('#### HTTP data        : %s' % d)
            
        return d
示例#20
0
    def call(self, addr, environ, start_response):
        """ Builds and performs an HTTP request. Returns the response payload.

        @param addr: address to receive the request in the form
            schema://hostname:port
        @type addr: string

        @return: response payload
        @rtype: string
        """

        log.debug('#### HTTPProxy call - addr : %s' % str(addr))

        # Build a request
        addr = parse_url(addr)
        real_addr = '%s:%d' % (addr.hostname, addr.port)
        real_path = addr.path

        if addr.query:
            real_path += '?' + addr.query

        if addr.scheme == 'https':
            r = httplib.HTTPSConnection(real_addr)
        else:
            r = httplib.HTTPConnection(real_addr)

        log.debug('#### HTTPProxy call - real_addr : %s' % real_addr)
        log.debug('#### HTTPProxy call - real_path : %s' % real_path)
        log.debug('#### HTTPProxy call - addr.scheme : %s' % addr.scheme)
        log.debug('#### HTTPProxy call - addr.hostname : %s' % addr.hostname)

        headers = {}
        for key, value in environ.items():
            if key.startswith('HTTP_'):
                key = key[5:].lower().replace('_', '-')
                if key == 'host':
                    continue
                headers[key] = value

        headers['host'] = real_addr

        log.debug('#### HTTPProxy headers: %s' % str(headers))

        if 'range' in headers:
            # second request, return everything
            send_all = True
        else:
            send_all = False

        if 'REMOTE_ADDR' in environ:
            headers['x-forwarded-for'] = environ['REMOTE_ADDR']
        if environ.get('CONTENT_TYPE'):
            headers['content-type'] = environ['CONTENT_TYPE']
        if environ.get('CONTENT_LENGTH'):
            headers['content-length'] = environ['CONTENT_LENGTH'] 
            length = int(environ['CONTENT_LENGTH'])
            body = environ['wsgi.input'].read(length)
        else:
            body = ''

        path_info = urllib.quote(environ['PATH_INFO'])
        if real_path:            
            request_path = path_info
            if request_path[0] == '/':
                request_path = request_path[1:]
            path = urlparse.urljoin(real_path, request_path)
        else:
            path = path_info
        if environ.get('QUERY_STRING'):
            path += '?' + environ['QUERY_STRING']

        log.debug('#### HTTPProxy BEFORE r.request ################################')

        r.request(environ['REQUEST_METHOD'], path, body, headers)

        log.debug('#### HTTPProxy BEFORE r.getresponse ################################')
        
        res = r.getresponse()

        log.debug('#### HTTPProxy AFTER r.getresponse ################################')

        log.debug('#### HTTPProxy AFTER r.getresponse res: %s', res)

        headers_out = parse_headers(res.msg)

        log.debug('#### HTTPProxy headers_out: %s' % str(headers_out))

        status = '%s %s' % (res.status, res.reason)

        log.debug('#### HTTPProxy status: %s' % str(status))

        start_response(status, headers_out)     # this is for the original GET from the ZP

        if send_all:
#            length = 1000000
            length = res.getheader('content-length')
        else:
            length = 400000
            
        if length is not None:
            body = res.read(int(length))
        else:
            body = res.read()
        r.close()

        # TODO: decode utf-8
        return body
示例#21
0
def parse_base_url(url):
    if url == '':
        return ''
    parsed = parse_url(url)
    return '%s://%s' % (parsed[0], parsed[1])
示例#22
0
def parse_base_url(url):
    parsed = parse_url(url)
    return '%s://%s' % (parsed[0], parsed[1])
示例#23
0
def parse_base_url(url):
    if url == '':
        return ''
    parsed = parse_url(url)
    return '%s://%s' % (parsed[0], parsed[1])
示例#24
0
文件: soap.py 项目: michaelnt/sonospy
    def call(self, addr, environ, start_response):
        """ Builds and performs an HTTP request. Returns the response payload.

        @param addr: address to receive the request in the form
            schema://hostname:port
        @type addr: string

        @return: response payload
        @rtype: string
        """

        log.debug('#### HTTPProxy call - addr : %s' % str(addr))

        # Build a request
        addr = parse_url(addr)
        real_addr = '%s:%d' % (addr.hostname, addr.port)
        real_path = addr.path

        if addr.query:
            real_path += '?' + addr.query

        if addr.scheme == 'https':
            r = httplib.HTTPSConnection(real_addr)
        else:
            r = httplib.HTTPConnection(real_addr)

        log.debug('#### HTTPProxy call - real_addr : %s' % real_addr)
        log.debug('#### HTTPProxy call - real_path : %s' % real_path)
        log.debug('#### HTTPProxy call - addr.scheme : %s' % addr.scheme)
        log.debug('#### HTTPProxy call - addr.hostname : %s' % addr.hostname)

        headers = {}
        for key, value in environ.items():
            if key.startswith('HTTP_'):
                key = key[5:].lower().replace('_', '-')
                if key == 'host':
                    continue
                headers[key] = value

        headers['host'] = real_addr

        log.debug('#### HTTPProxy headers: %s' % str(headers))

        if 'range' in headers:
            # second request, return everything
            send_all = True
        else:
            send_all = False

        if 'REMOTE_ADDR' in environ:
            headers['x-forwarded-for'] = environ['REMOTE_ADDR']
        if environ.get('CONTENT_TYPE'):
            headers['content-type'] = environ['CONTENT_TYPE']
        if environ.get('CONTENT_LENGTH'):
            headers['content-length'] = environ['CONTENT_LENGTH'] 
            length = int(environ['CONTENT_LENGTH'])
            body = environ['wsgi.input'].read(length)
        else:
            body = ''

        path_info = urllib.quote(environ['PATH_INFO'])
        if real_path:            
            request_path = path_info
            if request_path[0] == '/':
                request_path = request_path[1:]
            path = urlparse.urljoin(real_path, request_path)
        else:
            path = path_info
        if environ.get('QUERY_STRING'):
            path += '?' + environ['QUERY_STRING']

        log.debug('#### HTTPProxy BEFORE r.request ################################')

        r.request(environ['REQUEST_METHOD'], path, body, headers)

        log.debug('#### HTTPProxy BEFORE r.getresponse ################################')
        
        res = r.getresponse()

        log.debug('#### HTTPProxy AFTER r.getresponse ################################')

        log.debug('#### HTTPProxy AFTER r.getresponse res: %s', res)

        headers_out = parse_headers(res.msg)

        log.debug('#### HTTPProxy headers_out: %s' % str(headers_out))

        status = '%s %s' % (res.status, res.reason)

        log.debug('#### HTTPProxy status: %s' % str(status))

        start_response(status, headers_out)     # this is for the original GET from the ZP

        if send_all:
#            length = 1000000
            length = res.getheader('content-length')
        else:
            length = 400000
            
        if length is not None:
            body = res.read(int(length))
        else:
            body = res.read()
        r.close()

        # TODO: decode utf-8
        return body
示例#25
0
    def call(self, addr, data, namespace, soapaction=None, encoding=None):
        """ Builds and performs an HTTP request. Returns the response payload.

        @param addr: address to receive the request in the form
        schema://hostname:port
        @param data: data to be sent
        @param soapaction: soap action to be called
        @param encoding: encoding for the message

        @type addr: string
        @type data: string
        @type soapaction: string
        @type encoding: string

        @return: response payload
        @rtype: string
        """
        # Build a request
        addr = parse_url(addr)
        real_addr = '%s:%d' % (addr.hostname, addr.port)
        real_path = addr.path
        if addr.query != '':
            real_path += '?%s' % addr.query

        if addr.scheme == 'https':
            r = httplib.HTTPS(real_addr)
        else:
            r = httplib.HTTP(real_addr)

        r.putrequest("POST", real_path)
        r.putheader("Host", addr.hostname)
        r.putheader("User-agent", USER_AGENT)
        t = 'text/xml'
        if encoding:
            t += '; charset="%s"' % encoding
        r.putheader("Content-type", t)
        r.putheader("Content-length", str(len(data)))

        # if user is not a user:passwd format
        if addr.username != None:
            val = base64.encodestring(addr.user)
            r.putheader('Authorization', 'Basic ' + val.replace('\012', ''))

        # This fixes sending either "" or "None"
        if soapaction:
            r.putheader("SOAPAction", '"%s"' % soapaction)
        else:
            r.putheader("SOAPAction", "")

        r.endheaders()
        r.send(data)

        #read response line
        code, msg, headers = r.getreply()

        content_type = headers.get("content-type", "text/xml")
        content_length = headers.get("Content-length")
        if content_length == None:
            data = r.getfile().read()
            message_len = len(data)
        else:
            message_len = int(content_length)
            data = r.getfile().read(message_len)

        def startswith(string, val):
            return string[0:len(val)] == val


        if code == 500 and not \
               (startswith(content_type, "text/xml") and message_len > 0):
            raise HTTPError(code, msg)

        if code not in (200, 500):
            raise HTTPError(code, msg)

        #return response payload
        return data.decode('utf-8')
示例#26
0
    def call(self, addr, data, namespace, soapaction=None, encoding=None):
        """ Builds and performs an HTTP request. Returns the response payload.

        @param addr: address to receive the request in the form
        schema://hostname:port
        @param data: data to be sent
        @param soapaction: soap action to be called
        @param encoding: encoding for the message

        @type addr: string
        @type data: string
        @type soapaction: string
        @type encoding: string

        @return: response payload
        @rtype: string
        """
        # Build a request
        addr = parse_url(addr)
        real_addr = '%s:%d' % (addr.hostname, addr.port)
        real_path = addr.path
        if addr.query != '':
            real_path += '?%s' % addr.query

        if addr.scheme == 'https':
            r = httplib.HTTPS(real_addr)
        else:
            r = httplib.HTTP(real_addr)

        r.putrequest("POST", real_path)
        r.putheader("Host", addr.hostname)
        r.putheader("User-agent", 'BRISA SERVER')
        t = 'text/xml'
        if encoding:
            t += '; charset="%s"' % encoding
        r.putheader("Content-type", t)
        r.putheader("Content-length", str(len(data)))

        # if user is not a user:passwd format
        if addr.username != None:
            val = base64.encodestring(addr.user)
            r.putheader('Authorization', 'Basic ' + val.replace('\012', ''))

        # This fixes sending either "" or "None"
        if soapaction:
            r.putheader("SOAPAction", '"%s"' % soapaction)
        else:
            r.putheader("SOAPAction", "")

        r.endheaders()
        r.send(data)

        #read response line
        code, msg, headers = r.getreply()

        content_type = headers.get("content-type", "text/xml")
        content_length = headers.get("Content-length")
        if content_length == None:
            data = r.getfile().read()
            message_len = len(data)
        else:
            message_len = int(content_length)
            data = r.getfile().read(message_len)

        def startswith(string, val):
            return string[0:len(val)] == val


        if code == 500 and not \
               (startswith(content_type, "text/xml") and message_len > 0):
            raise HTTPError(code, msg)

        if code not in (200, 500):
            raise HTTPError(code, msg)

        #return response payload
        return data.decode('utf-8')
示例#27
0
文件: soap.py 项目: michaelnt/sonospy
    def call(self, addr, data, namespace, soapaction=None, encoding=None):
        """ Builds and performs an HTTP request. Returns the response payload.

        @param addr: address to receive the request in the form
        schema://hostname:port
        @param data: data to be sent
        @param soapaction: soap action to be called
        @param encoding: encoding for the message

        @type addr: string
        @type data: string
        @type soapaction: string
        @type encoding: string

        @return: response payload
        @rtype: string
        """

        log.debug('#### HTTPTransport call - addr : %s' % str(addr))
        log.debug('#### HTTPTransport call - data : %s' % str(data))
        log.debug('#### HTTPTransport call - namespace : %s' % str(namespace))
        log.debug('#### HTTPTransport call - soapaction : %s' % str(soapaction))
        log.debug('#### HTTPTransport call - encoding : %s' % str(encoding))

        # Build a request
        addr = parse_url(addr)
        real_addr = '%s:%d' % (addr.hostname, addr.port)
        real_path = addr.path

        if addr.query:
        
            # Windows based media servers tend to use the query element of the address to hold connection information
            # TODO: standardise this code and only do the conversions for MS media player

            real_path += '?' + addr.query

            if data and soapaction.endswith('IsAuthorized'):

                # HACK - MS MP (check whether this is really the case)

                data = data.replace('<DeviceID />', '<DeviceID>""</DeviceID>')
                print "data after: " + data

            if data and soapaction.endswith('Browse'):

                # HACK - MS MP doesn't seem to like ObjectID element not being first in list
                # Actually seems to like a specific order (e.g. if req count is before starting index it doesn't bring anything back -
                # I guess because the index is after the end of the number it found)

                before = re.search('.*<ns[0-9]?:Browse[^>]*>', data)
                after = re.search('</ns[0-9]?:Browse>.*', data)
                objectid = re.search('<ObjectID>.*</ObjectID>', data)
                browseflag = re.search('<BrowseFlag>.*</BrowseFlag>', data)
                filter = re.search('<Filter>.*</Filter>', data)
                startingindex = re.search('<StartingIndex>.*</StartingIndex>', data)
                requestedcount = re.search('<RequestedCount>.*</RequestedCount>', data)
                sortcriteria = re.search('<SortCriteria>.*</SortCriteria>', data)
                if sortcriteria is None:
                    sortcriteria = '<SortCriteria />'
                else:
                    sortcriteria = sortcriteria.group()

#                print "data before: " + data
                data = before.group() + objectid.group() + browseflag.group() + filter.group() + startingindex.group() + requestedcount.group() + sortcriteria + after.group()
#                print "data after: " + data

            if data and soapaction.endswith('Search'):

                # HACK - MS MP doesn't seem to like elements not being in schema order

                before = re.search('.*<ns[0-9]?:Search[^>]*>', data)
                after = re.search('</ns[0-9]?:Search>.*', data)
                containerid = re.search('<ContainerID>.*</ContainerID>', data)
                searchcriteria = re.search('<SearchCriteria>.*</SearchCriteria>', data)
                filter = re.search('<Filter>.*</Filter>', data)
                startingindex = re.search('<StartingIndex>.*</StartingIndex>', data)
                requestedcount = re.search('<RequestedCount>.*</RequestedCount>', data)
                sortcriteria = re.search('<SortCriteria>.*</SortCriteria>', data)

#                print "data before: " + data
                data = before.group() + containerid.group() + searchcriteria.group() + filter.group() + startingindex.group() + requestedcount.group() + sortcriteria.group() + after.group()
#                print "data after: " + data

        if addr.scheme == 'https':
            r = httplib.HTTPSConnection(real_addr)
        else:
            r = httplib.HTTPConnection(real_addr)

        log.debug('#### HTTPTransport call - real_addr : %s' % real_addr)
        log.debug('#### HTTPTransport call - real_path : %s' % real_path)
        log.debug('#### HTTPTransport call - addr.scheme : %s' % addr.scheme)
        log.debug('#### HTTPTransport call - addr.hostname : %s' % addr.hostname)

        r.putrequest("POST", real_path, skip_host=1, skip_accept_encoding=1)
#        r.putheader("ACCEPT-ENCODING", 'gzip')
        r.putheader("CONNECTION", 'close')

        r.putheader("Host", addr.hostname)
        r.putheader("User-agent", 'BRISA SERVER')
        
        t = 'text/xml'
        if encoding:
            t += '; charset="%s"' % encoding
        r.putheader("Content-type", t)
        r.putheader("Content-length", str(len(data)))

        # if user is not a user:passwd format
        if addr.username != None:
            val = base64.encodestring(addr.user)
            r.putheader('Authorization', 'Basic ' + val.replace('\012', ''))

        # This fixes sending either "" or "None"
        if soapaction:
            r.putheader("SOAPAction", '"%s"' % soapaction)
        else:
            r.putheader("SOAPAction", "")

        r.endheaders()

        log.debug('#### HTTP BEFORE r.send ################################')

        r.send(data)

        log.debug('#### HTTP AFTER r.send ################################')

        #read response line
#        code, msg, headers = r.getreply()
        response = r.getresponse()
        code = response.status
        msg = response.reason
        headers = response.msg

        log.debug('#### HTTP AFTER START #################################')
        log.debug('#### HTTP code        : %s' % str(code))
        log.debug('#### HTTP msg         : %s' % str(msg))
        log.debug('#### HTTP headers     : %s' % str(headers))
        log.debug('#### HTTP AFTER END ###################################')

        content_type = headers.get("content-type", "text/xml")
        content_length = headers.get("Content-length")
        if content_length == None:
#            data = r.getfile().read()
            data = response.read()
            message_len = len(data)
        else:
            message_len = int(content_length)
#            data = r.getfile().read(message_len)
            data = response.read(message_len)

        def startswith(string, val):
            return string[0:len(val)] == val

        if code == 500 and not \
               (startswith(content_type, "text/xml") and message_len > 0):
            raise HTTPError(code, msg)

        if code not in (200, 500):
            raise HTTPError(code, msg)

        # TODO: use the content-type charset to convert the data returned

        #return response payload
        # NAS is sending some non utf-8 data - TODO: fix NAS rather than decoding for all types which is redundant
        try:
            d = data.decode('utf-8', 'replace')
        except UnicodeDecodeError:
            print "UnicodeDecodeError"
            return data
            
        log.debug('#### HTTP data        : %s' % d)
            
        return d
示例#28
0
def parse_base_url(url):
    parsed = parse_url(url)
    return '%s://%s' % (parsed[0], parsed[1])
示例#29
0
    def call(self, addr, data, namespace, soapaction=None, encoding=None):
        """ Builds and performs an HTTP request. Returns the response payload.

        @param addr: address to receive the request in the form
        schema://hostname:port
        @param data: data to be sent
        @param soapaction: soap action to be called
        @param encoding: encoding for the message

        @type addr: string
        @type data: string
        @type soapaction: string
        @type encoding: string

        @return: response payload
        @rtype: string
        """

        log.debug('#### HTTPTransport call - addr : %s' % str(addr))
        log.debug('#### HTTPTransport call - data : %s' % str(data))
        log.debug('#### HTTPTransport call - namespace : %s' % str(namespace))
        log.debug('#### HTTPTransport call - soapaction : %s' % str(soapaction))
        log.debug('#### HTTPTransport call - encoding : %s' % str(encoding))

        # Build a request
        addr = parse_url(addr)
        real_addr = '%s:%d' % (addr.hostname, addr.port)
        real_path = addr.path

        if addr.query:
        
            # Windows based media servers tend to use the query element of the address to hold connection information
            # TODO: standardise this code and only do the conversions for MS media player

            real_path += '?' + addr.query

            if data and soapaction.endswith('IsAuthorized'):

                # HACK - MS MP (check whether this is really the case)

                data = data.replace('<DeviceID />', '<DeviceID>""</DeviceID>')
                print "data after: " + data

            if data and soapaction.endswith('Browse'):

                # HACK - MS MP doesn't seem to like ObjectID element not being first in list
                # Actually seems to like a specific order (e.g. if req count is before starting index it doesn't bring anything back -
                # I guess because the index is after the end of the number it found)

                before = re.search('.*<ns[0-9]?:Browse[^>]*>', data)
                after = re.search('</ns[0-9]?:Browse>.*', data)
                objectid = re.search('<ObjectID>.*</ObjectID>', data)
                browseflag = re.search('<BrowseFlag>.*</BrowseFlag>', data)
                filter = re.search('<Filter>.*</Filter>', data)
                startingindex = re.search('<StartingIndex>.*</StartingIndex>', data)
                requestedcount = re.search('<RequestedCount>.*</RequestedCount>', data)
                sortcriteria = re.search('<SortCriteria>.*</SortCriteria>', data)
                if sortcriteria is None:
                    sortcriteria = '<SortCriteria />'
                else:
                    sortcriteria = sortcriteria.group()

#                print "data before: " + data
                data = before.group() + objectid.group() + browseflag.group() + filter.group() + startingindex.group() + requestedcount.group() + sortcriteria + after.group()
#                print "data after: " + data

            if data and soapaction.endswith('Search'):

                # HACK - MS MP doesn't seem to like elements not being in schema order

                before = re.search('.*<ns[0-9]?:Search[^>]*>', data)
                after = re.search('</ns[0-9]?:Search>.*', data)
                containerid = re.search('<ContainerID>.*</ContainerID>', data)
                searchcriteria = re.search('<SearchCriteria>.*</SearchCriteria>', data)
                filter = re.search('<Filter>.*</Filter>', data)
                startingindex = re.search('<StartingIndex>.*</StartingIndex>', data)
                requestedcount = re.search('<RequestedCount>.*</RequestedCount>', data)
                sortcriteria = re.search('<SortCriteria>.*</SortCriteria>', data)

#                print "data before: " + data
                data = before.group() + containerid.group() + searchcriteria.group() + filter.group() + startingindex.group() + requestedcount.group() + sortcriteria.group() + after.group()
#                print "data after: " + data

        if addr.scheme == 'https':
            r = httplib.HTTPSConnection(real_addr)
        else:
            r = httplib.HTTPConnection(real_addr)

        log.debug('#### HTTPTransport call - real_addr : %s' % real_addr)
        log.debug('#### HTTPTransport call - real_path : %s' % real_path)
        log.debug('#### HTTPTransport call - addr.scheme : %s' % addr.scheme)
        log.debug('#### HTTPTransport call - addr.hostname : %s' % addr.hostname)

        r.putrequest("POST", real_path, skip_host=1, skip_accept_encoding=1)
#        r.putheader("ACCEPT-ENCODING", 'gzip')
        r.putheader("CONNECTION", 'close')

        r.putheader("Host", addr.hostname)
#        r.putheader("User-agent", 'BRISA SERVER')
        r.putheader("User-agent", 'Sonospy')
        
        t = 'text/xml'
        if encoding:
            t += '; charset="%s"' % encoding
        r.putheader("Content-type", t)
        r.putheader("Content-length", str(len(data)))

        # if user is not a user:passwd format
        if addr.username != None:
            val = base64.encodestring(addr.user)
            r.putheader('Authorization', 'Basic ' + val.replace('\012', ''))

        # This fixes sending either "" or "None"
        if soapaction:
            r.putheader("SOAPAction", '"%s"' % soapaction)
        else:
            r.putheader("SOAPAction", "")

        r.endheaders()

        log.debug('#### HTTP BEFORE r.send ################################')

        r.send(data)

        log.debug('#### HTTP AFTER r.send ################################')

        #read response line
#        code, msg, headers = r.getreply()
        response = r.getresponse()
        code = response.status
        msg = response.reason
        headers = response.msg

        log.debug('#### HTTP AFTER START #################################')
        log.debug('#### HTTP code        : %s' % str(code))
        log.debug('#### HTTP msg         : %s' % str(msg))
        log.debug('#### HTTP headers     : %s' % str(headers))
        log.debug('#### HTTP AFTER END ###################################')

        content_type = headers.get("content-type", "text/xml")
        content_length = headers.get("Content-length")
        if content_length == None:
#            data = r.getfile().read()
            data = response.read()
            message_len = len(data)
        else:
            message_len = int(content_length)
#            data = r.getfile().read(message_len)
            data = response.read(message_len)

        def startswith(string, val):
            return string[0:len(val)] == val

        if code == 500 and not \
               (startswith(content_type, "text/xml") and message_len > 0):
            raise HTTPError(code, msg)

        if code not in (200, 500):
            raise HTTPError(code, msg)

        # TODO: use the content-type charset to convert the data returned

        #return response payload
        # NAS is sending some non utf-8 data - TODO: fix NAS rather than decoding for all types which is redundant
        try:
            d = data.decode('utf-8', 'replace')
        except UnicodeDecodeError:
            print "UnicodeDecodeError"
            return data
            
        log.debug('#### HTTP data        : %s' % d)
            
        return d
示例#30
0
    def call(self, addr, data, namespace, soapaction=None, encoding=None):
        """ Builds and performs an HTTP request. Returns the response payload.

        @param addr: address to receive the request in the form
        schema://hostname:port
        @param data: data to be sent
        @param soapaction: soap action to be called
        @param encoding: encoding for the message

        @type addr: string
        @type data: string
        @type soapaction: string
        @type encoding: string

        @return: response payload
        @rtype: string
        """

        log.debug('#### HTTPTransport call - addr : %s' % str(addr))
        log.debug('#### HTTPTransport call - data : %s' % str(data))
        log.debug('#### HTTPTransport call - namespace : %s' % str(namespace))
        log.debug('#### HTTPTransport call - soapaction : %s' %
                  str(soapaction))
        log.debug('#### HTTPTransport call - encoding : %s' % str(encoding))

        # Build a request
        '''
        addr : http://legato.radiotime.com:80
        data : <?xml version="1.0" encoding="utf-8"?><s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Header><credentials xmlns="http://www.sonos.com/Services/1.1"><deviceProvider>Sonos</deviceProvider></credentials></s:Header><s:Body><ns0:getMetadata xmlns:ns0="http://www.sonos.com/Services/1.1"><count>100</count><index>0</index><recursive>false</recursive><id>root</id></ns0:getMetadata></s:Body></s:Envelope>
        namespace : ('u', 'http://www.sonos.com/Services/1.1')
        soapaction : http://www.sonos.com/Services/1.1#getMetadata
        encoding : utf-8
        real_addr : legato.radiotime.com:80
        real_path : 
        addr.scheme : http
        addr.hostname : legato.radiotime.com

        POST /Radio.asmx HTTP/1.1
        CONNECTION: close
        ACCEPT-ENCODING: gzip
        HOST: legato.radiotime.com
        USER-AGENT: Linux UPnP/1.0 Sonos/11.7-19141a
        CONTENT-LENGTH: 337
        CONTENT-TYPE: text/xml; charset="utf-8"
        ACCEPT-LANGUAGE: en-US
        SOAPACTION: "http://www.sonos.com/Services/1.1#getMetadata"
        '''
        # TODO: tidy up parameters, use saved params from musicservices call, change to gzip
        addr = parse_url(addr)
        real_addr = '%s:%d' % (addr.hostname, addr.port)
        real_path = addr.path

        if addr.scheme == 'https':
            r = httplib.HTTPSConnection(real_addr)
        else:
            r = httplib.HTTPConnection(real_addr)

        log.debug('#### HTTPTransport call - real_addr : %s' % real_addr)
        log.debug('#### HTTPTransport call - real_path : %s' % real_path)
        log.debug('#### HTTPTransport call - addr.scheme : %s' % addr.scheme)
        log.debug('#### HTTPTransport call - addr.hostname : %s' %
                  addr.hostname)

        r.putrequest("POST", real_path, skip_host=1, skip_accept_encoding=1)

        r.putheader("ACCEPT-ENCODING", 'gzip')
        r.putheader("CONNECTION", 'close')

        r.putheader("HOST", addr.hostname)
        r.putheader("USER-AGENT", 'Linux UPnP/1.0 Sonos/11.7-19141a')
        t = 'text/xml'
        #        if encoding:
        #            t += '; charset="%s"' % encoding

        r.putheader("CONTENT-TYPE", t)
        #        r.putheader("ACCEPT-CHARSET", 'ISO-8859-1,utf-8;q=0.7,*;q=0.7')
        r.putheader("ACCEPT-LANGUAGE", 'en-US')
        r.putheader("CONTENT-LENGTH", str(len(data)))

        # if user is not a user:passwd format
        if addr.username != None:
            val = base64.encodestring(addr.user)
            r.putheader('Authorization', 'Basic ' + val.replace('\012', ''))

        # This fixes sending either "" or "None"
        if soapaction:
            r.putheader("SOAPACTION", '"%s"' % soapaction)
        else:
            r.putheader("SOAPACTION", "")

        r.endheaders()

        log.debug('#### HTTP BEFORE r.send ################################')

        r.send(data)

        log.debug('#### HTTP AFTER r.send ################################')

        #read response line
        #        code, msg, headers = r.getreply()
        response = r.getresponse()
        code = response.status
        msg = response.reason
        headers = response.msg

        log.debug('#### HTTP AFTER START #################################')
        log.debug('#### HTTP code        : %s' % str(code))
        log.debug('#### HTTP msg         : %s' % str(msg))
        log.debug('#### HTTP headers     : %s' % str(headers))
        log.debug('#### HTTP AFTER END ###################################')

        content_type = headers.get("content-type", "text/xml")
        content_length = headers.get("Content-length")
        if content_length == None:
            #            data = r.getfile().read()
            data = response.read()
            message_len = len(data)
        else:
            message_len = int(content_length)
            #            data = r.getfile().read(message_len)
            data = response.read(message_len)

        def startswith(string, val):
            return string[0:len(val)] == val


        if code == 500 and not \
               (startswith(content_type, "text/xml") and message_len > 0):
            raise HTTPError(code, msg)

        if code not in (200, 500):
            raise HTTPError(code, msg)

        #return response payload


#        return data.decode('utf-8')

        import StringIO
        stream = StringIO.StringIO(data)
        import gzip
        gzipper = gzip.GzipFile(fileobj=stream)
        data = gzipper.read()

        return data