Example #1
0
    def listchilds(self, uri):
        uri = to_string(uri)
        self.info(f'listchilds {uri}')
        if uri[-1] != '/':
            uri += '/'

        cl = []
        for child in self.coherence.children:
            device = self.coherence.get_device_with_id(child)
            if device is not None:
                cl.append(f'<li><a href={uri}{child}>'
                          f'{device.get_friendly_device_type()}:'
                          f'{device.get_device_type_version()} '
                          f'{device.get_friendly_name()}'
                          f'</a></li>')

        # We put in a blacklist the styles and server-images folders,
        # in order to avoid to appear into the generated html list
        blacklist = ['styles', 'server-images']
        for c in self.children:
            c = to_string(c)
            if c in blacklist:
                continue
            cl.append(f'<li><a href={uri}{c}>{c}</a></li>')
        return ''.join(cl)
 def listchilds(self, uri):
     uri = to_string(uri)
     cl = ''
     for c in self.children:
         c = to_string(c)
         cl += f'<li><a href={uri}/{c}>{c}</a></li>'
     return cl
Example #3
0
 def constructConfigData(backend):
     msg = '<plugin active="yes">'
     msg += '<backend>' + to_string(backend_type) + '</backend>'
     for key, value in list(backend.config.items()):
         msg += '<' + to_string(key) + '>' + to_string(value) + \
                '</' + to_string(key) + '>'
     msg += '</plugin>'
     return to_bytes(msg)
Example #4
0
def send_notification(s, xml):
    '''
    send a notification a subscriber
    return its response
    '''
    logger = log.get_logger('notification_protocol')
    # logger.debug('\t-send_notification s is: {}'.format(s))
    # logger.debug('\t-send_notification xml is: {}'.format(xml))

    _, host_port, path, _, _ = urlsplit(s['callback'])
    # logger.debug('\t-send_notification host_port is: {}'.format(host_port))
    # logger.debug('\t-send_notification path is: {}'.format(path))
    path = to_string(path)
    host_port = to_string(host_port)
    if path == '':
        path = '/'
    if host_port.find(':') != -1:
        host, port = tuple(host_port.split(':'))
        port = int(port)
    else:
        host = host_port
        port = 80

    def send_request(p, port_item):
        request = [
            f'NOTIFY {path} HTTP/1.1', f'HOST:  {host}:{port}',
            f'SEQ:  {s["seq"]}', 'CONTENT-TYPE:  text/xml;charset="utf-8"',
            f'SID:  {s["sid"]}', 'NTS:  upnp:propchange', 'NT:  upnp:event',
            f'Content-Length: {len(xml)}', ''
        ]
        request = [to_bytes(x) for x in request]
        request.append(xml)
        request = b'\r\n'.join(request)
        logger.info(f'send_notification.send_request to '
                    f'{s["sid"]} {s["callback"]}')
        logger.info(f'request: {request}')
        s['seq'] += 1
        if s['seq'] > 0xffffffff:
            s['seq'] = 1
        p.transport.write(request)
        port_item.disconnect()

    def got_error(failure, port_item):
        port_item.disconnect()
        logger.info(
            f'error sending notification to {s["sid"]} {s["callback"]}')
        logger.debug(failure)

    d = defer.Deferred()
    f = _InstanceFactory(reactor, NotificationProtocol(), d)
    port_item = reactor.connectTCP(host, port, f, timeout=30, bindAddress=None)

    d.addCallback(send_request, port_item)
    d.addErrback(got_error, port_item)

    return d, port_item
Example #5
0
 def listchilds(self, uri):
     uri = to_string(uri)
     self.info(f'listchilds {uri}')
     if uri[-1] != '/':
         uri += '/'
     cl = f'<li><a href={uri}0>Content</a></li>'
     cl += f'<li><a href={uri}config>Config</a></li>'
     for c in self.children:
         c = to_string(c)
         cl += f'<li><a href={uri}{c}>{c}</a></li>'
     return cl
Example #6
0
    def render_SUBSCRIBE(self, request):
        self.info(
            f'EventSubscriptionServer {self.service.id} ({self.backend_name}) '
            + f'received subscribe request from {request.client}, ' +
            f'code: {request.code:d}')
        data = request.content.getvalue()
        request.setResponseCode(200)

        command = {'method': request.method, 'path': request.path}
        headers = request.responseHeaders
        self.dispatch_event('event_client_message_received', command, headers,
                            data)

        if request.code != 200:
            self.debug(f'data: {data}')
        else:
            headers = request.getAllHeaders()
            if b'sid' in headers and headers[b'sid'] in self.subscribers:
                s = self.subscribers[headers[b'sid']]
                s['timeout'] = headers[b'timeout']
                s['created'] = time.time()
            elif b'callback' not in headers:
                request.setResponseCode(404)
                request.setHeader(b'SERVER', to_bytes(SERVER_ID))
                request.setHeader(b'CONTENT-LENGTH', to_bytes(0))
                return b''
            else:
                from .uuid import UUID

                sid = UUID()
                c = to_string(
                    headers[b'callback'][1:len(headers[b'callback']) - 1])
                s = {
                    'sid': to_string(sid),
                    'callback': c,
                    'seq': 0,
                    'timeout': to_string(headers[b'timeout']),
                    'created': time.time(),
                }
                self.service.new_subscriber(s)
            request.setHeader(b'SID', to_bytes(s['sid']))

            # wrong example in the UPnP UUID spec?
            # request.setHeader(b'Subscription-ID', sid)

            request.setHeader(b'TIMEOUT', to_bytes(s['timeout']))
            request.setHeader(b'SERVER', to_bytes(SERVER_ID))
            request.setHeader(b'CONTENT-LENGTH', to_bytes(0))
        return b''
Example #7
0
 def build_page(r, page):
     # self.debug('build_page', r)
     page += '''<div class="list"><ul>'''
     if r is not None:
         for c in r:
             if hasattr(c, 'get_url'):
                 url_path = c.get_url()
             elif hasattr(c, 'get_path') and c.get_path is not None:
                 # path = c.get_path().encode(
                 #     'utf-8').encode('string_escape')
                 url_path = c.get_path()
                 if isinstance(url_path, str):
                     pass
                 elif isinstance(url_path, bytes):
                     url_path = url_path.decode(
                         'utf-8', 'xmlcharrefreplace'
                     )
                 elif isinstance(url_path, ReverseProxyResource):
                     url_path = to_string(c.url)
             else:
                 url_path = request.uri.split('/')
                 url_path[-1] = str(c.get_id())
                 url_path = '/'.join(url_path)
             title = c.get_name()
             try:
                 if isinstance(title, str):
                     title = title
                 else:
                     title = title.decode(
                         'utf-8', 'xmlcharrefreplace'
                     )
             except (UnicodeEncodeError, UnicodeDecodeError):
                 title = (
                     c.get_name()
                     .encode('utf-8')
                     .encode('string_escape')
                 )
             it_cls = ''
             has_mime = hasattr(c, 'mimetype')
             if has_mime and c.mimetype.startswith('video'):
                 it_cls = 'class="item-video"'
             elif has_mime and c.mimetype.startswith('audio'):
                 it_cls = 'class="item-audio"'
             elif has_mime and c.mimetype.startswith('image'):
                 it_cls = 'class="item-image"'
             page += (
                 f'<li>'
                 + f'<a {it_cls} href="{url_path}">{title}</a>'
                 + f'</li>'
             )
     page += '''</ul></div>'''
     page += '''</body></html>'''
     return static.Data(to_bytes(page), 'text/html')
Example #8
0
    def datagramReceived(self, data, xxx_todo_changeme):
        '''Handle a received multicast datagram.'''
        self.debug(f'datagramReceived: {data}')
        (host, port) = xxx_todo_changeme
        data = to_string(data)
        try:
            header, payload = data.split('\r\n\r\n')[:2]
        except ValueError as err:
            print(err)
            print('Arggg,', data)
            import pdb

            pdb.set_trace()

        lines = header.split('\r\n')
        cmd = lines[0].split(' ')
        lines = [x.replace(': ', ':', 1) for x in lines[1:]]
        lines = [x for x in lines if len(x) > 0]

        # TODO: Find  and fix where some of the header's keys are quoted.
        # This hack, allows to fix the quoted keys for the headers, introduced
        # at some point of the source code. I notice that the issue appears
        # when using FSStore plugin. But where?
        def fix_string(s, to_lower=True):
            for q in ['\'', '"']:
                while s.startswith(q):
                    s = s[1:]
            for q in ['\'', '"']:
                while s.endswith(q):
                    s = s[:-1]
            if to_lower:
                s = s.lower()
            return s

        headers = [x.split(':', 1) for x in lines]
        headers = dict([(fix_string(x[0]), fix_string(x[1], to_lower=False))
                        for x in headers])

        self.msg(f'SSDP command {cmd[0]} {cmd[1]} - from {host}:{port}')
        self.debug(f'with headers: {headers}')
        if cmd[0] == 'M-SEARCH' and cmd[1] == '*':
            # SSDP discovery
            self.discoveryRequest(headers, (host, port))
        elif cmd[0] == 'NOTIFY' and cmd[1] == '*':
            # SSDP presence
            self.notifyReceived(headers, (host, port))
        else:
            self.warning(f'Unknown SSDP command {cmd[0]} {cmd[1]}')

        # make raw data available
        # send out the signal after we had a chance to register the device
        self.dispatch_event('datagram_received', data, host, port)
Example #9
0
                def got_attachment(ch):
                    try:
                        # FIXME same as below
                        if 'transcoded' in request.args:
                            if (self.server.coherence.config.get(
                                    'transcoding', 'no') == 'yes'):
                                format = request.args['transcoded'][0]
                                type = request.args['type'][0]
                                self.info(
                                    f'request transcoding {format} {type}')
                                try:
                                    from coherence.transcoder import (
                                        TranscoderManager, )

                                    manager = TranscoderManager(
                                        self.server.coherence)
                                    return manager.select(
                                        format,
                                        ch.item.attachments[
                                            request.args['attachment'][0]],
                                    )
                                except Exception:
                                    self.debug(traceback.format_exc())
                                request.setResponseCode(404)
                                return static.Data(
                                    b'<html><p>the requested transcoded file '
                                    b'was not found</p></html>',
                                    'text/html',
                                )
                            else:
                                request.setResponseCode(404)
                                return static.Data(
                                    b'<html><p>This MediaServer '
                                    b'doesn\'t support transcoding</p></html>',
                                    'text/html',
                                )
                        else:
                            return ch.item.attachments[to_string(
                                request.args[b'attachment'][0])]
                    except Exception:
                        request.setResponseCode(404)
                        return static.Data(
                            b'<html><p>the requested attachment '
                            b'was not found</p></html>',
                            'text/html',
                        )
Example #10
0
    def getChild(self, name, request):
        self.debug(f'SimpleRoot getChild {name}, {request}')
        name = to_string(name)
        if name == 'oob':
            ''' we have an out-of-band request '''
            return static.File(
                self.coherence.dbus.pinboard[request.args['key'][0]])

        if name in ['', None]:
            return self

        # at this stage, name should be a device UUID
        try:
            return self.coherence.children[name]
        except KeyError:
            self.warning(f'Cannot find device for requested name: {name}')
            request.setResponseCode(404)
            return static.Data(
                f'<html><p>No device for requested UUID: '
                f'{name.encode("ascii")}</p></html>'.encode('ascii'),
                'text/html',
            )
Example #11
0
    def list_content(self, name, item, request):
        self.info(f'list_content {name} {item} {request}')
        page = f'''\
        <html>
            <head><link rel="stylesheet" type="text/css"
            href="/styles/main.css" />
                <title>Cohen3 ({item.get_name()})</title>
            </head>
            <body>
                <h5>
                    <img class="logo-icon"
                    src="/server-images/coherence-icon.svg">
                    </img>{item.get_name()}
                </h5>
        '''

        if (
                hasattr(item, 'mimetype')
                and item.mimetype in ['directory', 'root']
        ):
            uri = to_string(request.uri)
            if uri[-1] != '/':
                uri += '/'

            def build_page(r, page):
                # self.debug('build_page', r)
                page += '''<div class="list"><ul>'''
                if r is not None:
                    for c in r:
                        if hasattr(c, 'get_url'):
                            url_path = c.get_url()
                        elif hasattr(c, 'get_path') and c.get_path is not None:
                            # path = c.get_path().encode(
                            #     'utf-8').encode('string_escape')
                            url_path = c.get_path()
                            if isinstance(url_path, str):
                                pass
                            elif isinstance(url_path, bytes):
                                url_path = url_path.decode(
                                    'utf-8', 'xmlcharrefreplace'
                                )
                            elif isinstance(url_path, ReverseProxyResource):
                                url_path = to_string(c.url)
                        else:
                            url_path = request.uri.split('/')
                            url_path[-1] = str(c.get_id())
                            url_path = '/'.join(url_path)
                        title = c.get_name()
                        try:
                            if isinstance(title, str):
                                title = title
                            else:
                                title = title.decode(
                                    'utf-8', 'xmlcharrefreplace'
                                )
                        except (UnicodeEncodeError, UnicodeDecodeError):
                            title = (
                                c.get_name()
                                .encode('utf-8')
                                .encode('string_escape')
                            )
                        it_cls = ''
                        has_mime = hasattr(c, 'mimetype')
                        if has_mime and c.mimetype.startswith('video'):
                            it_cls = 'class="item-video"'
                        elif has_mime and c.mimetype.startswith('audio'):
                            it_cls = 'class="item-audio"'
                        elif has_mime and c.mimetype.startswith('image'):
                            it_cls = 'class="item-image"'
                        page += (
                            f'<li>'
                            + f'<a {it_cls} href="{url_path}">{title}</a>'
                            + f'</li>'
                        )
                page += '''</ul></div>'''
                page += '''</body></html>'''
                return static.Data(to_bytes(page), 'text/html')

            children = item.get_children()
            if isinstance(children, defer.Deferred):
                print('list_content, we have a Deferred', children)
                children.addCallback(build_page, page)
                # children.addErrback(....) #FIXME
                return children

            return build_page(children, page)

        elif hasattr(item, 'mimetype') and item.mimetype.find('image/') == 0:
            # path = item.get_path().encode('utf-8').encode('string_escape')
            path = urllib.parse.quote(item.get_path().encode('utf-8'))
            title = item.get_name().decode('utf-8', 'xmlcharrefreplace')
            page += (
                f'<p><img class="item-image" src="{path}" alt="{title}"></p>'
            )
        else:
            pass
        page += '''</body></html>'''
        return static.Data(to_bytes(page), 'text/html')