def __init__(self, host=None, host_kwargs={'port': 80}): # starts a WebHost on port 80 that if host is None: from guavacado import WebHost self.host = WebHost(**host_kwargs) else: self.host = host
def __init__(self, host=None, host_kwargs={}, host_addr_kwargs={}, web_dispatcher_ident=None, dispatcher_level=None): # pylint: disable=W0102 if web_dispatcher_ident is None: disp_type = 'web' else: disp_type = ('web', web_dispatcher_ident) # starts a WebHost on port 80 that if host is None: from guavacado import WebHost # pylint: disable=C0415 self.host = WebHost(**host_kwargs) host_addr_kwargs_add = host_addr_kwargs if not web_dispatcher_ident is None: host_addr_kwargs_add.update({'disp_type': disp_type}) self.host.add_addr(**host_addr_kwargs_add) else: self.host = host self.resource_dict = {} self.host.get_specialized_dispatcher(disp_type).add_resource_handler( self.identify_request, self.handle_request, 'WebInterface', level=dispatcher_level)
def __init__(self, host=None, host_kwargs=None, host_addr_kwargs=None, web_dispatcher_ident=None, dispatcher_level=None, recv_timeout=None): if host_kwargs is None: host_kwargs = {} if host_addr_kwargs is None: host_addr_kwargs = {} if web_dispatcher_ident is None: disp_type = 'web' else: disp_type = ('web', web_dispatcher_ident) if host is None: from guavacado import WebHost # pylint: disable=C0415 self.host = WebHost(**host_kwargs) host_addr_kwargs_add = host_addr_kwargs if not web_dispatcher_ident is None: host_addr_kwargs_add.update({'disp_type': disp_type}) self.host.add_addr(**host_addr_kwargs_add) else: self.host = host self.resource_dict = {} self.recv_timeout = recv_timeout self.host.get_specialized_dispatcher(disp_type).add_resource_handler( self.identify_request, self.handle_request, 'WebInterface', level=dispatcher_level, call_after_handled=self.after_http_handled, override_status_code=101)
class WebInterface(object): """ Allows for easily defining web interfaces for the server. Expects the variable "self.host" to be set to a WebHost object before calling "connect()". See implementation of __init__ class for an example initialization. """ def __init__(self, host=None, host_kwargs={'port': 80}): # starts a WebHost on port 80 that if host is None: from guavacado import WebHost self.host = WebHost(**host_kwargs) else: self.host = host # # add lines like the following: # self.connect('/test/:id','GET_ID','GET') # self.connect('/test/:id',self.GET_ID,'GET') # # to call member function GET_ID() with the argument after "/test/" when a GET request # # is received for "/test/<any text here>" def connect(self, resource, action, method, body_included=False): if isinstance(action, str): callback = getattr(self, action) else: callback = action self.connect_callback(resource, callback, method, body_included=body_included) def connect_callback(self, resource, callback, method, body_included=False): """ connects a specified callback (function) in this object to the specified resource (URL) and http method (GET/PUT/POST/DELETE) """ self.dispatcher = self.host.get_dispatcher() if body_included: disp_callback = callback else: def disp_callback(body, *args): return callback(*args) self.dispatcher.connect(resource, disp_callback, method) # log this connection on the host self.host.log_connection(resource, callback, method) def start_service(self): self.host.start_service() def stop_service(self): self.host.stop_service()
def __init__(self, host=None, host_kwargs={}, host_addr_kwargs={}, web_dispatcher_ident=None, dispatcher_level=None, staticdir="static", staticindex="index.html", include_fp=['{staticdir}/*'], exclude_fp=[]): # pylint: disable=W0102 if web_dispatcher_ident is None: disp_type = 'web' else: disp_type = ('web', web_dispatcher_ident) # starts a WebHost on port 80 that if host is None: from guavacado import WebHost # pylint: disable=C0415 self.host = WebHost(**host_kwargs) host_addr_kwargs_add = host_addr_kwargs if not web_dispatcher_ident is None: host_addr_kwargs_add.update({'disp_type': disp_type}) self.host.add_addr(**host_addr_kwargs_add) else: self.host = host self.log_handler = init_logger(__name__) self.staticdir = staticdir self.staticindex = staticindex self.include_fp = include_fp self.exclude_fp = exclude_fp self.method_actions = {} self.host.get_specialized_dispatcher(disp_type).add_resource_handler( self.identify_request, self.handle_request, 'WebFileInterface', level=dispatcher_level) self.register_method_action('GET', self.identify_GET_request) self.register_method_action('HEAD', self.identify_HEAD_request)
class WebInterface(object): """ Allows for easily defining web interfaces for the server. Expects the variable "self.host" to be set to a WebHost object before calling "connect()". See implementation of __init__ class for an example initialization. """ def __init__(self, host=None, host_kwargs={}, host_addr_kwargs={}, web_dispatcher_ident=None, dispatcher_level=None): # pylint: disable=W0102 if web_dispatcher_ident is None: disp_type = 'web' else: disp_type = ('web', web_dispatcher_ident) # starts a WebHost on port 80 that if host is None: from guavacado import WebHost # pylint: disable=C0415 self.host = WebHost(**host_kwargs) host_addr_kwargs_add = host_addr_kwargs if not web_dispatcher_ident is None: host_addr_kwargs_add.update({'disp_type': disp_type}) self.host.add_addr(**host_addr_kwargs_add) else: self.host = host self.resource_dict = {} self.host.get_specialized_dispatcher(disp_type).add_resource_handler( self.identify_request, self.handle_request, 'WebInterface', level=dispatcher_level) # # add lines like the following: # self.connect('/test/:id','GET_ID','GET') # self.connect('/test/:id',self.GET_ID,'GET') # # to call member function GET_ID() with the argument after "/test/" when a GET request # # is received for "/test/<any text here>" def identify_request( self, req_info={ 'url': None, 'method': None, 'headers': None, 'body': None, 'clientsocket': None, 'extra_response_headers': {} }): # pylint: disable=W0102 if req_info['method'] in self.resource_dict: url_no_browseparams = req_info['url'].split('?')[ 0] # remove and ignore anything after a question mark for (url_prefix, url_param_count, params ) in self.get_possible_split_url_params(url_no_browseparams): if url_prefix in self.resource_dict[req_info['method']]: if url_param_count in self.resource_dict[ req_info['method']][url_prefix]: callback = self.resource_dict[ req_info['method']][url_prefix][url_param_count] args = (req_info['body'], ) + params return (callback, args) return None def handle_request(self, callback, args): return callback(*args) def get_possible_split_url_params(self, url): ret = [] split_url = url.split('/') remaining = split_url removed = [] while len(remaining) > 0: prefix = '/'.join(remaining) param_count = len(split_url) - len(remaining) params = removed[:param_count] if (prefix + '/') == url: ret.append((prefix, param_count, params)) param_count = param_count - 1 params = removed[:param_count] params_decoded = [] for par in params: params_decoded.append(url_decode(par)) params_decoded_tup = tuple(params_decoded) ret.append((prefix, param_count, params_decoded_tup)) removed = [remaining[-1]] + removed remaining = remaining[:-1] return ret def split_url_params(self, url): split_url = url.split('/:') prefix = split_url[0] param_count = len(split_url) - 1 return (prefix, param_count) def connect(self, resource, action, method, body_included=False): if isinstance(action, str): callback = getattr(self, action) else: callback = action self.connect_callback(resource, callback, method, body_included=body_included) def connect_callback(self, resource, callback, method, body_included=False): """ connects a specified callback (function) in this object to the specified resource (URL) and http method (GET/PUT/POST/DELETE) """ self.dispatcher = self.host.get_dispatcher() if body_included: disp_callback = callback else: def disp_callback(_body, *args): return callback(*args) if method not in self.resource_dict: self.resource_dict[method] = {} (url_prefix, url_param_count) = self.split_url_params(resource) if url_prefix not in self.resource_dict[method]: self.resource_dict[method][url_prefix] = {} self.resource_dict[method][url_prefix][url_param_count] = disp_callback # log this connection on the host self.host.get_docs().log_connection(resource, callback, method) def start_service(self): self.host.start_service() def stop_service(self): self.host.stop_service()
class WebFileInterface(object): def __init__(self, host=None, host_kwargs={}, host_addr_kwargs={}, web_dispatcher_ident=None, dispatcher_level=None, staticdir="static", staticindex="index.html", include_fp=['{staticdir}/*'], exclude_fp=[]): # pylint: disable=W0102 if web_dispatcher_ident is None: disp_type = 'web' else: disp_type = ('web', web_dispatcher_ident) # starts a WebHost on port 80 that if host is None: from guavacado import WebHost # pylint: disable=C0415 self.host = WebHost(**host_kwargs) host_addr_kwargs_add = host_addr_kwargs if not web_dispatcher_ident is None: host_addr_kwargs_add.update({'disp_type': disp_type}) self.host.add_addr(**host_addr_kwargs_add) else: self.host = host self.log_handler = init_logger(__name__) self.staticdir = staticdir self.staticindex = staticindex self.include_fp = include_fp self.exclude_fp = exclude_fp self.method_actions = {} self.host.get_specialized_dispatcher(disp_type).add_resource_handler( self.identify_request, self.handle_request, 'WebFileInterface', level=dispatcher_level) self.register_method_action('GET', self.identify_GET_request) self.register_method_action('HEAD', self.identify_HEAD_request) def register_method_action(self, method, callback): self.method_actions[method] = callback def identify_request( self, req_info={ 'url': None, 'method': None, 'headers': None, 'body': None, 'clientsocket': None, 'extra_response_headers': {} }): # pylint: disable=W0102 if req_info['method'] in self.method_actions: return self.method_actions[req_info['method']](req_info['url'], req_info['headers'], req_info['body']) return None def identify_GET_request(self, url, _headers, _body): url_relative = url[1:] while len(url_relative) > 0 and url_relative[0] == '/': url_relative = url_relative[1:] index_relative = os.path.join(url_relative, self.staticindex) url_relative_static = os.path.join(self.staticdir, url_relative).replace('\\', '/') index_relative_static = os.path.join(self.staticdir, index_relative).replace( '\\', '/') check_paths = [ index_relative, url_relative, index_relative_static, url_relative_static ] for path in check_paths: if self.check_path_allowed(path): if os.path.exists(path): if os.path.isfile(path): def read_file(path=path): with open(path, 'rb') as fp: data = fp.read() return data return (read_file, ()) else: return (self.get_dir_page, (path, )) return None def identify_HEAD_request(self, url, headers, body): result = self.identify_GET_request(url, headers, body) if result is None: return None else: # callback, args = result def get_empty_result(): return b'' return (get_empty_result, ()) def handle_request(self, callback, args): return callback(*args) def check_path_allowed(self, path): for ex_fp in self.exclude_fp: if fnmatch.fnmatch( path, ex_fp.format(staticdir=self.staticdir, staticindex=self.staticindex)): return False for inc_fp in self.include_fp: if fnmatch.fnmatch( path, inc_fp.format(staticdir=self.staticdir, staticindex=self.staticindex)): return True return False def get_address_string(self): return "{server} Server at {addr}".format(server=WebServerNameAndVer, addr=addr_rep( self.host.get_addr(), pretty=True)) def get_dir_page(self, path): if path[-1] != '/': return generate_redirect_page('/' + path + '/') data = ('<html><head><title>Index of {path}</title></head><body><h1>Index of {path}</h1><table>'+\ '<tr><th valign="top"></th><th>Name</th><th>Last modified</th><th>Size</th></tr>'+\ '<tr><th colspan="5"><hr></th></tr>'+\ '<tr><td valign="top"></td><td><a href="..">Parent Directory</a></td><td> </td><td align="right"> - </td></tr>').format( path="/"+path ) for filename in os.listdir(path): fullpath = os.path.join(path, filename) if os.path.isdir(fullpath): if filename[-1] != '/': filename = filename + '/' filestat = os.stat(fullpath) size = filestat.st_size size_str = str(size) if size > (1 << 10): size_str = str(size / (1 << 10)) + "K" if size > (1 << 20): size_str = str(size / (1 << 20)) + "M" if size > (1 << 30): size_str = str(size / (1 << 30)) + "G" if size > (1 << 40): size_str = str(size / (1 << 40)) + "T" data = data + '<tr><td valign="top"></td><td><a href="{filename}">{filename}</a></td><td align="right">{lastmodified}</td><td align="right">{size}</td></tr>'.format( filename=filename, lastmodified=datetime.fromtimestamp(filestat.st_mtime), size=size_str) data = data + (('<tr><th colspan="5"><hr></th></tr></table>'+\ '<address>{address}</address>'+\ '</body></html>').format( address=self.get_address_string() )) return data def start_service(self): self.host.start_service() def stop_service(self): self.host.stop_service()
class WebSocketInterface(object): def __init__(self, host=None, host_kwargs=None, host_addr_kwargs=None, web_dispatcher_ident=None, dispatcher_level=None, recv_timeout=None): if host_kwargs is None: host_kwargs = {} if host_addr_kwargs is None: host_addr_kwargs = {} if web_dispatcher_ident is None: disp_type = 'web' else: disp_type = ('web', web_dispatcher_ident) if host is None: from guavacado import WebHost # pylint: disable=C0415 self.host = WebHost(**host_kwargs) host_addr_kwargs_add = host_addr_kwargs if not web_dispatcher_ident is None: host_addr_kwargs_add.update({'disp_type': disp_type}) self.host.add_addr(**host_addr_kwargs_add) else: self.host = host self.resource_dict = {} self.recv_timeout = recv_timeout self.host.get_specialized_dispatcher(disp_type).add_resource_handler( self.identify_request, self.handle_request, 'WebInterface', level=dispatcher_level, call_after_handled=self.after_http_handled, override_status_code=101) def identify_request( self, req_info={ 'url': None, 'method': None, 'headers': None, 'body': None, 'clientsocket': None, 'web_request_handler': None, 'extra_response_headers': {} }): # pylint: disable=W0102 if req_info['method'] in self.resource_dict: url_no_browseparams = req_info['url'].split('?')[ 0] # remove and ignore anything after a question mark for (url_prefix, url_param_count, params ) in self.get_possible_split_url_params(url_no_browseparams): if url_prefix in self.resource_dict[req_info['method']]: if url_param_count in self.resource_dict[ req_info['method']][url_prefix]: callbacks_dict = self.resource_dict[ req_info['method']][url_prefix][url_param_count] callback = callbacks_dict['http_callback'] args = (req_info['body'], ) + params websocket_callbacks = { 'connected': callbacks_dict['connected'], 'msg_received': callbacks_dict['received'], 'closed': callbacks_dict['closed'], } return (callback, websocket_callbacks, args, req_info['clientsocket'], req_info['web_request_handler'], req_info['headers'], req_info['extra_response_headers']) return None def handle_request(self, callback, _websocket_callbacks, args, _clientsocket, _web_request_handler, headers, extra_response_headers): _version = headers['Sec-WebSocket-Version'] # only valid value is "13" _upgrade_value = headers['Upgrade'] # only valid value is "websocket" extra_response_headers['Upgrade'] = 'websocket' extra_response_headers['Connection'] = 'Upgrade' extra_response_headers[ 'Sec-WebSocket-Accept'] = WebSocketInterface.calc_response_nonce( headers['Sec-WebSocket-Key']) if callback is None: return b'' return callback(*args) def after_http_handled(self, _callback, websocket_callbacks, args, clientsocket, web_request_handler, _headers, _extra_response_headers): def msg_received(msg): if websocket_callbacks['msg_received'] is not None: websocket_callbacks['msg_received'](handler, msg, *args) clientsocket.settimeout(self.recv_timeout) handler = WebSocketHandler(web_request_handler, msg_received) if websocket_callbacks['connected'] is not None: websocket_callbacks['connected'](handler, *args) handler.run() if websocket_callbacks['closed'] is not None: websocket_callbacks['closed'](handler, *args) def get_possible_split_url_params(self, url): ret = [] split_url = url.split('/') remaining = split_url removed = [] while len(remaining) > 0: prefix = '/'.join(remaining) param_count = len(split_url) - len(remaining) params = removed[:param_count] if (prefix + '/') == url: ret.append((prefix, param_count, params)) param_count = param_count - 1 params = removed[:param_count] params_decoded = [] for par in params: params_decoded.append(url_decode(par)) params_decoded_tup = tuple(params_decoded) ret.append((prefix, param_count, params_decoded_tup)) removed = [remaining[-1]] + removed remaining = remaining[:-1] return ret def split_url_params(self, url): split_url = url.split('/:') prefix = split_url[0] param_count = len(split_url) - 1 return (prefix, param_count) def connect(self, resource, connected=None, received=None, closed=None, http_action=None, method='GET', body_included=False): def getattr_if_str(action): if isinstance(action, str): return getattr(self, action) else: return action connected_callback = getattr_if_str(connected) received_callback = getattr_if_str(received) closed_callback = getattr_if_str(closed) http_callback = getattr_if_str(http_action) self.connect_callback(resource, connected_callback, received_callback, closed_callback, http_callback, method, body_included=body_included) def connect_callback(self, resource, connected=None, received=None, closed=None, http_callback=None, method='GET', body_included=False): """ connects a specified callback (function) in this object to the specified resource (URL) and http method (GET/PUT/POST/DELETE) """ def gen_callback_no_body(cb, body_pos=0): def sub_callback(*args): return cb(*(args[:body_pos] + args[body_pos + 1:])) if cb is not None: return sub_callback else: return None def gen_callback_no_body_if_inluded(cb, body_pos=0): if body_included: return cb else: return gen_callback_no_body(cb, body_pos=body_pos) self.dispatcher = self.host.get_dispatcher() if method not in self.resource_dict: self.resource_dict[method] = {} (url_prefix, url_param_count) = self.split_url_params(resource) if url_prefix not in self.resource_dict[method]: self.resource_dict[method][url_prefix] = {} self.resource_dict[method][url_prefix][url_param_count] = { 'http_callback': gen_callback_no_body_if_inluded(http_callback), 'connected': gen_callback_no_body_if_inluded(connected, body_pos=1), 'received': gen_callback_no_body_if_inluded(received, body_pos=2), 'closed': gen_callback_no_body_if_inluded(closed, body_pos=1), } # log this connection on the host self.host.get_docs().log_connection(resource, http_callback, method, websock_actions={ 'connected': connected, 'received': received, 'closed': closed, }) def start_service(self): self.host.start_service() def stop_service(self): self.host.stop_service() @staticmethod def calc_response_nonce(client_nonce): nonce_hash = hashlib.sha1() nonce_hash.update(client_nonce.encode('utf-8')) nonce_hash.update(b'258EAFA5-E914-47DA-95CA-C5AB0DC85B11') return base64.b64encode(nonce_hash.digest()).decode('utf-8')