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
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)
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
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
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''
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')
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)
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', )
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', )
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')