From 3cdc35306e2a1e152915fa19dcd806fd232d16a6 Mon Sep 17 00:00:00 2001 From: Nikolaos Ftylitakis Date: Tue, 11 May 2021 16:21:33 +0300 Subject: [PATCH 1/5] Support of pyend instruction for execution of commands right after page serving --- MicroWebSrv2/mods/PyhtmlTemplate.py | 85 ++++++++++++++++++++++------- 1 file changed, 65 insertions(+), 20 deletions(-) diff --git a/MicroWebSrv2/mods/PyhtmlTemplate.py b/MicroWebSrv2/mods/PyhtmlTemplate.py index 9fd2275..215090a 100644 --- a/MicroWebSrv2/mods/PyhtmlTemplate.py +++ b/MicroWebSrv2/mods/PyhtmlTemplate.py @@ -6,6 +6,7 @@ from os import stat import re +from _thread import start_new_thread # ============================================================================ # ===( MicroWebSrv2 : PyhtmlTemplate Module )================================= @@ -64,6 +65,7 @@ def ReturnTemplate(self, microWebSrv2, request, filepath): codeTemplate = CodeTemplate(code, microWebSrv2.HTMLEscape) content = codeTemplate.Execute(self._pyGlobalVars, None) request.Response.ReturnOk(content) + codeTemplate._handleEndPyCode() except Exception as ex : microWebSrv2.Log( 'Exception raised from pyhtml template file "%s": %s' % (filepath, ex), @@ -122,6 +124,7 @@ class CodeTemplate : TOKEN_CLOSE_LEN = len(TOKEN_CLOSE) INSTRUCTION_PYTHON = 'py' + INSTRUCTION_PYTHON_END = 'pyend' INSTRUCTION_IF = 'if' INSTRUCTION_ELIF = 'elif' INSTRUCTION_ELSE = 'else' @@ -141,8 +144,10 @@ def __init__(self, code, escapeStrFunc=None) : self._pyGlobalVars = { } self._pyLocalVars = { } self._rendered = '' + self._endPyCode = None self._instructions = { CodeTemplate.INSTRUCTION_PYTHON : self._processInstructionPYTHON, + CodeTemplate.INSTRUCTION_PYTHON_END : self._processInstructionPYTHONEND, CodeTemplate.INSTRUCTION_IF : self._processInstructionIF, CodeTemplate.INSTRUCTION_ELIF : self._processInstructionELIF, CodeTemplate.INSTRUCTION_ELSE : self._processInstructionELSE, @@ -262,26 +267,34 @@ def _processInstructionPYTHON(self, instructionBody, execute) : % (tokenContent, self._line) ) if execute : lines = pyCode.split('\n') - indent = '' - for line in lines : - if len(line.strip()) > 0 : - for c in line : - if c == ' ' or c == '\t' : - indent += c - else : - break - break - indentLen = len(indent) - for i in range(len(lines)) : - if lines[i].startswith(indent) : - lines[i] = lines[i][indentLen:] + '\n' - else : - lines[i] += '\n' - pyCode = ''.join(lines) - try : - exec(pyCode, self._pyGlobalVars, self._pyLocalVars) - except Exception as ex : - raise CodeTemplateException('%s (line %s)' % (ex, self._line)) + self._executePyCode(lines) + return None + + # ------------------------------------------------------------------------ + + def _processInstructionPYTHONEND(self, instructionBody, execute) : + if instructionBody is not None : + raise CodeTemplateException( 'Instruction "%s" is invalid (line %s)' + % (CodeTemplate.INSTRUCTION_PYTHON, self._line) ) + idx = self._code.find(CodeTemplate.TOKEN_OPEN, self._pos) + if idx < 0 : + raise CodeTemplateException('"%s" is required but the end of code has been found' % CodeTemplate.TOKEN_OPEN) + pyCode = self._code[self._pos:idx] + self._line += pyCode.count('\n') + self._pos = idx + CodeTemplate.TOKEN_OPEN_LEN + idx = self._code.find(CodeTemplate.TOKEN_CLOSE, self._pos) + if idx < 0 : + raise CodeTemplateException('"%s" is required but the end of code has been found' % CodeTemplate.TOKEN_CLOSE) + tokenContent = self._code[self._pos:idx].strip() + self._line += tokenContent.count('\n') + self._pos = idx + CodeTemplate.TOKEN_CLOSE_LEN + if tokenContent != CodeTemplate.INSTRUCTION_END : + raise CodeTemplateException( '"%s" is a bad instruction in a python bloc (line %s)' + % (tokenContent, self._line) ) + if execute : + self._endPyCode = pyCode.split('\n') + else: + self._endPyCode = None return None # ------------------------------------------------------------------------ @@ -389,6 +402,38 @@ def _processInstructionEND(self, instructionBody, execute) : % (CodeTemplate.INSTRUCTION_END, self._line) ) return CodeTemplate.INSTRUCTION_END + # ------------------------------------------------------------------------ + + def _handleEndPyCode(self) : + if self._endPyCode is None: + return + + start_new_thread(self._executePyCode, (self._endPyCode,)) + + # ------------------------------------------------------------------------ + + def _executePyCode(self, lines): + indent = '' + for line in lines : + if len(line.strip()) > 0 : + for c in line : + if c == ' ' or c == '\t' : + indent += c + else : + break + break + indentLen = len(indent) + for i in range(len(lines)) : + if lines[i].startswith(indent) : + lines[i] = lines[i][indentLen:] + '\n' + else : + lines[i] += '\n' + pyCode = ''.join(lines) + try : + exec(pyCode, self._pyGlobalVars, self._pyLocalVars) + except Exception as ex : + raise CodeTemplateException('%s (line %s)' % (ex, self._line)) + # ============================================================================ # ============================================================================ # ============================================================================ From 160b306d081692347d1d16fcb3e8d4573fb471cf Mon Sep 17 00:00:00 2001 From: Nikolaos Ftylitakis Date: Tue, 11 May 2021 16:32:38 +0300 Subject: [PATCH 2/5] Updated README with pyend info --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 58861cf..dda5912 100644 --- a/README.md +++ b/README.md @@ -1363,6 +1363,7 @@ except KeyboardInterrupt : | ELSE | `{{ else }}` *html bloc* `{{ end }}` | | FOR | `{{ for` *identifier* `in` *Python iterator* `}}` *html bloc* `{{ end }}` | | Expression | `{{` *Python expression* `}}` | + | PYEND | `{{ pyend }}` *Python code executed after page served* `{{ end }}` | :cyclone: See the **[test.pyhtml](https://github.com/jczic/MicroWebSrv2/blob/master/www/test.pyhtml)** page for the example: From 1ee2b39a78441995e0b652cbdc7ba248d76e4a36 Mon Sep 17 00:00:00 2001 From: Nikolaos Ftylitakis Date: Fri, 11 Jun 2021 16:01:24 +0300 Subject: [PATCH 3/5] fix module import statement for mods. --- MicroWebSrv2/microWebSrv2.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/MicroWebSrv2/microWebSrv2.py b/MicroWebSrv2/microWebSrv2.py index 97fc6fc..0dcef34 100644 --- a/MicroWebSrv2/microWebSrv2.py +++ b/MicroWebSrv2/microWebSrv2.py @@ -122,19 +122,21 @@ def LoadModule(modName) : raise ValueError('"modName" must be a not empty string.') if modName in MicroWebSrv2._modules : raise MicroWebSrv2Exception('Module "%s" is already loaded.' % modName) - try : - modPath = MicroWebSrv2.__module__.split('microWebSrv2')[0] \ - + ('mods.%s' % modName) - module = getattr(__import__(modPath).mods, modName) - modClass = getattr(module, modName) - if type(modClass) is not type : + try: + modPath = MicroWebSrv2.__module__.split('microWebSrv2')[0] + ('mods.%s' % modName) + obj = __import__(modPath, globals(), locals(), [], 0) + modClass = getattr(obj, modName) + if type(modClass) is not type: raise Exception modInstance = modClass() MicroWebSrv2._modules[modName] = modInstance return modInstance - except : + except Exception as e: + import sys + sys.print_exception(e) raise MicroWebSrv2Exception('Cannot load module "%s".' % modName) + # ------------------------------------------------------------------------ @staticmethod @@ -295,7 +297,7 @@ def _onSrvClosed(self, xAsyncTCPServer, closedReason) : def _validateChangeConf(self, name='Configuration') : if self._xasSrv : raise MicroWebSrv2Exception('%s cannot be changed while the server is running.' % name) - + # ------------------------------------------------------------------------ def EnableSSL(self, certFile, keyFile, caFile=None) : @@ -330,7 +332,7 @@ def DisableSSL(self) : if self._bindAddr[1] == 443 : self._bindAddr = (self._bindAddr[0], 80) - # ------------------------------------------------------------------------ + # ------------------------------------------------------------------------ def SetEmbeddedConfig(self) : self._validateChangeConf() From c8444a0ad450818bbab571c4af08342a5d04ec05 Mon Sep 17 00:00:00 2001 From: Nikolaos Ftylitakis Date: Fri, 11 Jun 2021 16:14:40 +0300 Subject: [PATCH 4/5] Removed WebSockets as it is unused deleted all comments to save 40KB of data --- MicroWebSrv2/httpRequest.py | 49 +-- MicroWebSrv2/httpResponse.py | 44 --- MicroWebSrv2/libs/XAsyncSockets.py | 106 ++----- MicroWebSrv2/libs/urlUtils.py | 17 +- MicroWebSrv2/microWebSrv2.py | 47 --- MicroWebSrv2/mods/PyhtmlTemplate.py | 39 +-- MicroWebSrv2/mods/WebSockets.py | 477 ---------------------------- MicroWebSrv2/webRoute.py | 37 +-- 8 files changed, 41 insertions(+), 775 deletions(-) delete mode 100644 MicroWebSrv2/mods/WebSockets.py diff --git a/MicroWebSrv2/httpRequest.py b/MicroWebSrv2/httpRequest.py index 0f1df1e..dab6861 100644 --- a/MicroWebSrv2/httpRequest.py +++ b/MicroWebSrv2/httpRequest.py @@ -9,27 +9,24 @@ from binascii import a2b_base64 import json -# ============================================================================ -# ===( HttpRequest )========================================================== -# ============================================================================ + + + class HttpRequest : MAX_RECV_HEADER_LINES = 100 - # ------------------------------------------------------------------------ def __init__(self, microWebSrv2, xasCli) : self._mws2 = microWebSrv2 self._xasCli = xasCli self._waitForRecvRequest() - # ------------------------------------------------------------------------ def _recvLine(self, onRecv) : self._xasCli.AsyncRecvLine(onLineRecv=onRecv, timeoutSec=self._mws2._timeoutSec) - # ------------------------------------------------------------------------ def _waitForRecvRequest(self) : self._httpVer = '' @@ -40,7 +37,6 @@ def _waitForRecvRequest(self) : self._response = HttpResponse(self._mws2, self) self._recvLine(self._onFirstLineRecv) - # ------------------------------------------------------------------------ def _onFirstLineRecv(self, xasCli, line, arg) : try : @@ -65,7 +61,6 @@ def _onFirstLineRecv(self, xasCli, line, arg) : except : self._response.ReturnBadRequest() - # ------------------------------------------------------------------------ def _onHeaderLineRecv(self, xasCli, line, arg) : try : @@ -83,7 +78,6 @@ def _onHeaderLineRecv(self, xasCli, line, arg) : except : self._response.ReturnBadRequest() - # ------------------------------------------------------------------------ def _processRequest(self) : if not self._processRequestModules() : @@ -113,7 +107,6 @@ def _processRequest(self) : else : self._response.ReturnNotImplemented() - # ------------------------------------------------------------------------ def _processRequestModules(self) : for modName, modInstance in self._mws2._modules.items() : @@ -127,7 +120,6 @@ def _processRequestModules(self) : self._mws2.ERROR ) return False - # ------------------------------------------------------------------------ def _processRequestRoutes(self) : self._routeResult = ResolveRoute(self._method, self._path) @@ -156,7 +148,6 @@ def onContentRecv(xasCli, content, arg) : return True return False - # ------------------------------------------------------------------------ def _routeRequest(self) : try : @@ -175,7 +166,6 @@ def _routeRequest(self) : self._mws2.ERROR ) self._response.ReturnInternalServerError() - # ------------------------------------------------------------------------ def GetPostedURLEncodedForm(self) : res = { } @@ -191,7 +181,6 @@ def GetPostedURLEncodedForm(self) : pass return res - # ------------------------------------------------------------------------ def GetPostedJSONObject(self) : if self.ContentType.lower() == 'application/json' : @@ -202,14 +191,12 @@ def GetPostedJSONObject(self) : pass return None - # ------------------------------------------------------------------------ def GetHeader(self, name) : if not isinstance(name, str) or len(name) == 0 : raise ValueError('"name" must be a not empty string.') return self._headers.get(name.lower(), '') - # ------------------------------------------------------------------------ def CheckBasicAuth(self, username, password) : if not isinstance(username, str) : @@ -229,7 +216,6 @@ def CheckBasicAuth(self, username, password) : pass return False - # ------------------------------------------------------------------------ def CheckBearerAuth(self, token) : if not isinstance(token, str) : @@ -245,55 +231,46 @@ def CheckBearerAuth(self, token) : pass return False - # ------------------------------------------------------------------------ @property def UserAddress(self) : return self._xasCli.CliAddr - # ------------------------------------------------------------------------ @property def IsSSL(self) : return self._xasCli.IsSSL - # ------------------------------------------------------------------------ @property def HttpVer(self) : return self._httpVer - # ------------------------------------------------------------------------ @property def Method(self) : return self._method - # ------------------------------------------------------------------------ @property def Path(self) : return self._path - # ------------------------------------------------------------------------ @property def QueryString(self) : return self._queryString - # ------------------------------------------------------------------------ @property def QueryParams(self) : return self._queryParams - # ------------------------------------------------------------------------ @property def Host(self) : return self._headers.get('host', '') - # ------------------------------------------------------------------------ @property def Accept(self) : @@ -302,7 +279,6 @@ def Accept(self) : return [x.strip() for x in s.split(',')] return [ ] - # ------------------------------------------------------------------------ @property def AcceptEncodings(self) : @@ -311,7 +287,6 @@ def AcceptEncodings(self) : return [x.strip() for x in s.split(',')] return [ ] - # ------------------------------------------------------------------------ @property def AcceptLanguages(self) : @@ -320,7 +295,6 @@ def AcceptLanguages(self) : return [x.strip() for x in s.split(',')] return [ ] - # ------------------------------------------------------------------------ @property def Cookies(self) : @@ -329,25 +303,21 @@ def Cookies(self) : return [x.strip() for x in s.split(';')] return [ ] - # ------------------------------------------------------------------------ @property def CacheControl(self) : return self._headers.get('cache-control', '') - # ------------------------------------------------------------------------ @property def Referer(self) : return self._headers.get('referer', '') - # ------------------------------------------------------------------------ @property def ContentType(self) : return self._headers.get('content-type', '').split(';', 1)[0].strip() - # ------------------------------------------------------------------------ @property def ContentLength(self) : @@ -356,60 +326,47 @@ def ContentLength(self) : except : return 0 - # ------------------------------------------------------------------------ @property def UserAgent(self) : return self._headers.get('user-agent', '') - # ------------------------------------------------------------------------ @property def Authorization(self) : return self._headers.get('authorization', '') - # ------------------------------------------------------------------------ @property def Origin(self) : return self._headers.get('origin', '') - # ------------------------------------------------------------------------ @property def IsKeepAlive(self) : return ('keep-alive' in self._headers.get('connection', '').lower()) - # ------------------------------------------------------------------------ @property def IsUpgrade(self) : return ('upgrade' in self._headers.get('connection', '').lower()) - # ------------------------------------------------------------------------ @property def Upgrade(self) : return self._headers.get('upgrade', '') - # ------------------------------------------------------------------------ @property def Content(self) : return self._content - # ------------------------------------------------------------------------ @property def Response(self) : return self._response - # ------------------------------------------------------------------------ @property def XAsyncTCPClient(self) : return self._xasCli - -# ============================================================================ -# ============================================================================ -# ============================================================================ diff --git a/MicroWebSrv2/httpResponse.py b/MicroWebSrv2/httpResponse.py index 3d5fbe1..3ea36f6 100644 --- a/MicroWebSrv2/httpResponse.py +++ b/MicroWebSrv2/httpResponse.py @@ -7,10 +7,6 @@ from os import stat import json -# ============================================================================ -# ===( HttpResponse )========================================================= -# ============================================================================ - class HttpResponse : _RESPONSE_CODES = { @@ -108,7 +104,6 @@ class HttpResponse : """ - # ------------------------------------------------------------------------ def __init__(self, microWebSrv2, request) : self._mws2 = microWebSrv2 @@ -125,7 +120,6 @@ def __init__(self, microWebSrv2, request) : self._hdrSent = False self._onSent = None - # ------------------------------------------------------------------------ def SetHeader(self, name, value) : if not isinstance(name, str) or len(name) == 0 : @@ -134,7 +128,6 @@ def SetHeader(self, name, value) : raise ValueError('"value" cannot be None.') self._headers[name] = str(value) - # ------------------------------------------------------------------------ def _onDataSent(self, xasCli, arg) : if self._stream : @@ -184,7 +177,6 @@ def onLastChunkSent(xasCli, arg) : self._mws2.Log( 'Exception raised from "Response.OnSent" handler: %s' % ex, self._mws2.ERROR ) - # ------------------------------------------------------------------------ def _onClosed(self, xasCli, closedReason) : if self._stream : @@ -195,7 +187,6 @@ def _onClosed(self, xasCli, closedReason) : self._stream = None self._sendingBuf = None - # ------------------------------------------------------------------------ def _makeBaseResponseHdr(self, code) : reason = self._RESPONSE_CODES.get(code, ('Unknown reason', ))[0] @@ -219,7 +210,6 @@ def _makeBaseResponseHdr(self, code) : resp = 'HTTP/1.1 %s %s\r\n%s\r\n' % (code, reason, hdr) return resp.encode('ISO-8859-1') - # ------------------------------------------------------------------------ def _makeResponseHdr(self, code) : if code >= 200 and code < 300 : @@ -244,7 +234,6 @@ def _makeResponseHdr(self, code) : self.SetHeader('Content-Length', self._contentLength) return self._makeBaseResponseHdr(code) - # ------------------------------------------------------------------------ def SwitchingProtocols(self, upgrade) : if not isinstance(upgrade, str) or len(upgrade) == 0 : @@ -260,7 +249,6 @@ def SwitchingProtocols(self, upgrade) : self._xasCli.AsyncSendData(data) self._hdrSent = True - # ------------------------------------------------------------------------ def ReturnStream(self, code, stream) : if not isinstance(code, int) or code <= 0 : @@ -293,7 +281,6 @@ def ReturnStream(self, code, stream) : self._xasCli.AsyncSendData(data, onDataSent=self._onDataSent) self._hdrSent = True - # ------------------------------------------------------------------------ def Return(self, code, content=None) : if not isinstance(code, int) or code <= 0 : @@ -323,7 +310,6 @@ def Return(self, code, content=None) : self._xasCli.AsyncSendData(data, onDataSent=self._onDataSent) self._hdrSent = True - # ------------------------------------------------------------------------ def ReturnJSON(self, code, obj) : if not isinstance(code, int) or code <= 0 : @@ -335,17 +321,14 @@ def ReturnJSON(self, code, obj) : raise ValueError('"obj" cannot be converted into JSON format.') self.Return(code, content) - # ------------------------------------------------------------------------ def ReturnOk(self, content=None) : self.Return(200, content) - # ------------------------------------------------------------------------ def ReturnOkJSON(self, obj) : self.ReturnJSON(200, obj) - # ------------------------------------------------------------------------ def ReturnFile(self, filename, attachmentName=None) : if not isinstance(filename, str) or len(filename) == 0 : @@ -370,12 +353,10 @@ def ReturnFile(self, filename, attachmentName=None) : self._contentLength = size self.ReturnStream(200, file) - # ------------------------------------------------------------------------ def ReturnNotModified(self) : self.Return(304) - # ------------------------------------------------------------------------ def ReturnRedirect(self, location) : if not isinstance(location, str) or len(location) == 0 : @@ -383,12 +364,10 @@ def ReturnRedirect(self, location) : self.SetHeader('Location', location) self.Return(307) - # ------------------------------------------------------------------------ def ReturnBadRequest(self) : self.Return(400) - # ------------------------------------------------------------------------ def ReturnUnauthorized(self, typeName, realm=None) : if not isinstance(typeName, str) or len(typeName) == 0 : @@ -401,12 +380,10 @@ def ReturnUnauthorized(self, typeName, realm=None) : self.SetHeader('WWW-Authenticate', wwwAuth) self.Return(401) - # ------------------------------------------------------------------------ def ReturnForbidden(self) : self.Return(403) - # ------------------------------------------------------------------------ def ReturnNotFound(self) : if self._mws2._notFoundURL : @@ -414,60 +391,49 @@ def ReturnNotFound(self) : else : self.Return(404) - # ------------------------------------------------------------------------ def ReturnMethodNotAllowed(self) : self.Return(405) - # ------------------------------------------------------------------------ def ReturnEntityTooLarge(self) : self.Return(413) - # ------------------------------------------------------------------------ def ReturnInternalServerError(self) : self.Return(500) - # ------------------------------------------------------------------------ def ReturnNotImplemented(self) : self.Return(501) - # ------------------------------------------------------------------------ def ReturnServiceUnavailable(self) : self.Return(503) - # ------------------------------------------------------------------------ def ReturnBasicAuthRequired(self) : self.ReturnUnauthorized('Basic') - # ------------------------------------------------------------------------ def ReturnBearerAuthRequired(self) : self.ReturnUnauthorized('Bearer') - # ------------------------------------------------------------------------ @property def Request(self) : return self._request - # ------------------------------------------------------------------------ @property def UserAddress(self) : return self._xasCli.CliAddr - # ------------------------------------------------------------------------ @property def IsSSL(self) : return self._xasCli.IsSSL - # ------------------------------------------------------------------------ @property def AllowCaching(self) : @@ -479,7 +445,6 @@ def AllowCaching(self, value) : raise ValueError('"AllowCaching" must be a boolean.') self._allowCaching = value - # ------------------------------------------------------------------------ @property def AccessControlAllowOrigin(self) : @@ -491,7 +456,6 @@ def AccessControlAllowOrigin(self, value) : raise ValueError('"AccessControlAllowOrigin" must be a string or None.') self._acAllowOrigin = value - # ------------------------------------------------------------------------ @property def ContentType(self) : @@ -503,7 +467,6 @@ def ContentType(self, value) : raise ValueError('"ContentType" must be a string or None.') self._contentType = value - # ------------------------------------------------------------------------ @property def ContentCharset(self) : @@ -515,7 +478,6 @@ def ContentCharset(self, value) : raise ValueError('"ContentCharset" must be a string or None.') self._contentCharset = value - # ------------------------------------------------------------------------ @property def ContentLength(self) : @@ -527,13 +489,11 @@ def ContentLength(self, value) : raise ValueError('"ContentLength" must be a positive integer or zero.') self._contentLength = value - # ------------------------------------------------------------------------ @property def HeadersSent(self) : return self._hdrSent - # ------------------------------------------------------------------------ @property def OnSent(self) : @@ -544,7 +504,3 @@ def OnSent(self, value) : if type(value) is not type(lambda x:x) : raise ValueError('"OnSent" must be a function.') self._onSent = value - -# ============================================================================ -# ============================================================================ -# ============================================================================ diff --git a/MicroWebSrv2/libs/XAsyncSockets.py b/MicroWebSrv2/libs/XAsyncSockets.py index 836fed0..c8f7424 100644 --- a/MicroWebSrv2/libs/XAsyncSockets.py +++ b/MicroWebSrv2/libs/XAsyncSockets.py @@ -17,9 +17,9 @@ def perf_counter() : return ticks_ms() / 1000 -# ============================================================================ -# ===( XAsyncSocketsPool )==================================================== -# ============================================================================ + + + class XAsyncSocketsPoolException(Exception) : pass @@ -35,21 +35,18 @@ def __init__(self) : self._writeList = [ ] self._handlingList = [ ] - # ------------------------------------------------------------------------ def _incThreadsCount(self) : self._opLock.acquire() self._threadsCount += 1 self._opLock.release() - # ------------------------------------------------------------------------ def _decThreadsCount(self) : self._opLock.acquire() self._threadsCount -= 1 self._opLock.release() - # ------------------------------------------------------------------------ def _addSocket(self, socket, asyncSocket) : if socket : @@ -62,7 +59,6 @@ def _addSocket(self, socket, asyncSocket) : return ok return False - # ------------------------------------------------------------------------ def _removeSocket(self, socket) : if socket : @@ -79,7 +75,6 @@ def _removeSocket(self, socket) : return ok return False - # ------------------------------------------------------------------------ def _socketListAdd(self, socket, socketsList) : self._opLock.acquire() @@ -89,7 +84,6 @@ def _socketListAdd(self, socket, socketsList) : self._opLock.release() return ok - # ------------------------------------------------------------------------ def _socketListRemove(self, socket, socketsList) : self._opLock.acquire() @@ -99,7 +93,6 @@ def _socketListRemove(self, socket, socketsList) : self._opLock.release() return ok - # ------------------------------------------------------------------------ _CHECK_SEC_INTERVAL = 1.0 @@ -141,7 +134,6 @@ def _processWaitEvents(self) : self._processing = False self._decThreadsCount() - # ------------------------------------------------------------------------ def AddAsyncSocket(self, asyncSocket) : try : @@ -150,7 +142,6 @@ def AddAsyncSocket(self, asyncSocket) : raise XAsyncSocketsPoolException('AddAsyncSocket : "asyncSocket" is incorrect.') return self._addSocket(socket, asyncSocket) - # ------------------------------------------------------------------------ def RemoveAsyncSocket(self, asyncSocket) : try : @@ -159,17 +150,14 @@ def RemoveAsyncSocket(self, asyncSocket) : raise XAsyncSocketsPoolException('RemoveAsyncSocket : "asyncSocket" is incorrect.') return self._removeSocket(socket) - # ------------------------------------------------------------------------ def GetAllAsyncSockets(self) : return list(self._asyncSockets.values()) - # ------------------------------------------------------------------------ def GetAsyncSocketByID(self, id) : return self._asyncSockets.get(id, None) - # ------------------------------------------------------------------------ def NotifyNextReadyForReading(self, asyncSocket, notify) : try : @@ -181,7 +169,6 @@ def NotifyNextReadyForReading(self, asyncSocket, notify) : else : self._socketListRemove(socket, self._readList) - # ------------------------------------------------------------------------ def NotifyNextReadyForWriting(self, asyncSocket, notify) : try : @@ -193,7 +180,6 @@ def NotifyNextReadyForWriting(self, asyncSocket, notify) : else : self._socketListRemove(socket, self._writeList) - # ------------------------------------------------------------------------ def AsyncWaitEvents(self, threadsCount=0) : if self._processing or self._threadsCount : @@ -211,22 +197,20 @@ def AsyncWaitEvents(self, threadsCount=0) : else : self._processWaitEvents() - # ------------------------------------------------------------------------ def StopWaitEvents(self) : self._processing = False while self._threadsCount : sleep(0.001) - # ------------------------------------------------------------------------ @property def WaitEventsProcessing(self) : return (self._threadsCount > 0) -# ============================================================================ -# ===( XClosedReason )======================================================== -# ============================================================================ + + + class XClosedReason() : @@ -235,9 +219,9 @@ class XClosedReason() : ClosedByPeer = 0x02 Timeout = 0x03 -# ============================================================================ -# ===( XAsyncSocket )========================================================= -# ============================================================================ + + + class XAsyncSocketException(Exception) : pass @@ -264,7 +248,6 @@ def __init__(self, asyncSocketsPool, socket, recvBufSlot=None, sendBufSlot=None) except : raise XAsyncSocketException('XAsyncSocket : Arguments are incorrects.') - # ------------------------------------------------------------------------ def _setExpireTimeout(self, timeoutSec) : try : @@ -273,12 +256,10 @@ def _setExpireTimeout(self, timeoutSec) : except : raise XAsyncSocketException('"timeoutSec" is incorrect to set expire timeout.') - # ------------------------------------------------------------------------ def _removeExpireTimeout(self) : self._expireTimeSec = None - # ------------------------------------------------------------------------ def _close(self, closedReason=XClosedReason.Error, triggerOnClosed=True) : if self._asyncSocketsPool.RemoveAsyncSocket(self) : @@ -301,37 +282,30 @@ def _close(self, closedReason=XClosedReason.Error, triggerOnClosed=True) : return True return False - # ------------------------------------------------------------------------ def GetAsyncSocketsPool(self) : return self._asyncSocketsPool - # ------------------------------------------------------------------------ def GetSocketObj(self) : return self._socket - # ------------------------------------------------------------------------ def Close(self) : return self._close(XClosedReason.ClosedByHost) - # ------------------------------------------------------------------------ def OnReadyForReading(self) : pass - # ------------------------------------------------------------------------ def OnReadyForWriting(self) : pass - # ------------------------------------------------------------------------ def OnExceptionalCondition(self) : self._close() - # ------------------------------------------------------------------------ @property def SocketID(self) : @@ -355,9 +329,9 @@ def State(self) : def State(self, value) : self._state = value -# ============================================================================ -# ===( XAsyncTCPServer )====================================================== -# ============================================================================ + + + class XAsyncTCPServerException(Exception) : pass @@ -385,7 +359,6 @@ def Create(asyncSocketsPool, srvAddr, srvBacklog=256, bufSlots=None) : asyncSocketsPool.NotifyNextReadyForReading(xAsyncTCPServer, True) return xAsyncTCPServer - # ------------------------------------------------------------------------ def __init__(self, asyncSocketsPool, srvSocket, srvAddr, bufSlots) : try : @@ -396,7 +369,6 @@ def __init__(self, asyncSocketsPool, srvSocket, srvAddr, bufSlots) : except : raise XAsyncTCPServerException('Error to creating XAsyncTCPServer, arguments are incorrects.') - # ------------------------------------------------------------------------ def OnReadyForReading(self) : try : @@ -424,7 +396,6 @@ def OnReadyForReading(self) : asyncTCPCli._close() raise XAsyncTCPServerException('Error when handling the "OnClientAccepted" event : %s' % ex) - # ------------------------------------------------------------------------ @property def SrvAddr(self) : @@ -437,9 +408,9 @@ def OnClientAccepted(self) : def OnClientAccepted(self, value) : self._onClientAccepted = value -# ============================================================================ -# ===( XAsyncTCPClient )====================================================== -# ============================================================================ + + + class XAsyncTCPClientException(Exception) : pass @@ -508,7 +479,6 @@ def Create( asyncSocketsPool, asyncTCPCli._close() return None - # ------------------------------------------------------------------------ def __init__(self, asyncSocketsPool, cliSocket, srvAddr, cliAddr, recvBufSlot, sendBufSlot) : try : @@ -530,7 +500,6 @@ def __init__(self, asyncSocketsPool, cliSocket, srvAddr, cliAddr, recvBufSlot, s except : raise XAsyncTCPClientException('Error to creating XAsyncTCPClient, arguments are incorrects.') - # ------------------------------------------------------------------------ def Close(self) : if self._wrBufView : @@ -544,7 +513,6 @@ def Close(self) : pass return self._close(XClosedReason.ClosedByHost) - # ------------------------------------------------------------------------ def OnReadyForReading(self) : while True : @@ -570,7 +538,7 @@ def OnReadyForReading(self) : return if b : if b == b'\n' : - lineLen = self._rdLinePos + lineLen = self._rdLinePos self._rdLinePos = None self._asyncSocketsPool.NotifyNextReadyForReading(self, False) self._removeExpireTimeout() @@ -639,7 +607,6 @@ def OnReadyForReading(self) : else : return - # ------------------------------------------------------------------------ def OnReadyForWriting(self) : if not self._socketOpened : @@ -674,7 +641,6 @@ def OnReadyForWriting(self) : except Exception as ex : raise XAsyncTCPClientException('Error when handling the "OnDataSent" event : %s' % ex) - # ------------------------------------------------------------------------ def AsyncRecvLine(self, lineEncoding='UTF-8', onLineRecv=None, onLineRecvArg=None, timeoutSec=None) : if self._rdLinePos is not None or self._sizeToRecv : @@ -689,7 +655,6 @@ def AsyncRecvLine(self, lineEncoding='UTF-8', onLineRecv=None, onLineRecvArg=Non return True return False - # ------------------------------------------------------------------------ def AsyncRecvData(self, size=None, onDataRecv=None, onDataRecvArg=None, timeoutSec=None) : if self._rdLinePos is not None or self._sizeToRecv : @@ -714,7 +679,6 @@ def AsyncRecvData(self, size=None, onDataRecv=None, onDataRecvArg=None, timeoutS return True return False - # ------------------------------------------------------------------------ def AsyncSendData(self, data, onDataSent=None, onDataSentArg=None) : if self._socket : @@ -734,7 +698,6 @@ def AsyncSendData(self, data, onDataSent=None, onDataSentArg=None) : raise XAsyncTCPClientException('AsyncSendData : "data" is incorrect.') return False - # ------------------------------------------------------------------------ def AsyncSendSendingBuffer(self, size=None, onDataSent=None, onDataSentArg=None) : if self._wrBufView : @@ -750,7 +713,6 @@ def AsyncSendSendingBuffer(self, size=None, onDataSent=None, onDataSentArg=None) return True return False - # ------------------------------------------------------------------------ def _doSSLHandshake(self) : count = 0 @@ -769,7 +731,6 @@ def _doSSLHandshake(self) : except Exception as ex : raise XAsyncTCPClientException('SSL : Handshake error : %s' % ex) - # ------------------------------------------------------------------------ def StartSSL( self, keyfile = None, @@ -795,7 +756,6 @@ def StartSSL( self, raise XAsyncTCPClientException('StartSSL : %s' % ex) self._doSSLHandshake() - # ------------------------------------------------------------------------ def StartSSLContext(self, sslContext, serverSide=False) : if not hasattr(ssl, 'SSLContext') : @@ -814,7 +774,6 @@ def StartSSLContext(self, sslContext, serverSide=False) : raise XAsyncTCPClientException('StartSSLContext : %s' % ex) self._doSSLHandshake() - # ------------------------------------------------------------------------ @property def SrvAddr(self) : @@ -847,9 +806,9 @@ def OnConnected(self) : def OnConnected(self, value) : self._onConnected = value -# ============================================================================ -# ===( XAsyncUDPDatagram )==================================================== -# ============================================================================ + + + class XAsyncUDPDatagramException(Exception) : pass @@ -883,7 +842,6 @@ def Create(asyncSocketsPool, localAddr=None, recvBufLen=4096, broadcast=False) : asyncSocketsPool.NotifyNextReadyForReading(xAsyncUDPDatagram, True) return xAsyncUDPDatagram - # ------------------------------------------------------------------------ def __init__(self, asyncSocketsPool, udpSocket, recvBufSlot) : try : @@ -896,7 +854,6 @@ def __init__(self, asyncSocketsPool, udpSocket, recvBufSlot) : except : raise XAsyncUDPDatagramException('Error to creating XAsyncUDPDatagram, arguments are incorrects.') - # ------------------------------------------------------------------------ def OnReadyForReading(self) : try : @@ -914,7 +871,6 @@ def OnReadyForReading(self) : except Exception as ex : raise XAsyncUDPDatagramException('Error when handling the "OnDataRecv" event : %s' % ex) - # ------------------------------------------------------------------------ def OnReadyForWriting(self) : if not self._wrDgramFiFo.Empty : @@ -938,7 +894,6 @@ def OnReadyForWriting(self) : except Exception as ex : raise XAsyncUDPDatagramException('Error when handling the "OnDataSent" event : %s' % ex) - # ------------------------------------------------------------------------ def AsyncSendDatagram(self, datagram, remoteAddr, onDataSent=None, onDataSentArg=None) : if self._socket : @@ -954,7 +909,6 @@ def AsyncSendDatagram(self, datagram, remoteAddr, onDataSent=None, onDataSentArg raise XAsyncUDPDatagramException('AsyncSendDatagram : Arguments are incorrects.') return False - # ------------------------------------------------------------------------ @property def LocalAddr(self) : @@ -977,9 +931,9 @@ def OnFailsToSend(self) : def OnFailsToSend(self, value) : self._onFailsToSend = value -# ============================================================================ -# ===( XBufferSlot )========================================================== -# ============================================================================ + + + class XBufferSlot : @@ -1009,9 +963,9 @@ def Buffer(self) : self._buffer = bytearray(self._size) return self._buffer -# ============================================================================ -# ===( XBufferSlots )========================================================= -# ============================================================================ + + + class XBufferSlots : @@ -1046,9 +1000,9 @@ def SlotsSize(self) : def Slots(self) : return self._slots -# ============================================================================ -# ===( XFiFo )================================================================ -# ============================================================================ + + + class XFiFoException(Exception) : pass @@ -1088,7 +1042,3 @@ def Clear(self) : @property def Empty(self) : return (self._first is None) - -# ============================================================================ -# ============================================================================ -# ============================================================================ diff --git a/MicroWebSrv2/libs/urlUtils.py b/MicroWebSrv2/libs/urlUtils.py index c7eac88..c5b45a6 100644 --- a/MicroWebSrv2/libs/urlUtils.py +++ b/MicroWebSrv2/libs/urlUtils.py @@ -6,7 +6,6 @@ class UrlUtils : - # ---------------------------------------------------------------------------- @staticmethod def Quote(s, safe='/') : @@ -22,13 +21,11 @@ def Quote(s, safe='/') : r += '%%%02X' % b return r - # ---------------------------------------------------------------------------- @staticmethod def UrlEncode(s) : return UrlUtils.Quote(s, ';/?:@&=+$,') - # ---------------------------------------------------------------------------- @staticmethod def Unquote(s) : @@ -44,7 +41,6 @@ def Unquote(s) : except : return str(s) - # ---------------------------------------------------------------------------- @staticmethod def UnquotePlus(s) : @@ -55,21 +51,18 @@ def UnquotePlus(s) : # ============================================================================ class Url : - + def __init__(self, url='') : self.URL = url - # ------------------------------------------------------------------------ def __repr__(self) : return self.URL if self.URL is not None else '' - # ------------------------------------------------------------------------ def IsHttps(self) : return (self._proto == 'https') - # ------------------------------------------------------------------------ @property def URL(self) : @@ -119,7 +112,6 @@ def URL(self, value) : self._queryParams = { } self.Path = path - # ------------------------------------------------------------------------ @property def Proto(self) : @@ -136,17 +128,15 @@ def Proto(self, value) : raise ValueError('Unsupported URL protocol (%s)' % value) self._proto = value - # ------------------------------------------------------------------------ @property def Host(self) : return self._host - + @Host.setter def Host(self, value) : self._host = UrlUtils.UnquotePlus(value) - # ------------------------------------------------------------------------ @property def Port(self) : @@ -162,7 +152,6 @@ def Port(self, value) : raise ValueError('Port must be greater than 0 and less than 65536') self._port = p - # ------------------------------------------------------------------------ @property def Path(self) : @@ -180,7 +169,6 @@ def Path(self, value) : if len(x) == 2 : self.QueryString = x[1] - # ------------------------------------------------------------------------ @property def QueryString(self) : @@ -201,7 +189,6 @@ def QueryString(self, value) : value = UrlUtils.Unquote(param[1]) if len(param) > 1 else '' self._queryParams[UrlUtils.Unquote(param[0])] = value - # ------------------------------------------------------------------------ @property def QueryParams(self) : diff --git a/MicroWebSrv2/microWebSrv2.py b/MicroWebSrv2/microWebSrv2.py index 0dcef34..c26b870 100644 --- a/MicroWebSrv2/microWebSrv2.py +++ b/MicroWebSrv2/microWebSrv2.py @@ -10,14 +10,9 @@ from sys import implementation from _thread import stack_size -# ============================================================================ -# ===( MicroWebSrv2 )========================================================= -# ============================================================================ - class MicroWebSrv2Exception(Exception) : pass -# ---------------------------------------------------------------------------- class MicroWebSrv2 : @@ -74,11 +69,9 @@ class MicroWebSrv2 : ERROR : 'ERROR' } - # ------------------------------------------------------------------------ _modules = { } - # ------------------------------------------------------------------------ def __init__(self) : self._backlog = None @@ -98,7 +91,6 @@ def __init__(self) : self._xasPool = None self.SetNormalConfig() - # ------------------------------------------------------------------------ @staticmethod def _physPathExists(physPath) : @@ -108,13 +100,11 @@ def _physPathExists(physPath) : except : return False - # ------------------------------------------------------------------------ @staticmethod def _physPathIsDir(physPath) : return (stat(physPath)[0] & MicroWebSrv2._STAT_MODE_DIR != 0) - # ------------------------------------------------------------------------ @staticmethod def LoadModule(modName) : @@ -137,15 +127,12 @@ def LoadModule(modName) : raise MicroWebSrv2Exception('Cannot load module "%s".' % modName) - # ------------------------------------------------------------------------ - @staticmethod def HTMLEscape(s) : if not isinstance(s, str) : raise ValueError('"s" must be a string.') return ''.join(MicroWebSrv2._HTML_ESCAPE_CHARS.get(c, c) for c in s) - # ------------------------------------------------------------------------ @staticmethod def AddDefaultPage(filename) : @@ -153,7 +140,6 @@ def AddDefaultPage(filename) : raise ValueError('"filename" must be a not empty string.') MicroWebSrv2._DEFAULT_PAGES.append(filename) - # ------------------------------------------------------------------------ @staticmethod def AddMimeType(ext, mimeType) : @@ -163,7 +149,6 @@ def AddMimeType(ext, mimeType) : raise ValueError('"mimeType" must be a not empty string.') MicroWebSrv2._MIME_TYPES[ext.lower()] = mimeType.lower() - # ------------------------------------------------------------------------ @staticmethod def GetMimeTypeFromFilename(filename) : @@ -173,7 +158,6 @@ def GetMimeTypeFromFilename(filename) : return MicroWebSrv2._MIME_TYPES[ext] return None - # ------------------------------------------------------------------------ def StartInPool(self, asyncSocketsPool) : if not isinstance(asyncSocketsPool, XAsyncSocketsPool) : @@ -197,7 +181,6 @@ def StartInPool(self, asyncSocketsPool) : self._xasSrv.OnClosed = self._onSrvClosed self.Log('Server listening on %s:%s.' % self._bindAddr, MicroWebSrv2.INFO) - # ------------------------------------------------------------------------ def StartManaged(self, parllProcCount=1, procStackSize=0) : if not isinstance(parllProcCount, int) or parllProcCount < 0 : @@ -229,7 +212,6 @@ def StartManaged(self, parllProcCount=1, procStackSize=0) : except : pass - # ------------------------------------------------------------------------ def Stop(self) : if self._xasSrv : @@ -240,7 +222,6 @@ def Stop(self) : self._xasPool.StopWaitEvents() self._xasPool = None - # ------------------------------------------------------------------------ def Log(self, msg, msgType) : if self._onLogging : @@ -254,7 +235,6 @@ def Log(self, msg, msgType) : if t : print('MWS2-%s> %s' % (t, msg)) - # ------------------------------------------------------------------------ def ResolvePhysicalPath(self, urlPath) : if not isinstance(urlPath, str) or len(urlPath) == 0 : @@ -272,7 +252,6 @@ def ResolvePhysicalPath(self, urlPath) : except : return None - # ------------------------------------------------------------------------ def _onSrvClientAccepted(self, xAsyncTCPServer, xAsyncTCPClient) : if self._sslContext : @@ -287,18 +266,15 @@ def _onSrvClientAccepted(self, xAsyncTCPServer, xAsyncTCPClient) : return HttpRequest(self, xAsyncTCPClient) - # ------------------------------------------------------------------------ def _onSrvClosed(self, xAsyncTCPServer, closedReason) : self.Log('Server %s:%s closed.' % self._bindAddr, MicroWebSrv2.INFO) - # ------------------------------------------------------------------------ def _validateChangeConf(self, name='Configuration') : if self._xasSrv : raise MicroWebSrv2Exception('%s cannot be changed while the server is running.' % name) - # ------------------------------------------------------------------------ def EnableSSL(self, certFile, keyFile, caFile=None) : import ssl @@ -324,7 +300,6 @@ def EnableSSL(self, certFile, keyFile, caFile=None) : if self._bindAddr[1] == 80 : self._bindAddr = (self._bindAddr[0], 443) - # ------------------------------------------------------------------------ def DisableSSL(self) : self._validateChangeConf() @@ -332,7 +307,6 @@ def DisableSSL(self) : if self._bindAddr[1] == 443 : self._bindAddr = (self._bindAddr[0], 80) - # ------------------------------------------------------------------------ def SetEmbeddedConfig(self) : self._validateChangeConf() @@ -342,7 +316,6 @@ def SetEmbeddedConfig(self) : self._keepAlloc = True self._maxContentLen = 16*1024 - # ------------------------------------------------------------------------ def SetLightConfig(self) : self._validateChangeConf() @@ -352,7 +325,6 @@ def SetLightConfig(self) : self._keepAlloc = True self._maxContentLen = 512*1024 - # ------------------------------------------------------------------------ def SetNormalConfig(self) : self._validateChangeConf() @@ -362,7 +334,6 @@ def SetNormalConfig(self) : self._keepAlloc = True self._maxContentLen = 2*1024*1024 - # ------------------------------------------------------------------------ def SetLargeConfig(self) : self._validateChangeConf() @@ -372,7 +343,6 @@ def SetLargeConfig(self) : self._keepAlloc = True self._maxContentLen = 8*1024*1024 - # ------------------------------------------------------------------------ @property def IsRunning(self) : @@ -380,7 +350,6 @@ def IsRunning(self) : self._xasPool.WaitEventsProcessing and \ self._xasSrv is not None ) - # ------------------------------------------------------------------------ @property def ConnQueueCapacity(self) : @@ -393,7 +362,6 @@ def ConnQueueCapacity(self, value) : self._validateChangeConf('"ConnQueueCapacity"') self._backlog = value - # ------------------------------------------------------------------------ @property def BufferSlotsCount(self) : @@ -406,7 +374,6 @@ def BufferSlotsCount(self, value) : self._validateChangeConf('"BufferSlotsCount"') self._slotsCount = value - # ------------------------------------------------------------------------ @property def BufferSlotSize(self) : @@ -419,7 +386,6 @@ def BufferSlotSize(self, value) : self._validateChangeConf('"BufferSlotSize"') self._slotsSize = value - # ------------------------------------------------------------------------ @property def KeepAllocBufferSlots(self) : @@ -432,7 +398,6 @@ def KeepAllocBufferSlots(self, value) : self._validateChangeConf('"KeepAllocBufferSlots"') self._keepAlloc = value - # ------------------------------------------------------------------------ @property def MaxRequestContentLength(self) : @@ -444,7 +409,6 @@ def MaxRequestContentLength(self, value) : raise ValueError('"MaxRequestContentLength" must be a positive integer.') self._maxContentLen = value - # ------------------------------------------------------------------------ @property def BindAddress(self) : @@ -461,13 +425,11 @@ def BindAddress(self, value) : self._validateChangeConf('"BindAddress"') self._bindAddr = value - # ------------------------------------------------------------------------ @property def IsSSLEnabled(self) : return (self._sslContext is not None) - # ------------------------------------------------------------------------ @property def RootPath(self) : @@ -480,7 +442,6 @@ def RootPath(self, value) : self._validateChangeConf('"RootPath"') self._rootPath = (value[:-1] if value.endswith('/') else value) - # ------------------------------------------------------------------------ @property def RequestsTimeoutSec(self) : @@ -492,7 +453,6 @@ def RequestsTimeoutSec(self, value) : raise ValueError('"RequestsTimeoutSec" must be a positive integer.') self._timeoutSec = value - # ------------------------------------------------------------------------ @property def NotFoundURL(self) : @@ -504,7 +464,6 @@ def NotFoundURL(self, value) : raise ValueError('"NotFoundURL" must be a string or None.') self._notFoundURL = value - # ------------------------------------------------------------------------ @property def AllowAllOrigins(self) : @@ -516,7 +475,6 @@ def AllowAllOrigins(self, value) : raise ValueError('"AllowAllOrigins" must be a boolean.') self._allowAllOrigins = value - # ------------------------------------------------------------------------ @property def CORSAllowAll(self) : @@ -528,7 +486,6 @@ def CORSAllowAll(self, value) : raise ValueError('"CORSAllowAll" must be a boolean.') self._corsAllowAll = value - # ------------------------------------------------------------------------ @property def OnLogging(self) : @@ -539,7 +496,3 @@ def OnLogging(self, value) : if type(value) is not type(lambda x:x) : raise ValueError('"OnLogging" must be a function.') self._onLogging = value - -# ============================================================================ -# ============================================================================ -# ============================================================================ diff --git a/MicroWebSrv2/mods/PyhtmlTemplate.py b/MicroWebSrv2/mods/PyhtmlTemplate.py index 215090a..b6725d4 100644 --- a/MicroWebSrv2/mods/PyhtmlTemplate.py +++ b/MicroWebSrv2/mods/PyhtmlTemplate.py @@ -8,9 +8,9 @@ import re from _thread import start_new_thread -# ============================================================================ -# ===( MicroWebSrv2 : PyhtmlTemplate Module )================================= -# ============================================================================ + +: PyhtmlTemplate Module )================================= + class PyhtmlTemplate : @@ -32,13 +32,11 @@ class PyhtmlTemplate : """ - # ------------------------------------------------------------------------ def __init__(self) : self._showDebug = False self._pyGlobalVars = { } - # ------------------------------------------------------------------------ def OnRequest(self, microWebSrv2, request) : if (request.Method == 'GET' or request.Method == 'HEAD') and \ @@ -46,7 +44,6 @@ def OnRequest(self, microWebSrv2, request) : filepath = microWebSrv2.ResolvePhysicalPath(request.Path) self.ReturnTemplate(microWebSrv2, request, filepath) - # ------------------------------------------------------------------------ def ReturnTemplate(self, microWebSrv2, request, filepath): if not filepath: @@ -78,14 +75,12 @@ def ReturnTemplate(self, microWebSrv2, request, filepath): else : request.Response.ReturnInternalServerError() - # ------------------------------------------------------------------------ def SetGlobalVar(self, globalVarName, globalVar) : if not isinstance(globalVarName, str) or len(globalVarName) == 0 : raise ValueError('"globalVarName" must be a not empty string.') self._pyGlobalVars[globalVarName] = globalVar - # ------------------------------------------------------------------------ def GetGlobalVar(self, globalVarName) : if not isinstance(globalVarName, str) or len(globalVarName) == 0 : @@ -95,7 +90,6 @@ def GetGlobalVar(self, globalVarName) : except : return None - # ------------------------------------------------------------------------ @property def ShowDebug(self) : @@ -107,16 +101,15 @@ def ShowDebug(self, value) : raise ValueError('"ShowDebug" must be a boolean.') self._showDebug = value -# ============================================================================ -# ===( CodeTemplate )========================================================= -# ============================================================================ + + + class CodeTemplateException(Exception) : pass class CodeTemplate : - # ------------------------------------------------------------------------ TOKEN_OPEN = '{{' TOKEN_CLOSE = '}}' @@ -133,7 +126,6 @@ class CodeTemplate : RE_IDENTIFIER = re.compile(r'[a-zA-Z_][a-zA-Z0-9_]*$') - # ------------------------------------------------------------------------ def __init__(self, code, escapeStrFunc=None) : self._code = code @@ -155,7 +147,6 @@ def __init__(self, code, escapeStrFunc=None) : CodeTemplate.INSTRUCTION_END : self._processInstructionEND } - # ------------------------------------------------------------------------ def Validate(self, pyGlobalVars=None, pyLocalVars=None) : try : @@ -164,7 +155,6 @@ def Validate(self, pyGlobalVars=None, pyLocalVars=None) : except Exception as ex : return str(ex) - # ---------------------------------------------------------------------------- def Execute(self, pyGlobalVars=None, pyLocalVars=None) : try : @@ -173,7 +163,6 @@ def Execute(self, pyGlobalVars=None, pyLocalVars=None) : except Exception as ex : raise CodeTemplateException(str(ex)) - # ------------------------------------------------------------------------ def _parseCode(self, pyGlobalVars, pyLocalVars, execute) : self._pos = 0 @@ -187,7 +176,6 @@ def _parseCode(self, pyGlobalVars, pyLocalVars, execute) : raise CodeTemplateException( '"%s" instruction is not valid here (line %s)' % (newTokenToProcess, self._line) ) - # ------------------------------------------------------------------------ def _parseBloc(self, execute) : while True : @@ -213,12 +201,10 @@ def _parseBloc(self, execute) : if newTokenToProcess is not None : return newTokenToProcess - # ------------------------------------------------------------------------ def _renderingPrint(self, s) : self._rendered += str(s) - # ------------------------------------------------------------------------ def _processToken(self, tokenContent, execute) : parts = tokenContent.split(' ', 1) @@ -244,7 +230,6 @@ def _processToken(self, tokenContent, execute) : raise CodeTemplateException('%s (line %s)' % (ex, self._line)) return newTokenToProcess - # ------------------------------------------------------------------------ def _processInstructionPYTHON(self, instructionBody, execute) : if instructionBody is not None : @@ -270,7 +255,6 @@ def _processInstructionPYTHON(self, instructionBody, execute) : self._executePyCode(lines) return None - # ------------------------------------------------------------------------ def _processInstructionPYTHONEND(self, instructionBody, execute) : if instructionBody is not None : @@ -297,7 +281,6 @@ def _processInstructionPYTHONEND(self, instructionBody, execute) : self._endPyCode = None return None - # ------------------------------------------------------------------------ def _processInstructionIF(self, instructionBody, execute) : if instructionBody is not None : @@ -339,7 +322,6 @@ def _processInstructionIF(self, instructionBody, execute) : raise CodeTemplateException( '"%s" alone is an incomplete syntax (line %s)' % (CodeTemplate.INSTRUCTION_IF, self._line) ) - # ------------------------------------------------------------------------ def _processInstructionELIF(self, instructionBody, execute) : if instructionBody is None : @@ -348,7 +330,6 @@ def _processInstructionELIF(self, instructionBody, execute) : self._elifInstructionBody = instructionBody return CodeTemplate.INSTRUCTION_ELIF - # ------------------------------------------------------------------------ def _processInstructionELSE(self, instructionBody, execute) : if instructionBody is not None : @@ -356,7 +337,6 @@ def _processInstructionELSE(self, instructionBody, execute) : % (CodeTemplate.INSTRUCTION_ELSE, self._line) ) return CodeTemplate.INSTRUCTION_ELSE - # ------------------------------------------------------------------------ def _processInstructionFOR(self, instructionBody, execute) : if instructionBody is not None : @@ -394,7 +374,6 @@ def _processInstructionFOR(self, instructionBody, execute) : raise CodeTemplateException( '"%s" alone is an incomplete syntax (line %s)' % (CodeTemplate.INSTRUCTION_FOR, self._line) ) - # ------------------------------------------------------------------------ def _processInstructionEND(self, instructionBody, execute) : if instructionBody is not None : @@ -402,7 +381,6 @@ def _processInstructionEND(self, instructionBody, execute) : % (CodeTemplate.INSTRUCTION_END, self._line) ) return CodeTemplate.INSTRUCTION_END - # ------------------------------------------------------------------------ def _handleEndPyCode(self) : if self._endPyCode is None: @@ -410,7 +388,6 @@ def _handleEndPyCode(self) : start_new_thread(self._executePyCode, (self._endPyCode,)) - # ------------------------------------------------------------------------ def _executePyCode(self, lines): indent = '' @@ -433,7 +410,3 @@ def _executePyCode(self, lines): exec(pyCode, self._pyGlobalVars, self._pyLocalVars) except Exception as ex : raise CodeTemplateException('%s (line %s)' % (ex, self._line)) - -# ============================================================================ -# ============================================================================ -# ============================================================================ diff --git a/MicroWebSrv2/mods/WebSockets.py b/MicroWebSrv2/mods/WebSockets.py deleted file mode 100644 index 4de0849..0000000 --- a/MicroWebSrv2/mods/WebSockets.py +++ /dev/null @@ -1,477 +0,0 @@ - -""" -The MIT License (MIT) -Copyright © 2019 Jean-Christophe Bos & HC² (www.hc2.fr) -""" - -from hashlib import sha1 -from binascii import b2a_base64 -from struct import pack - -# ============================================================================ -# ===( MicroWebSrv2 : WebSockets Module )===================================== -# ============================================================================ - -class WebSockets : - - _PROTOCOL_VERSION = 13 - _HANDSHAKE_SIGN = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" - - # ------------------------------------------------------------------------ - - def __init__(self) : - self._onWebSocketProtocol = None - self._onWebSocketAccepted = None - - # ------------------------------------------------------------------------ - - def OnRequest(self, microWebSrv2, request) : - if request.IsUpgrade and request.Upgrade.lower() == 'websocket' : - ver = request.GetHeader('Sec-Websocket-Version') - if ver == str(WebSockets._PROTOCOL_VERSION) : - response = request.Response - key = request.GetHeader('Sec-Websocket-Key') - if key : - try : - key += WebSockets._HANDSHAKE_SIGN - sec = sha1(key.encode()).digest() - sec = b2a_base64(sec).decode().strip() - protocols = request.GetHeader('Sec-WebSocket-Protocol') - response.SetHeader('Sec-WebSocket-Accept', sec) - if protocols and self._onWebSocketProtocol : - protocols = [x.strip() for x in protocols.split(',')] - try : - proto = self._onWebSocketProtocol(microWebSrv2, protocols) - except Exception as ex : - microWebSrv2.Log( 'Exception raised from "WebSockets.OnWebSocketProtocol" handler: %s' % ex, - microWebSrv2.ERROR ) - raise ex - if proto in protocols : - response.SetHeader('Sec-WebSocket-Protocol', proto) - response.SwitchingProtocols('websocket') - WebSocket(self, microWebSrv2, request) - except : - response.ReturnInternalServerError() - else : - response.ReturnBadRequest() - - # ------------------------------------------------------------------------ - - @property - def OnWebSocketProtocol(self) : - return self._onWebSocketProtocol - - @OnWebSocketProtocol.setter - def OnWebSocketProtocol(self, value) : - if type(value) is not type(lambda x:x) : - raise ValueError('"OnWebSocketProtocol" must be a function.') - self._onWebSocketProtocol = value - - # ------------------------------------------------------------------------ - - @property - def OnWebSocketAccepted(self) : - return self._onWebSocketAccepted - - @OnWebSocketAccepted.setter - def OnWebSocketAccepted(self, value) : - if type(value) is not type(lambda x:x) : - raise ValueError('"OnWebSocketAccepted" must be a function.') - self._onWebSocketAccepted = value - -# ============================================================================ -# ===( WebSocket )============================================================ -# ============================================================================ - -class WebSocket : - - _OP_FRAME_CONT = 0x00 - _OP_FRAME_TEXT = 0x01 - _OP_FRAME_BIN = 0x02 - _OP_FRAME_CLOSE = 0x08 - _OP_FRAME_PING = 0x09 - _OP_FRAME_PONG = 0x0A - - _MSG_TYPE_TEXT = 0x01 - _MSG_TYPE_BIN = 0x02 - - # ------------------------------------------------------------------------ - - def __init__(self, wsMod, mws2, request) : - - self._mws2 = mws2 - self._request = request - self._xasCli = request.XAsyncTCPClient - self._currentMsgType = None - self._currentMsgData = None - self._isClosed = False - self._waitFrameTimeoutSec = 300 - self._maxRecvMsgLen = mws2.MaxRequestContentLength - self._onTextMsg = None - self._onBinMsg = None - self._onClosed = None - - onWSAccepted = wsMod.OnWebSocketAccepted - - self._mws2.Log( '%sWebSocket %s from %s:%s.' - % ( ('SSL-' if request.IsSSL else ''), - 'accepted' if onWSAccepted else 'denied', - self._xasCli.CliAddr[0], - self._xasCli.CliAddr[1] ), - self._mws2.INFO ) - - if not onWSAccepted : - self._close(1001, 'Going away...') - return - - self._xasCli.OnClosed = self._onXAsCliClosed - - try : - onWSAccepted(self._mws2, self) - except Exception as ex : - self._mws2.Log( 'Exception raised from "WebSockets.OnWebSocketAccepted" handler: %s' % ex, - self._mws2.ERROR ) - self._close(1011, 'Unexpected error') - return - - self._waitFrame() - - # ------------------------------------------------------------------------ - - def _recvData(self, onRecv, size=None) : - self._xasCli.AsyncRecvData( size = size, - onDataRecv = onRecv, - timeoutSec = self._mws2.RequestsTimeoutSec ) - - # ------------------------------------------------------------------------ - - def _onXAsCliClosed(self, xasCli, closedReason) : - self._isClosed = True - if self._onClosed : - try : - self._onClosed(self) - except Exception as ex : - self._mws2.Log( 'Exception raised from "WebSocket.OnClosed" handler: %s' % ex, - self._mws2.ERROR ) - - # ------------------------------------------------------------------------ - - def _waitFrame(self) : - - def onHdrStartingRecv(xasCli, data, arg) : - - fin = data[0] & 0x80 > 0 - opcode = data[0] & 0x0F - masked = data[1] & 0x80 > 0 - length = data[1] & 0x7F - - # Control frame ? - isCtrlFrame = ( opcode != WebSocket._OP_FRAME_TEXT and \ - opcode != WebSocket._OP_FRAME_BIN and \ - opcode != WebSocket._OP_FRAME_CONT ) - - if ( isCtrlFrame and not fin ) \ - or \ - ( opcode == WebSocket._OP_FRAME_CONT and \ - not self._currentMsgType ) \ - or \ - ( self._currentMsgType and \ - ( opcode == WebSocket._OP_FRAME_TEXT or \ - opcode == WebSocket._OP_FRAME_BIN ) ) : - # Bad frame in the context, - self._close(1002, 'Protocol error (bad frame in the context)') - return - - def endOfHeader(dataLen, maskingKey) : - - def onPayloadDataRecv(xasCli, data, arg) : - - if maskingKey : - for i in range(dataLen) : - data[i] ^= maskingKey[i%4] - - if self._currentMsgData : - try : - self._currentMsgData += data - except : - # Frame is too large for memory allocation, - self._close(1009, 'Frame is too large to be processed') - return - else : - self._currentMsgData = data - - if fin : - # Frame is fully received, - if self._currentMsgType == WebSocket._MSG_TYPE_TEXT : - # Text frame, - if self._onTextMsg : - try : - msg = bytes(self._currentMsgData).decode('UTF-8') - try : - self._onTextMsg(self, msg) - except Exception as ex : - self._mws2.Log( 'Exception raised from "WebSocket.OnTextMessage" handler: %s' % ex, - self._mws2.ERROR ) - self._close(1011, 'Unexpected error while processing text message') - return - except : - self._mws2.Log( 'Error during UTF-8 decoding of websocket text message.', - self._mws2.WARNING ) - self._close(1007, 'Error to decode UTF-8 text message') - return - else : - self._close(1003, 'Text messages are not implemented') - return - elif self._currentMsgType == WebSocket._MSG_TYPE_BIN : - # Binary frame, - if self._onBinMsg : - try : - self._onBinMsg(self, bytes(self._currentMsgData)) - except Exception as ex : - self._mws2.Log( 'Exception raised from "WebSocket.OnBinaryMessage" handler: %s' % ex, - self._mws2.ERROR ) - self._close(1011, 'Unexpected error while processing binary message') - return - else : - self._close(1003, 'Binary messages are not implemented') - return - - self._currentMsgType = None - self._currentMsgData = None - - self._waitFrame() - - # - End of onPayloadDataRecv - - - if not isCtrlFrame : - # Message frame or continuation frame, - if self._maxRecvMsgLen : - l = dataLen - if self._currentMsgData : - l += len(self._currentMsgData) - if l > self._maxRecvMsgLen : - # Message length exceeds the defined limit, - self._close(1009, 'Frame is too large to be processed') - return - if opcode == WebSocket._OP_FRAME_TEXT : - self._currentMsgType = WebSocket._MSG_TYPE_TEXT - elif opcode == WebSocket._OP_FRAME_BIN : - self._currentMsgType = WebSocket._MSG_TYPE_BIN - try : - self._recvData(onPayloadDataRecv, dataLen) - except : - # Frame is too large for memory allocation, - self._close(1009, 'Frame is too large to be processed') - elif opcode == WebSocket._OP_FRAME_PING : - # Ping control frame, - if dataLen > 0 : - def onPingDataRecv(xasCli, data, arg) : - data = bytearray(data) - self._sendFrame(WebSocket._OP_FRAME_PONG, data) - self._waitFrame() - self._recvData(onPingDataRecv, dataLen) - else : - self._sendFrame(WebSocket._OP_FRAME_PONG) - self._waitFrame() - elif opcode == WebSocket._OP_FRAME_PONG : - # Pong control frame, - if dataLen > 0 : - def onPongDataRecv(xasCli, data, arg) : - self._waitFrame() - self._recvData(onPongDataRecv, dataLen) - else : - self._waitFrame() - elif opcode == WebSocket._OP_FRAME_CLOSE : - # Close control frame,') - if dataLen > 0 : - def onCloseDataRecv(xasCli, data, arg) : - self._close() - self._recvData(onCloseDataRecv, dataLen) - else : - self._close() - else : - # Unknown frame type, - self._close(1002, 'Protocol error (bad opcode)') - - # - End of endOfHeader - - - def getMaskingKey(dataLen) : - - if masked : - # Frame is masked by the next 4 bytes key, - def onMaskingKeyRecv(xasCli, data, arg) : - endOfHeader(dataLen=dataLen, maskingKey=bytes(data)) - self._recvData(onMaskingKeyRecv, 4) - else : - # Frame is not masked, - endOfHeader(dataLen=dataLen, maskingKey=None) - - # - End of getMaskingKey - - - if length == 0 and not isCtrlFrame : - # Bad frame for a no control frame without payload data, - self._close(1002, 'Protocol error (payload data required)') - elif length <= 0x7D : - # Frame length <= 0x7D, - getMaskingKey(dataLen=length) - elif isCtrlFrame : - # Bad frame for length of control frame > 0x7D, - self._close(1002, 'Protocol error (bad control frame length)') - elif length == 0x7E : - # Frame length is encoded on next 16 bits, - def onLenExt1Recv(xasCli, data, arg) : - length = (data[0] << 8) + data[1] - if length < 0x7E : - # Bad frame for 16 bits length < 0x7E, - self._close(1002, 'Protocol error (bad length encoding)') - else : - getMaskingKey(dataLen=length) - self._recvData(onLenExt1Recv, 2) - else : - # Frame length is encoded on next 64 bits. - # It's too large and not implemented, - self._close(1009, 'Frame is too large to be processed') - - # - End of onHdrStartingRecv - - - self._xasCli.AsyncRecvData( size = 2, - onDataRecv = onHdrStartingRecv, - timeoutSec = self._waitFrameTimeoutSec ) - - # ------------------------------------------------------------------------ - - def _sendFrame(self, opcode, data=None, fin=True) : - try : - if opcode >= 0x00 and opcode <= 0x0F : - length = len(data) if data else 0 - if length <= 0xFFFF : - data = bytes([ (opcode | 0x80) if fin else opcode ] ) \ - + bytes([ length if length <= 0x7D else 0x7E ] ) \ - + (pack('>H', length) if length >= 0x7E else b'') \ - + (bytes(data) if data else b'') - return self._xasCli.AsyncSendData(data) - except : - pass - return False - - # ------------------------------------------------------------------------ - - def _close(self, statusCode=None, reason=None, waitCloseFrame=False) : - if not self._isClosed : - if statusCode : - data = pack('>H', statusCode) - if reason : - data += reason.encode('UTF-8') - else : - data = None - self._sendFrame(WebSocket._OP_FRAME_CLOSE, data) - self._isClosed = True - if waitCloseFrame : - return - self._xasCli.Close() - - # ------------------------------------------------------------------------ - - def SendTextMessage(self, msg) : - if not isinstance(msg, str) or len(msg) == 0 : - raise ValueError('"msg" must be a not empty string.') - if not self._isClosed : - try : - msg = msg.encode('UTF-8') - except : - return False - return self._sendFrame(WebSocket._OP_FRAME_TEXT, msg) - return False - - # ------------------------------------------------------------------------ - - def SendBinaryMessage(self, msg) : - try : - bytes([msg[0]]) - except : - raise ValueError('"msg" must be a not empty bytes object.') - if not self._isClosed : - return self._sendFrame(WebSocket._OP_FRAME_BIN, msg) - return False - - # ------------------------------------------------------------------------ - - def Close(self) : - if not self._isClosed : - self._close(1000, 'Normal closure', waitCloseFrame=True) - - # ------------------------------------------------------------------------ - - @property - def Request(self) : - return self._request - - # ------------------------------------------------------------------------ - - @property - def IsClosed(self) : - return self._isClosed - - # ------------------------------------------------------------------------ - - @property - def WaitFrameTimeoutSec(self) : - return self._waitFrameTimeoutSec - - @WaitFrameTimeoutSec.setter - def WaitFrameTimeoutSec(self, value) : - if not isinstance(value, int) or value <= 0 : - raise ValueError('"WaitFrameTimeoutSec" must be a positive integer.') - self._waitFrameTimeoutSec = value - - # ------------------------------------------------------------------------ - - @property - def MaxRecvMessageLength(self) : - return self._maxRecvMsgLen - - @MaxRecvMessageLength.setter - def MaxRecvMessageLength(self, value) : - if value is not None and (not isinstance(value, int) or value < 125) : - raise ValueError('"MaxRecvMessageLength" must be an integer >= 125 or None.') - self._maxRecvMsgLen = value - - # ------------------------------------------------------------------------ - - @property - def OnTextMessage(self) : - return self._onTextMsg - - @OnTextMessage.setter - def OnTextMessage(self, value) : - if type(value) is not type(lambda x:x) : - raise ValueError('"OnTextMessage" must be a function.') - self._onTextMsg = value - - # ------------------------------------------------------------------------ - - @property - def OnBinaryMessage(self) : - return self._onBinMsg - - @OnBinaryMessage.setter - def OnBinaryMessage(self, value) : - if type(value) is not type(lambda x:x) : - raise ValueError('"OnBinaryMessage" must be a function.') - self._onBinMsg = value - - # ------------------------------------------------------------------------ - - @property - def OnClosed(self) : - return self._onClosed - - @OnClosed.setter - def OnClosed(self, value) : - if type(value) is not type(lambda x:x) : - raise ValueError('"OnClosed" must be a function.') - self._onClosed = value - -# ============================================================================ -# ============================================================================ -# ============================================================================ diff --git a/MicroWebSrv2/webRoute.py b/MicroWebSrv2/webRoute.py index edbf894..f9a6b46 100644 --- a/MicroWebSrv2/webRoute.py +++ b/MicroWebSrv2/webRoute.py @@ -6,26 +6,18 @@ import re -# ============================================================================ -# ===( @WebRoute decorator )================================================== -# ============================================================================ - def WebRoute(method=None, routePath=None, name=None) : if type(method) is type(lambda x:x) and not routePath : raise ValueError('[@WebRoute] arguments are required for this decorator.') - + def decorated(handler) : RegisterRoute(handler, method, routePath, name) s = (' (%s)' % name) if name else '' print(' + [@WebRoute] %s %s' % (method, routePath) + s) return handler - - return decorated -# ============================================================================ -# ===( RegisterResult )======================================================= -# ============================================================================ + return decorated def RegisterRoute(handler, method, routePath, name=None) : if type(handler) is not type(lambda x:x) : @@ -66,10 +58,6 @@ def RegisterRoute(handler, method, routePath, name=None) : regRoute = _registeredRoute(handler, method, routePath, name, regex, argNames) _registeredRoutes.append(regRoute) -# ============================================================================ -# ===( ResolveRoute )========================================================= -# ============================================================================ - def ResolveRoute(method, path) : try : path = path.lower() @@ -94,10 +82,6 @@ def ResolveRoute(method, path) : pass return None -# ============================================================================ -# ===( PathFromRoute )======================================================== -# ============================================================================ - def PathFromRoute(routeName, routeArgs={ }) : if not isinstance(routeName, str) or len(routeName) == 0 : raise ValueError('"routeName" requires a not empty string.') @@ -114,10 +98,6 @@ def PathFromRoute(routeName, routeArgs={ }) : return path raise ValueError('"routeName" is not a registered route (%s).' % routeName) -# ============================================================================ -# ===( RouteResult )========================================================== -# ============================================================================ - class RouteResult : def __init__(self, regRoute, args=None) : @@ -149,10 +129,6 @@ def Name(self) : def Args(self) : return self._args -# ============================================================================ -# ===( Methods )============================================================== -# ============================================================================ - GET = 'GET' HEAD = 'HEAD' POST = 'POST' @@ -161,13 +137,8 @@ def Args(self) : OPTIONS = 'OPTIONS' PATCH = 'PATCH' -# ============================================================================ -# ===( Private registered routes )=========================================== -# ============================================================================ - _registeredRoutes = [ ] -# ------------------------------------------------------------------------ class _registeredRoute : @@ -178,7 +149,3 @@ def __init__(self, handler, method, routePath, name, regex, argNames) : self.Name = name self.Regex = regex self.ArgNames = argNames - -# ============================================================================ -# ============================================================================ -# ============================================================================ From 5e67380d9b5f9c6497dd0c2a3cb0fc7f61f7734b Mon Sep 17 00:00:00 2001 From: Nikolaos Ftylitakis Date: Fri, 11 Jun 2021 16:21:26 +0300 Subject: [PATCH 5/5] fixed typo after refactoring --- MicroWebSrv2/libs/urlUtils.py | 8 -------- MicroWebSrv2/mods/PyhtmlTemplate.py | 3 --- 2 files changed, 11 deletions(-) diff --git a/MicroWebSrv2/libs/urlUtils.py b/MicroWebSrv2/libs/urlUtils.py index c5b45a6..d4f2990 100644 --- a/MicroWebSrv2/libs/urlUtils.py +++ b/MicroWebSrv2/libs/urlUtils.py @@ -46,10 +46,6 @@ def Unquote(s) : def UnquotePlus(s) : return UrlUtils.Unquote(str(s).replace('+', ' ')) - # ============================================================================ - # ===( Class Url )============================================================ - # ============================================================================ - class Url : def __init__(self, url='') : @@ -199,7 +195,3 @@ def QueryParams(self, value) : if not isinstance(value, dict) : raise ValueError('QueryParams must be a dict') self._queryParams = value - - # ============================================================================ - # ============================================================================ - # ============================================================================ diff --git a/MicroWebSrv2/mods/PyhtmlTemplate.py b/MicroWebSrv2/mods/PyhtmlTemplate.py index b6725d4..d9854a8 100644 --- a/MicroWebSrv2/mods/PyhtmlTemplate.py +++ b/MicroWebSrv2/mods/PyhtmlTemplate.py @@ -9,9 +9,6 @@ from _thread import start_new_thread -: PyhtmlTemplate Module )================================= - - class PyhtmlTemplate : _CODE_CONTENT_DEBUG = """\