Coder Social home page Coder Social logo

jczic / microwebsrv Goto Github PK

View Code? Open in Web Editor NEW
640.0 49.0 115.0 712 KB

A micro HTTP Web server that supports WebSockets, html/python language templating and routing handlers, for MicroPython (used on Pycom modules & ESP32)

Home Page: https://github.com/jczic/MicroWebSrv

License: MIT License

Python 94.53% HTML 4.79% CSS 0.68%
micropython webserver language-templating esp32 websockets http wipy websocket-server template-engine websocket

microwebsrv's Introduction

Also check out the new ESP32 MPY-Jama free IDE and the latest MicroWebSrv2 below:

New microWebSrv2                   New microWebSrv2



MicroWebSrv is a micro HTTP Web server that supports WebSockets, html/python language templating and routing handlers, for MicroPython (principally used on ESP32 and Pycom modules. Now supports all variants of Pyboard D-series from the makers of Micropython)

HC²

Very easy to integrate and very light with 3 files only :

  • "microWebSrv.py" - The Web server
  • "microWebSocket.py" - The optional support of WebSockets
  • "microWebTemplate.py" - The optional templating language for .pyhtml rendered pages

Mini tuto in video by rdagger68 :

Simple but effective :

  • Use it to embed a cool Web site in yours modules
  • Handle GET, POST, ... requests to interract with user and configure options
  • Exchange in JSON format on HTTP methods to make an embedded fullREST API
  • Serve files on the fly to export any data to the user
  • Use routes and variable route handlers
  • Play with AjAX to interact speedly with a Web application
  • Make it a captive portal simply
  • Use WebSockets for fast and powerful data exchange
  • Make html/python files for rendering more efficient web pages

Using microWebSrv main class :

Name Function
Constructor mws = MicroWebSrv(routeHandlers=None, port=80, bindIP='0.0.0.0', webPath="/flash/www")
Start Web server mws.Start(threaded=True)
Stop Web server mws.Stop()
Check if Web server is running mws.IsStarted()
Set URL location for not found page mws.SetNotFoundPageUrl(url=None)
Get mime type from file extention mws.GetMimeTypeFromFilename(filename)
Get handler function from route (routeHandler, routeArgs) = mws.GetRouteHandler(resUrl, method)
Callback function to enable and accept WebSockets mws.AcceptWebSocketCallback = _acptWS _acptWS(webSocket, httpClient) { }
Maximum length of memory allocated to receive WebSockets data (1024 by default) mws.MaxWebSocketRecvLen
New thread used for each WebSocket connection (True by default) mws.WebSocketThreaded
Escape string to HTML usage MicroWebSrv.HTMLEscape(s)

Basic example :

from microWebSrv import MicroWebSrv
mws = MicroWebSrv()      # TCP port 80 and files in /flash/www
mws.Start(threaded=True) # Starts server in a new thread

Using as captive portal :

# To intercept all not found queries and redirect it,
mws.SetNotFoundPageUrl("http://my-device.wifi")

Using route handlers example :

routeHandlers = [
  ( "relative_url_route_1", "METHOD", handlerFunc_1 ),
  ( "relative_url_route_2", "METHOD", handlerFunc_2 ),
  ( ... )
]
def handlerFunc_1(httpClient, httpResponse, routeArgs=None) :
  print("In HTTP handler 1")

def handlerFunc_2(httpClient, httpResponse, routeArgs=None) :
  print("In HTTP handler 2")

Using directly route handlers decorators example :

@MicroWebSrv.route('/get-test')
def handlerFuncGet(httpClient, httpResponse) :
  print("In GET-TEST HTTP")

@MicroWebSrv.route('/post-test', 'POST')
def handlerFuncPost(httpClient, httpResponse) :
  print("In POST-TEST HTTP")

Using variable routes example :

routeHandlers = [
  ( "/edit/<testid>/<testpath>", "GET", handlerFuncEdit ),
  ( ... )
]
def handlerFuncEdit(httpClient, httpResponse, routeArgs) :
  print("In EDIT HTTP variable route :")
  print(" - testid   = %s" % routeArgs['testid'])
  print(" - testpath = %s" % routeArgs['testpath'])

Or direclty with route handler decorator :

@MicroWebSrv.route('/edit/<testid>/<testpath>')
def handlerFuncEdit(httpClient, httpResponse, routeArgs) :
  print("In EDIT HTTP variable route :")
  print(" - testid   = %s" % routeArgs['testid'])
  print(" - testpath = %s" % routeArgs['testpath'])

Using httpClient class in a route handler function :

Name Function
Get MicroWebSrv class httpClient.GetServer()
Get client address as tuple httpClient.GetAddr()
Get client IP address httpClient.GetIPAddr()
Get client TCP port httpClient.GetPort()
Get client request method httpClient.GetRequestMethod()
Get client request total path httpClient.GetRequestTotalPath()
Get client request ressource path httpClient.GetRequestPath()
Get client request query string httpClient.GetRequestQueryString()
Get client request query parameters as list httpClient.GetRequestQueryParams()
Get client request headers as list httpClient.GetRequestHeaders()
Get client request content type httpClient.GetRequestContentType()
Get client request content length httpClient.GetRequestContentLength()
Get client request content httpClient.ReadRequestContent(size=None)
Get client request form data as list httpClient.ReadRequestPostedFormData()
Get client request as JSON object httpClient.ReadRequestContentAsJSON()

Using httpResponse class in a route handler function :

Name Function
Write switching protocols response httpResponse.WriteSwitchProto(upgrade, headers=None)
Write generic response httpResponse.WriteResponse(code, headers, contentType, contentCharset, content)
Write PyHTML rendered response page httpResponse.WriteResponsePyHTMLFile(filepath, headers=None, vars=None)
Write file directly as response httpResponse.WriteResponseFile(filepath, contentType=None, headers=None)
Write attached file as response httpResponse.WriteResponseFileAttachment(filepath, attachmentName, headers=None)
Write OK response httpResponse.WriteResponseOk(headers=None, contentType=None, contentCharset=None, content=None)
Write JSON object as OK response httpResponse.WriteResponseJSONOk(obj=None, headers=None)
Write redirect response httpResponse.WriteResponseRedirect(location)
Write error response httpResponse.WriteResponseError(code)
Write JSON object as error response httpResponse.WriteResponseJSONError(code, obj=None)
Write bad request response httpResponse.WriteResponseBadRequest()
Write forbidden response httpResponse.WriteResponseForbidden()
Write not found response httpResponse.WriteResponseNotFound()
Write method not allowed response httpResponse.WriteResponseMethodNotAllowed()
Write internal server error response httpResponse.WriteResponseInternalServerError()
Write not implemented response httpResponse.WriteResponseNotImplemented()

Using route handler function example :

def _httpHandlerTestPost(httpClient, httpResponse) :
  formData  = httpClient.ReadRequestPostedFormData()
  firstname = formData["firstname"]
  lastname  = formData["lastname"]
  content   = """\
  <!DOCTYPE html>
  <html>
    <head>
      <meta charset="UTF-8" />
      <title>TEST POST</title>
    </head>
    <body>
      <h1>TEST POST</h1>
      Firstname = %s<br />
      Lastname = %s<br />
    </body>
  </html>
  """ % ( MicroWebSrv.HTMLEscape(firstname),
          MicroWebSrv.HTMLEscape(lastname) )
  httpResponse.WriteResponseOk( headers         = None,
                                contentType     = "text/html",
                                contentCharset  = "UTF-8",
                                content         = content )

Known mime types (content types) :

File extension Mime type
.txt text/plain
.htm text/html
.html text/html
.css text/css
.csv text/csv
.js application/javascript
.xml application/xml
.xhtml application/xhtml+xml
.json application/json
.zip application/zip
.pdf application/pdf
.ts application/typescript
.woff font/woff
.woff2 font/woff2
.ttf font/ttf
.otf font/otf
.jpg image/jpeg
.jpeg image/jpeg
.png image/png
.gif image/gif
.svg image/svg+xml
.ico image/x-icon

Default index pages order (for http://hostname/) :

Filename
index.pyhtml
index.html
index.htm
default.pyhtml
default.html
default.htm

Using optional module microWebSocket to connect WebSockets :

  • File "microWebSocket.py" must be present to activate WebSockets support

Enable and accept WebSockets :

from microWebSrv import MicroWebSrv
mws = MicroWebSrv()                                    # TCP port 80 and files in /flash/www
mws.MaxWebSocketRecvLen     = 256                      # Default is set to 1024
mws.WebSocketThreaded       = False                    # WebSockets without new threads
mws.AcceptWebSocketCallback = _acceptWebSocketCallback # Function to receive WebSockets
mws.Start(threaded=True)                               # Starts server in a new thread
Name Function
Callback function to receive text message ws.RecvTextCallback = func(webSocket, msg)
Callback function to receive binary data ws.RecvBinaryCallback = func(webSocket, data)
Callback function when connection was closed ws.ClosedCallback = func(webSocket)
Send a text message ws.SendText(msg)
Send a binary message ws.SendBinary(data)
Check connection state ws.IsClosed()
Close the connection ws.Close()

Basic example of callback functions :

def _acceptWebSocketCallback(webSocket, httpClient) :
  print("WS ACCEPT")
  webSocket.RecvTextCallback   = _recvTextCallback
  webSocket.RecvBinaryCallback = _recvBinaryCallback
  webSocket.ClosedCallback     = _closedCallback

def _recvTextCallback(webSocket, msg) :
  print("WS RECV TEXT : %s" % msg)
  webSocket.SendText("Reply for %s" % msg)

def _recvBinaryCallback(webSocket, data) :
  print("WS RECV DATA : %s" % data)

def _closedCallback(webSocket) :
  print("WS CLOSED")

Using optional module microWebTemplate for .pyhtml rendered pages :

  • File "microWebTemplate.py" must be present to activate .pyhtml pages
  • Pages will be rendered in HTML with integrated MicroPython code
Instruction Schema
PY {{ py }} MicroPython code {{ end }}
IF {{ if MicroPython condition }} html bloc {{ end }}
ELIF {{ elif MicroPython condition }} html bloc {{ end }}
ELSE {{ else }} html bloc {{ end }}
FOR {{ for identifier in MicroPython iterator }} html bloc {{ end }}
INCLUDE {{ include pyhtml_filename }}
?   {{ MicroPython expression }}

Using {{ py }} :

{{ py }}
  import machine
  from utime import sleep
  test = 123
  def testFunc(x) :
    return 2 * x
{{ end }}

Using {{ if ... }} :

{{ if testFunc(5) <= 3 }}
  <span>titi</span>
{{ elif testFunc(10) >= 15 }}
  <span>tata</span>
{{ else }}
  <span>I like the number {{ test }} !</span>
{{ end }}

Using {{ for ... }} :

{{ for toto in range(testFunc(3)) }}
  <div>toto x 10 equal {{ toto * 10 }}</div>
  <hr />
{{ end }}

Using {{ include ... }} :

{{ include myTemplate.pyhtml }}

Example of a .pyhtml file :

<html>
  <head>
    <title>TEST PYHTML</title>
  </head>
  <body>
    <h1>BEGIN</h1>
    {{ py }}
      def _testFunction(x) :
        return "IN TEST FUNCTION %s" % x
    {{ end }}
    <div style="background-color: black; color: white;">
      {{ for toto in range(3) }}
        This is an HTML test...<br />
        TOTO = {{ toto + 1 }} !<br />
        {{ for toto2 in range(3) }}
          TOTO2 = {{ _testFunction(toto2) }}
        {{ end }}
        Ok good.<br />
      {{ end }}
    </div>
    {{ _testFunction(100) }}<br />
    <br />
    {{ if 2+5 < 3 }}
      IN IF (1)
    {{ elif 10+15 != 25 }}
      IN ELIF (2)
    {{ elif 10+15 == 25 }}
      IN ELIF (3)
    {{ else }}
      IN ELSE (4)
    {{ end }}
  </body>
</html>

😉  Author

Jean-Christophe Bos (:fr:)

By JC`zic for HC² ;')

Keep it simple, stupid 👍

microwebsrv's People

Contributors

dhylands avatar hoihu avatar jczic avatar jk-de avatar nherriot avatar washcycle avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

microwebsrv's Issues

Curious whether MicroWebSrv supports https?

I’ve been wanting to handle web requests using https on a PyCom WiPy 3.0 for awhile now without success. Maybe this is asking too much of the hardware?

Thanks in advance,
Tim

Building firmware image, including this library, issue on pycom

I successfully use the POST/GET services from your libraries on a FiPy board (ESP32) when it's uploaded the normal way. It works great, loads webpages from SD, allows me to configure settings in the device and save them back to a config file, all good.
The problem is when I compile the 3 libraries along with the fipy firmware (i've done this successfully many times) I get a check_sum error and the FiPy won't start. I remove the 3 library files and all good, it works again.
Maybe a problem with the compiler and how it 'freezes' .py files, I just don't know why this is happening. For no I will try and load these libraries on the SD card as a work around.

Socket Time out when using Threading=True on Pyboard D

Hi MicrowWebSrv people,

this bug seems to be with the pyboard 'D' but I thought I'd report here in case anyone else is seeing large files that seem to timeout on the microWebSrv. Basically I noticed that sometimes my microWebSrv did not fully transfer large image files while testing.

I tested directly with curl scripts shown below:

curl -X GET http://192.168.110.143:8000/thumb.png > thumb.png
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 71268  100 71268    0     0   205k      0 --:--:-- --:--:-- --:--:--  205k
nherriot@Zenbook-UX32A ~ $ curl -X GET http://192.168.110.143:8000/thumb.png > thumb.png
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 71268  100 71268    0     0   220k      0 --:--:-- --:--:-- --:--:--  220k
nherriot@Zenbook-UX32A ~ $ curl -X GET http://192.168.110.143:8000/thumb.png > thumb.png
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
 10 71268   10  7403    0     0   2199      0  0:00:32  0:00:03  0:00:29  2199
curl: (18) transfer closed with 63865 bytes remaining to read

You can see where the last curl request fails.
The output from the microWebSrv on the Pyboard 'D' looks like:

Accepted 'client': <socket state=3 timeout=-1 incoming=0 off=0> and 'client address': ('192.168.110.147', 42094)
Processing request HTTP Method: GET Path: /thumb.png Version: HTTP/1.1
Server writing file: www//thumb.png of size: 71268 of type: image/png to host: ('192.168.110.147', 42094)
Last: 612 octets being sent
Accepted 'client': <socket state=3 timeout=-1 incoming=0 off=0> and 'client address': ('192.168.110.147', 42152)
Processing request HTTP Method: GET Path: /thumb.png Version: HTTP/1.1
Server writing file: www//thumb.png of size: 71268 of type: image/png to host: ('192.168.110.147', 42152)
Last: 612 octets being sent
Connected on IP: 192.168.110.143
Accepted 'client': <socket state=3 timeout=-1 incoming=0 off=0> and 'client address': ('192.168.110.147', 42178)
Processing request HTTP Method: GET Path: /thumb.png Version: HTTP/1.1
Server writing file: www//thumb.png of size: 71268 of type: image/png to host: ('192.168.110.147', 42178)

Again we can see the last file never gets sent, and there is no except being called in the WriteResponseFile method. The code looks like:

        def WriteResponseFile(self, filepath, contentType=None, headers=None):
            """
            A method to write a file to the client. It takes the path of the file, calculates it's size and copies the file in chunk
            sizes of 1024 octets via the low level socket interface. The method first builds the first line of the HTTP request and
            provides headers, content type, reason code and size of the file. It then does the sending of the file in 1024 octet chunks
            to the client.
            If there is a failure in reading the file a WriteREsponseNotFound is sent.
            If there is a faulure in sending the file to the client a WriteResponseInternalServerError is sent.
            :param filepath:    (e.g. www/style.css)
            :param contentType: (e.g. text/html)
            :param headers:     (e.g. {'Cache-Control': 'max-age=315360000', 'Last-Modified': 'Fri, 1 Jan 2018 23:42:00 GMT'})
            :return: Boolean
            """
            try :
                size = stat(filepath)[6]
                print("Server writing file: {} of size: {} of type: {} to host: {}".format(filepath, size, contentType, self._client._addr ))
                if size > 0 :
                    with open(filepath, 'rb') as file :                                 # Open file for reading in binary mode
                        self._writeBeforeContent(200, headers, contentType, None, size) # Write our HTTP header
                        try :
                            buf = bytearray(1024)
                            while size > 0 :
                                x = file.readinto(buf)
                                if x < len(buf) :
                                    buf = memoryview(buf)[:x]
                                    print("Last: {} octets being sent".format(x))
                                self._write(buf)                                        # call up low level socket write function
                                size -= x
                            return True
                        except :
                            self.WriteResponseInternalServerError()
                            return False
            except :
                pass
            self.WriteResponseNotFound()
            return False

The file I try and transfer is here - which is not even that large!

I've taken the liberty of adding a lot of print statements and doc strings to the microWebSrv.py file to help me debug. I'll push the doc strings back here today.

If anyone wants to try this out you can find instruction here

I've also reported this to the micropython team here

Things to note that:

  1. I have threading set to True, but it only ever uses a single thread so i have no idea why this would be an issue.
  2. I do use an IRQ Timer which happens every 10 seconds and calls a callback to check WiFi status.

If anyone has clever ways to debug on the embedded board please let me know. :-)
If anyone has an idea why this is happening, or has seen this behaviour before please let me know! :-)

Kind regards, Nicholas.

Accessing filesystem from threaded webserver crashes the machine

Dear Jean-Christophe,

thanks for conceiving and maintaining this fine project.

Similar to #54, we are either getting "maximum recursion depth exceeded" exceptions or blatant "stack overflow" crashes when accessing the filesystem from a route/handler within a threaded webserver. We are using the Pycom FiPy on a recent Pycom firmware version.

Maybe you have any idea about this? Otherwise, let's keep this as a reference for other visitors.

With kind regards,
Andreas.


***ERROR*** A stack overflow in task MPThread has been detected.
abort() was called at PC 0x40099324 on core 1

Backtrace: 0x400991b3:0x3fff0870 0x4009930b:0x3fff0890 0x40099324:0x3fff08b0 0x40095a5d:0x3fff08d0 0x400976a4:0x3fff0900 0x4009765a:0x3ffdd458
[...]

================= CORE DUMP START =================
dE4AABMAAABsAQAA
[...]
================= CORE DUMP END =================
E (6171) esp_core_dump: Skipped 1 tasks with bad TCB!
E (6175) esp_core_dump: Crashed task has been skipped!

size limit with GetRequestContent

I'm looking for parsing big json request and find a limit in GetRequestContent().

Here is the code used :

def _httpHandlerLEDPost(httpClient, httpResponse):
print("we pass here")
print("content type:",httpClient.GetRequestContentType())
print("Size:",httpClient.GetRequestContentLength())
content = httpClient.ReadRequestContent() # Read JSON color data
print("Size content:",str(len(content)))

....

Here is the trace :

we pass here
content type: application/json
Size:: 10151
Size content: 4308

I have tried ReadRequestContentAsJSON() but unfortunatly no way to get my data according to the use of the same methode ReadRequestContent.

Noob question - how to access 'pyhtml' pages?

Hello,

I'm trying the MicroWebSrv engine and it seems that serving static pages works fine. Using the controller methods also works fine. However, I have a serious issue with the pyhtml engine.

That's what I did:

  • I copied microWebSocket.py, microWebSrv.py and microWebTemplate.py in /flash/lib
  • I created simple static HTML page in /flash/www/index.pyhtml
  • I used the same initializiation code as from the provided sample

The initialization code:

from microWebSrv import MicroWebSrv
mws = MicroWebSrv()
mws.Start()

The issue is that whenever I try to access http://my-host, my WiPy device hangs for a while and then it seems to restart itself. This happens only when I hit pyhtml pages. Like I said, there is no problem serving static HTML files and there is no problem serving pages from controller methods. I guess I'm missing something. I'm using the latest 'master' source code. Could you please explain what I might be missing in my setup?

Thanks!

Basic Authentication Implementation

Hi,
I'm trying to implement a Basic Authentication method when I access a web site allocated on a LoPy4.

I've successfully managed to do this (in a quite naive way) inside a route handler:

@MicroWebSrv.route('/auth')
def _httpHandlerAuth(httpClient, httpResponse) :
    responseCode = 401

    requestHeader = httpClient.GetRequestHeaders()
    print(requestHeader)

    try:
        rta = validateAuthentication(requestHeader['Authorization'])
        if(rta == True):
            responseCode = 200
    except KeyError:
        pass

    print("response Code: ", responseCode)
    if(responseCode == 200):
        myHeader = dict()
        myHeader['Access-Control-Allow-Origin'] = '*'
        myHeader['Access-Control-Allow-Methods'] = 'GET, POST'
        httpResponse.WriteResponseOk(headers		 = myHeader,
                                     contentType	 = "text/plain",
                                     contentCharset = "UTF-8",
                                     content 		 = 'Login OK :)' )
    else:
        myHeader = dict()
        myHeader['Access-Control-Allow-Origin'] = '*'
        myHeader['Access-Control-Allow-Methods'] = 'GET, POST'
        myHeader['Authorization'] = 'Basic'
        myHeader['WWW-Authenticate'] = 'Basic realm="401"'
        httpResponse.WriteResponse( code = responseCode,
                                    headers		 = myHeader,
                                    contentType	 = "text/plain",
                                    contentCharset = "UTF-8",
                                    content 		 = None)

def validateAuthentication(request):
    # Mock User and Password
    user = "admin"
    pwd = "1234"

    ret = False

    request_enc = request.split(" ")[1]
    request_dec = str( base64.b64decode(request_enc) )
    aux = request_dec.split("'")
    aux = aux[1].split(":")
    print("aux: ", aux)

    request_user = aux[0]
    request_pass = aux[1]
    print('User: ', request_user)
    print('Pass: ', request_pass)

    if(request_user == user and request_pass == pwd):
        print("OK!!!")
        ret = True
    return ret

I would like to implement something similar to this but before accessing the index.html file allocated inside the /www directory. If I write the same code as before, but using @MicroWebSrv.route('/') then I cannot access the index.html file (as expected).

Is there a way to implement this authentication method? Thanks in advance!

Webserver & GPIO

Hi, I just discover this microserver, but i don't find a way to interact with GPIO.

I mean, putting a button in my webpage, and interact with my pycom pin through this button.

threaded=True is slow

Hi

I use your great module for my nodemcu-32s v1.1 board, micropython version 1.9.4, everything looks fine, but when I start webserver with threaded=True, the response is slow, about 4s, however it's ~200ms when threaded mode is False.

I have no idea why this happens, my micropython is clean, no other modules and I use IP to connect the device, so it seems not an DNS issue, could you give me some hints about this?

Thanks a lot.
-Silver

Error 112 on ESP32

During development every time I download a new version, I got the following trace:
Traceback (most recent call last):
File "", line 1, in
File "", line 34, in
File "microWebSrv.py", line 224, in Start
OSError: 112

Allocation MemoryError on Pycom

Hello, just tried MicroWebSrv on w WiPy 2.0 and got this error (with the unaltered files):

Traceback (most recent call last):
File "main.py", line 1, in
File "microWebSrv.py", line 21, in
File "microWebSrv.py", line 98, in MicroWebSrv
MemoryError: memory allocation failed, allocating 1784 bytes
MicroPython v1.8.6-760-g90b72952 on 2017-09-01; WiPy with ESP32

Its the line: "_hextochr = dict(('%02x' % i, chr(i)) for i in range(256))"

I could get it running when I uncommented "_hextochr ", but only the URL "test" worked. index.html gave me a 404.

Any idea whats wrong?
(On peut communiquer en francais si vous voulez)
Merci, Ronald Krause

ESP32 - mws.IsStarted() problem when threaded

Hi,
when running mws.Start(threaded=True)
then mws.IsStarted() always returns false.

mws is working fine, but of course mws.Stop() also fails.

What am I missing ? Thanks for your support
Alf
ESP32 4MB , micropython version='v1.11-178'

Recursion error from .pyhtml when threaded=True

If I start the process with mws.Start(threaded=True), attempting to load any .pyhtml page renders:

PyHTML page execution error
maximum recursion depth exceeded (line 18)

This does not happen at all if I start with threaded=False.
Is this to be expected?

Does it work on esp8266?

A very good webserver for micropython, even with websocket and template!
My question is, does this powerful lightweight web server work on esp8266? After all, micropython offically support 8266, and 32 and 8266 using same basic MicroPython libraries. Or should I do some modify to make it works.
Thanks a lot!

HTTPS and WSS support

Are you planning to extend the features with secure operation?
How big effort to implement the SSL handsake to this project?

Handle file uploads?

From the readme and I can not deduce how to write a file upload handler with microwebsrv.

I currently use python3/tornado where I go:

class UploadHandler(tornado.web.RequestHandler):
    def post(self):
        if 'file_0' in self.request.files:

etc.

I want to move to micropython for this web app. How do I do that?

str.encode() changing contentLength in writeResponse()

I'm using writeResponseOK() (I could have used writeResponseJSONOK() but nvm) to send a JSON to my app.
Though I get an error on app side (JSON.parse() failure) when my JSON contains the 'é' character (the only 'exotic' character I send). I found out that i had one character stripped from my response for each 'é'.
I looked at the code of MicroWebSrv.py and found that the data.encode() (in _write() line 578) is computed after len(content) (in WriteResponse() line 644). So in my use case I get data.encode() - len(content) == n where n is the number of 'é' and therefore as many character are stripped at the end of my content.
The fix is to compute the encode() before the len(), maybe contentLength = len(content.encode()) if content else 0 (and that's what I do outside of writeResponseOK() as a quick fix)

s = '\xe9'
print(s) # é
s.encode() # b'\xc3\xa9'
len(s) == len(s.encode()) # False

Post example on ESP32 not working

The example _httpHandlerTestPost method fires but doesn't make it past the line formData = httpClient.ReadRequestPostedFormData(). There is no error message. Looks like the ReadRequestContent method is the culprit. The response stops in this method at b = self._socket.readall().

exc_info not implemented on ESP32

sys.exc_info is not implemented for the ESP32 yet. It is used in several modules in this repo.
Would it be OK to replace them with Exception.message such as:

except :
    print("MicroWebSocket : Error on accept callback (%s)." % exc_info()[1])

replace with

except Exception as e:
    msg = e.message if hasattr(e, 'message') else str(e)
    print("MicroWebSocket : Error on accept callback (%s)." % msg)

Threads compatible with loboris firmware ?

Hello JC, I know that loboris makes some modification to your code in order to be compatible with his threads module. Maybe you could do as for DNS server in order to be compatible ?

Feature - Fine tune control over processing

I was thinking about creating a pull request to take the _serverProcess function and the ability to run the process outside in a while loop at the parent thread process.

def _serverProcess(self) :
    self._started = True
    while True :
        try :
            client, cliAddr = self._server.accept()
        except Exception as ex :
            if ex.args and ex.args[0] == 113 :
                break
            continue
        self._client(self, client, cliAddr)
    self._started = False

Proposed Addition

def serverProcessOneCycle(self) :
    try :
        client, cliAddr = self._server.accept()
    except Exception as ex :
        if ex.args and ex.args[0] == 113 :
            return
    self._client(self, client, cliAddr)

Example Usage

from microWebSrv import MicroWebSrv
mws = MicroWebSrv()                                    # TCP port 80 and files in /flash/www
mws.MaxWebSocketRecvLen     = 256                      # Default is set to 1024
mws.WebSocketThreaded       = False                    # WebSockets without new threads
mws.AcceptWebSocketCallback = _acceptWebSocketCallback # Function to receive WebSockets

mws.Init() ## not sure about this first init part

def some_process():
    #something awesome

whilte True:
    some_process()
    try:
        mws.serverProcessOneCycle()
   except:
       print("something went wrong")

Any thoughts, perhaps I didn't consider an already present micropythonic way to do this.

No logging is implemented to allow INFO,DEBUG,WARNING,ERROR and so.

More of a request of a feature than an error.... :-)
It would be great if there was a logging utility to allow logging to be added easily to the web server.
Something like the normal logging utility for python e.g.

import logging
logging.basicConfig(level=logging.INFO)
log = logging.getLogger("microWebSrv")
log.debug("Failed message: %d(%s)", 100, "HTTP 500")

Kind regards, Nicholas.

how to send updated json data from microwebserver to json file that embedded in html file

great project it is easy and simple
how to send updated json data from microwebserver to json file that embedded in html file with jquery ajax

`

<script type="text/javascript"> window.onload = function() { var dataPoints = []; var chart; $.getJSON("/livegraph2.json", function(data) { x=0;
	$.each(data, function(key, value){
		dataPoints.push({x:x},{y: parseInt(value)});
		x++;
		xaxis=x;
	});
	chart = new CanvasJS.Chart("chartContainer",{
		title:{
			text:"Live graph for spo2 pleth"
		},

axisX:{
title: "time in microsecond"//,
// minimum: xaxis , // change here
// maximum: xaxis+100
},
axisY:{
title: "in melevolt"//,
// minimum: xaxis , // change here
// maximum: xaxis+100
},
data: [{
type: "line",
dataPoints : dataPoints,
}]
});
chart.render();
updateChart();
});
var dataLength = 20;
function updateChart() {
$.getJSON("/livegraph2.json", function(data) {
$.each(data, function(key, value) {
dataPoints.push({
x:x,
y: parseInt(value)
})
x++;
if (dataPoints.length > dataLength) {
dataPoints.shift();
}
});

	chart.render();

	setTimeout(function(){updateChart()}, 1000);
});
}

}
</script>

<script type="text/javascript" src="https://canvasjs.com/assets/script/jquery-1.11.1.min.js"></script> <script type="text/javascript" src="https://canvasjs.com/assets/script/canvasjs.min.js"></script>
` like with micropython code ` import gc import os gc.collect() from microWebSrv import MicroWebSrv array=[80,90,86,89,90,89,86,95,94,91,89,97,94,100,110] array1='[' def _httpHandlerarray(httpClient, httpResponse): gc.collect() for x in array: array1=str(x+7) array1=',' array1[-1]=']' ## f=open('/www/livegraph2.json','w') ## f.write(mystring) ##f.close() ##print(mystring) httpResponse.WriteResponseOk(headers=None, contentType= "application/json", contentCharset="UTF-8", content=array1)

routeHandlers=[("/livegraph2.html","GET",_httpHandlerarray)]
srv=MicroWebSrv(routeHandlers=routeHandlers,webPath='/www/')
gc.collect()
print(array1)
srv.Start(threaded=False)`

403 Forbidden error occured when loading the fonts folder of the webapp made with Vue.js

Hi,

I'm using the MicroWebSrv to serve both the back end (rest api) and the front end (made with vue.js). The back end worked fine, but there is some issues with the front end.

The web app packed by Vue.js has 4 folders along with index.html, they are: css, fonts, js, statics. Altough extremely slow when loading the page for the first time, most parts of the page have loaded correctly except for the icons which are fonts. So I took a look at the console, and found some errors, e.g. GET http://192.168.123.108/fonts/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.0509ab09.woff2 net::ERR_ABORTED 403 (Forbidden)

How can I solve this problem? Is there a way to mark this folder as static folder like in Flask?

Thanks,
Kaiyuan

How to use Ajax?

Many thanks for making MicroWebSrv available!
I got a live web page update loop working with web sockets, but the real page I am trying to port to the esp32 uses Jquery Ajax (with web.py on a Raspberry Pi Zero). It would save me quite some work if I would not have to rewrite/debug the script for web sockets.
The browser developer window tells me that the script hangs in a send.
The server does not register any activity at all.
What am I doing wrong?
testajax.py:
testajax.py.txt
testajax.html:
testajax.html.txt

add support for list besides from string format of html file

For many case , html file will be loaded from flash into a string and then will be pass to WriteResponseOK.
In my application , having upto 50K of heap , but it is fragmented , a html file size of 6KB is failed to loads due to MemoryError
To overcome this , I create a list , load the html in chunk of 100bytes , modified the _write() to accept the list , it write to socket pieces by pieces.
Since micropython doesnt handle heap fragmentation , I think my experiences with this issue will help .

always got the 404 error

Hi,

I always got the "404 Not Found Nothing matches the given URI" error, although I could connect to the server.

The similar issue was reported here too: https://www.cnx-software.com/2017/10/16/esp32-micropython-tutorials/

I used the loboris fork of the Micropython firmware for ESP32: https://github.com/loboris/MicroPython_ESP32_psRAM_LoBo/. The MicroWebSrv module was frozen in the firmware.

Here is my code:

from microWebSrv import MicroWebSrv

ws = MicroWebSrv()

@MicroWebSrv.route('/')
def handlerFuncGet(httpClient, httpResponse):
    content = """\
    <!DOCTYPE html>
    <html>
        <h1>hello world</h1>
    </html>
    """
    print(content)

@MicroWebSrv.route('/<action>')
def handlerFuncEdit(httpClient, httpResponse, routeArgs):
    action = routeArgs['action']
    print(action)

ws.Start()

Thanks in advance for your help.

-Kaiyuan

POST and WebSocket does not work :-(

Examples from the delivery were used

On POST:
500 Internal Server Error
Server got itself in trouble

On MicroWebSocket Test:
ERROR : undefined

-- DISCONNECTED --

Client - Firefox 57.0.4

P.S.
GET - OK
test.pyhtml - OK

Core dump

I load one page and I get a core dump. The page loads successfully before the core. The page is a static index.html in /flash/web_admin. MicroWebSrv was compiled into frozen bytecode and I'm running on a WiPy 2.0 with 512KB RAM and 4MB flash. What else do you need to know to troubleshoot this?

from machine import Pin, info
from micropython import mem_info

gc.enable()
running = False

def web_srv_callback(web_srv_pin):
	''' If we hit the web_srv_pin launch the web server for configuration '''	
	# Debounce
	from utime import sleep, sleep_ms
	sleep(1)
	
	# Only call this function once
	global running
	if running:
		return
	
	from network import WLAN
	from microDNSSrv import MicroDNSSrv
	from microWebSrv import MicroWebSrv
	from microWebTemplate import MicroWebTemplate
	
	wlan = WLAN()
	
	MicroDNSSrv.Create({ '*' : '192.168.4.1' })
	
	if not web_srv_pin.value() == 0:
		sleep(1)
		return False
	
	# Give the clients 5 minutes to connect
	for i in range(300):
		if not wlan.isconnected():
			sleep(1)
		else:
			break
	
	if not wlan.isconnected():
		return False
	
	gc.collect()
	print('gc.mem_free(): ' + str(gc.mem_free()))
	print('machine.info(): ' + str(info()))
	print('gc.mem_alloc(): ' + str(gc.mem_alloc()))
	print('micropython.mem_info(): ' + str(mem_info()))
	
	mws = MicroWebSrv(bindIP='192.168.4.1', webPath="/flash/web_admin/")
	mws.SetNotFoundPageUrl("http://SlowBro904.local/")
	mws.Start()
	sleep(1)
	running = True
	
	@MicroWebSrv.route('/')
	def handlerFuncGet(httpClient, httpResponse):
		print("In GET-TEST HTTP")
	
	@MicroWebSrv.route('/', 'POST')
	def handlerFuncPost(httpClient, httpResponse):
		print("In POST-TEST HTTP")

web_srv_pin = Pin('P6', mode=Pin.IN, pull=Pin.PULL_UP)
web_srv_pin.callback(trigger=Pin.IRQ_FALLING, handler=web_srv_callback)
System memory info (in bytes)
---------------------------------------------
MPTask stack water mark: 1932
ServersTask stack water mark: 988
TimerTask stack water mark: 2172
IdleTask stack water mark: 600
System free heap: 15860
---------------------------------------------
machine.info(): None
gc.mem_alloc(): 47952
stack: 592 out of 5120
GC: total: 67008, used: 48080, free: 18928
 No. of 1-blocks: 525, 2-blocks: 126, max blk sz: 384, max free sz: 553
micropython.mem_info(): None

I then load one page and get a core dump.

abort() was called at PC 0x4008d4a8 on core 1

Backtrace: 0x4008d45f:0x3fff30f0 0x4008d490:0x3fff3110 0x4008d4a8:0x3fff3130 0x4008aa41:0x3fff3150 0x4008c114:0x3fff3180 0x4008c0ca:0x3fff32a0

================= CORE DUMP START =================
3EYAAA8AAABsAQAA
8JH+PzAw/z/MQP8/
gDH/P2BA/z+BsAAAlE/8P5RP/D/wkf4/jE/8PxQAAAAUM/4/FDP+P/CR/j8AAAAA
BQAAANAs/z9NUFRocmVhZAAAAAAAAAAAAQAAAMxA/z8AAAAAIA8GAAUAAAABAAAA
zPr9P/w//z+QNA1AAAAAAAAAAAAAEf0/aBH9P9AR/T8AAAAAAAAAAAEAAAAAAAAA
11dAPwAAAAAUoQlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAA==
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
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+JP9P4CS/T/wk/0/
gJL9P5CT/T8zOMe/dJn9PzBP/D/4k/0/KE/8PxkAAABbyN04X+aKPPiT/T8AAAAA
AAAAAPSP/T9JRExFAJ7K0wjmml/ZUJoAAAAAAPCT/T8AAAAAIQAGAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAEf0/aBH9P9AR/T8AAAAAAAAAAAEAAAAAAAAA
11dAPwAAAAAUoQlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJc8nw==
xDIIQCw6FEAwCwYA/LIIgECT/T8gAAAAAQAAAAAAAAC0kPw/HFH8P8RO/D/QkPw/
MzMzAwAAAABQDwAAAAAAAECS/T8DAAAAIwAGAAoAAADEjfo/AAAAAOxkDkAoZQ5A
AAAAAL00CEBAkv0/SMAIQMSN+j8AAAAAAAAAAAAAAAD//z+zAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAABAkv0/AwAAACMABgAAAAAAYJP9PwAAAAAAAAAA
AAAAALSQ/D8cUfw/xE78PwAAAACQk/0/AAAAAAAAAAAEGfw/AAAAAAAAAAAAAAAA
AQAAAAAAAAAEAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJyT/T8AAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
bJn9P/CX/T9kmf0/
8Jf9PwCZ/T8XnwgwME/8PwCU/T9smf0/KE/8PxkAAAAd9n4EUN0XdmyZ/T8AAAAA
AAAAAGiV/T9JRExFAFW+lzezPuVxkloAAQAAAGSZ/T8AAAAAIQAGAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAEf0/aBH9P9AR/T8AAAAAAAAAAAEAAAAAAAAA
11dAPwAAAAAUoQlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACuCzw==
xDIIQCw6FEAwBQYA/LIIgLCY/T8gAAAAAQAAACAAAAC0kPw/IFH8P8RO/D/wkPw/
AQAAAAAAAAD///9/V5wIgLCX/T8DAAAAIwAGAAAAAACwmP0/IAAAAAAAAAAAAAAA
AAAAAL00CECwl/0/SMAIQDST+j8AAAAAAAAAAAAAAAD//z+zAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAP//P7MAAAAAAAAAAAAAAAAAAAAA0Jj9PwAAAAABAAAA
AQAAAAQZ/D8gUfw/xE78PwAAAAAAmf0/AAAAAAAAAAAEGfw/AAAAAAAAAAAAAAAA
AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyZ/T8AAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
hIr9P5CI/T98iv0/
kIj9PxCK/T8sqgAAGEr+P2yN/T+Eiv0/FE/8PwcAAAC4ef0/uHn9P4SK/T+wef0/
EgAAAIB8/T90aVQAMIv9PwAAAAD///8A////f3yK/T8AAAAAIQAGABIAAAABAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAEf0/aBH9P9AR/T8AAAAAAAAAAAEAAAAAAAAA
11dAPwAAAAAUoQlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIz9Pw==
xDIIQCSlCEAwCQYAsdEVgFCJ/T+Mef0/4In9P9h5/T8AAAAA4Hn9PwAAAAAkpQiA
MIn9PwEAAABSAAAAIFH8PwEAAAAEGfw/AAAAABAAAAAAAAAAAAAAADSZCUBimQlA
AAAAAL00CEABAAAASMAIQESE+j8AAAAAAAAAAAAAAAD//z+zAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAJziFYCAif0/jP79PwAAAAD1VhWAkIn9P8ST/D/gif0/
AAAAANqpAACcBQAAKAAAAFIAAAAAAAAAAQAAAAAAAABR8hWAoIn9P7Ai/j8AAAAA
y+EUgMCJ/T/Ek/w/4In9P8LhFIDAif0/tC7/P+CJ/T9SAAAA2qkAAPb///8YAAAA
AAAAAOCJ/T/o8RVAAAAAAGCa/D/AVRVAAAAAABxR/D8AAAAAEIr9PwAAAAAAAAAA
YC7/PwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAciv0/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAA
EEr+P7Bf/j98Y/4/
sF/+PxBj/j8uqwAArFL8P4yK/T8QSv4/FE/8Pw4AAAAUYPw/FGD8PxBK/j8AAAAA
CwAAAIBL/j9JUlFzAAAAAAAAAAAAAAAAAQAAAHxj/j8AAAAAIQAGAAsAAAAAAAAA
GKj9P6xi/j+QNA1AAAAAAAAAAAAAEf0/aBH9P9AR/T8AAAAAAAAAAAEAAAAAAAAA
11dAPwAAAAAUoQlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAA==
xDIIQGyyCEAwBwYAMdUNgHBg/j8uqwAAIFH8PwQZ/D8BAAAAKgAAAPBh/j9ssgiA
UGD+PwEAAAAuqwAAEEr+PwEAAAD+AAAAAAAAAB4AAAAAAAAAAAAAABibCUAjmwlA
AAAAAL00CEABAAAASMAIQERd+z8AAAAAAAAAAAAAAAD//z+zAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFEr+Pxhh/j8aOhCAkGD+P+gDAADkX/w/
0GD+P6xi/j8USv4/cAAAALRCD4CwYP4/AAB6RAAAAAABAAAAAQAAAAEAAABSDAAA
+AwPgNBg/j8Iq0E/AQAAAAEAAAABAAAAAAAAAPgCAAC2vw+A8GD+PwirQT8BAAAA
AAAAANCT/j8BAAAA8F/+P8NDD4AQYf4/BAAAAJHp/j8AAAAA0JP+Pzhh/j/AYP4/
+AwPgLBh/j/ApP4/gF78P2Bi/j8AAAAAw0MPgBBh/j9gYv4/EgAAABSU/j8AAAAA
EJT+PwAAAAAAAAAAAAAAAPgMD4CwYf4/+AwPgLBh/j/ApP4/gF78P+ayD4AAAAAA
EgAAAAgAAAAIlP4/AAAAAAAAAACwk/4/FJT+PxCU/j8RAAAAEGL+PxCy/j/Mk/4/
zJP+PwAAAAAw////kun+PzwND4DwYf4/ELL+PwEAAABC6f4/rOn9PwAAAADY0A2A
AAAAABBi/j8USv4/NGD8P7CT/j9IAAAAEgAAALBh/j+VEw6AEGL+PxCy/j80IPw/
AAAAABBi/j/+AAAANCD8P1p/DoBAYv4/NCD8P/xc/D80IPw/AAAAAAAAAAAAAAAA
NGD8PwAAAAAAAAAAAAAAAMTQDYBgYv4/gBMOQAAAAAAAAAAA4GL+P4hi/j/gYv4/
AAAAAPBi/j/8XPw/AAAAAAAAAAAAAAAAxNANgGBi/j8AAAAAAAAAAIBe/D8AAAAA
CgAAAP///38AAAAAAAAAAAAAAAAAAAAAAAAAAPBi/j/8XPw/AAAAAE9/DoCAXvw/
wKT+PxBh/j/AYv4/ABQAAIATDkA0IPw/AAAAAAAAAACAXvw/AAAAAAoAAAD///9/
AAAAABBj/j8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAABAAAAAAAcY/4/AAAAAAAAAAAAAHpEAACAPwAAekQAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAA
pFL8P1DJ/T/Azv0/
UMn9P2DO/T+eNQEAyI/+PxhK/j+kUvw/FE/8PxQAAACIBP4/iAT+P6RS/D8AAAAA
BQAAAMSu/T9NaWNyb1B5AAAAAAAAAAAAAQAAAMDO/T8AAAAAIQAGAAUAAAAAAAAA
GHb7Pzxe/D+QNA1AAAAAAAAAAAAAEf0/aBH9P9AR/T8AAAAAAAAAAAEAAAAAAAAA
11dAPwAAAAAUoQlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAA==
xDIIQGyyCEAwCwYAMdUNgBDK/T+eNQEAIFH8PwQZ/D8BAAAAAAAAAAEAAABssgiA
8Mn9PwEAAACeNQEApFL8PwEAAAD+AAAAAAAAAB4AAAA3kw+A0Mn9PyFBCEBBQQhA
AAAAAL00CEABAAAASMAIQJTI+j8AAAAAAAAAAAAAAAD//z+zAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAGmhD4Awyv0/XLJBP6SuQj8aOhCAMMr9P2DqAADkX/w/
AQAAAAIAAADUdhBAAQAAALRCD4BQyv0/AAB6RAAAAAABAAAAAQAAANR2EEABAAAA
+AwPgHDK/T8Iq0E/AQAAAAEAAAABAAAAAAAAAE4MAABgDQ+AkMr9PwirQT8BAAAA
AAAAAJTL/T8BAAAA0g0AAEzAD4Cwyv0/AQAAAAAAAAAAAAAAlMv9PwwAAABwyv0/
w0MPgNDK/T8IAAAArIz+P4zL/T+Qy/0/5////wEAAAD4DA+AcMv9P4Be/D+AXvw/
UMz9PxDL/T/DQw+A0Mr9P1DM/T8KAAAAtMv9PwAAAACwy/0/AAAAAIMAAABlAAAA
jckOgEDL/T/4DA+AcMv9P4Be/D+AXvw/5rIPgIh+/j8KAAAABQAAAKjL/T8AAAAA
AAAAAHDL/T+0y/0/sMv9PwkAAAAAAAAAdMv9P4zL/T+My/0/AAAAADD///+tjP4/
JQ0PgBDM/T/gdv4/AAAAAOaJ/j+rjP4/IHf+P4jL/T+oy/0/gF78PwoAAAAIq0E/
AAAAAHkAAAABAAAAPwAAABkAAAABAAAAAQAAAAUAAADbAgAA4Mv9P1RS/D8gzP0/
m90NgFDM/T8AAAAAwwUAAOKJ/j8AzP0/IMz9PwAAAAAAAAAAAAAAAOB2/j8AAAAA
cMv9PwAAAAAKAAAA0Mv9P+baDYAwzP0/4Hb+PwAAAAAAAAAAAAAAAAAAAAAAAAAA
m90NgFDM/T/gdv4/wwUAAAAAAAAAAAAAAAAAACAAAADCzA2A8Mz9PycdQD9gd/4/
AAAAAIDM/T+b3Q2AUMz9PwAAAAAAAAAAAAAAAAfqQD+E6UA/CAAAACcdQD/gdv4/
9AIQQAoAAADCzA2A8Mz9PycdQD9gd/4/k9oNgJSJ/j+Qh/4/0Mz9PwYAAADkX/w/
AAAAANDM/T9ozP0/0Mz9PwAAAAAKBQAAYHf+PwEAAAAAAAAAB+pAP4TpQD8IAAAA
AAAAABDN/T8gzf0/AAAAAKDM/T8AAAAAAAAAAKRa/D8AAAAAYM79PwAAAAAAAAAA
AQAAAAAAAAClpaWlpaWlpZIAAAAhAAsBIEJPT1QuUFkA//////9ib290LnB5AP//
////////////////////////////////////////////paWlpaWlpaWlpaWlpaWl
paWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWl
xDIIQPDJDUAwAAUAAAAAAGDO/T8AAAAAAP//////////////////////////////
////////////AAAAAAAAAAAAAAABAAAAAAAAAP////8AAAAA////////////////
/////8VCE4EAAAAAMgAAAAIAAAAAAAAAAAAZABDN/T8ADAEAAAAAAAEAAAAYzv0/
4M39PwAAAAAAAAAAAAAAAAEAAABMVPw/AAAAAKEdQD8AAAAAAAAAAAAAAAAAAAAA
AAABAAAAAABszv0/AAAAAAAAAAAAYGpHAABwQgAAekQAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
wI/+P/Am/z/MLP8/
8Cb/P2As/z8NMkIAHE/8P6xS/D/Aj/4/FE/8PxQAAADgOv4/4Dr+P8CP/j/YOv4/
BQAAANAY/z9NUFRocmVhZAAAAAAAAAAAAQAAAMws/z8AAAAAIQAGAAUAAAABAAAA
8P/9P/wr/z+QNA1AAAAAAAAAAAAAEf0/aBH9P9AR/T8AAAAAAAAAAAEAAAAAAAAA
11dAPwAAAAAUoQlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAA==
xDIIQCSlCEAwCwYAsdEVgLAn/z+0Ov4/QCj/PwA7/j8AAAAACDv+PwAAAAAkpQiA
kCf/PwEAAAA2iUEAIFH8PwEAAAAEGfw/AAAAABoAAAAAAAAAAwAAABibCUAjmwlA
AAAAAL00CEABAAAASMAIQJQm/D8AAAAAAAAAAAAAAAD//z+zAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAEAo/z8DAAAAVGD8PwAAAACe1hWA8Cf/P0z+/T9AKP8/
AAAAANeoAABQ3/4/PF78PzaJQQBUYPw/VGH8PwYAAACy/SUQAwAAAHCeDkDang5A
X9oVgCAo/z8AAAAA0Cj/P5Qm/D8AAAAAAAAAAAAAAAA2iUEA16gAAP4AAAAjAAYA
080UgHAo/z88/v0/0Cj/P///P7MAAAAAAAAAAAAAAAAAAAAAAAAAAIgm/j8AIAAA
AAAAAPC/AEAwBQYAiq0IgDz+/T8AAAAAAQAAAAAAAADF2hSAoCj/PwAAAAAgAAAA
/gAAALgY/D8jBQYAwI/+PyAAAAAAAAAAAAAAAAAAAAAccg6AICn/PwUQAADQQP8/
AAAAAL00CEABAAAASMAIQAAAAAAAAAAAAAAAAAAAAAD//z+zAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAGAp/z9sQ/4/AAAAAAAAAABQKf8/0ED/PwEAAADQQP8/
AAEAAAAAAADwAAAANJP8P58qDoBQKf8/MBf/P9BA/z8AAAAAYCn/P+Rf/D8AAQAA
AAEAADST/D9QKf8/SJP8P9FCD4CQKf8/MBf/PwByDkA0YPw/AAAAAAEAAAAAAAAA
EAAAAJAp/z8wF/8/AQIAAAABAACoKf8/sCn/P6wp/z/4DA+A4Cn/P1gvQD8CAAAA
AQEAAAABAADQQP8/2NANgFDo/j/AKf8/NGD8P4RO/D+l0Q2A4Cn/P+hf/D8BAAAA
5F/8PwIAAAAAAAAAAQAAAGAND4AAKv8/WC9APwIAAAAAAAAA8IX+PwEAAABSCwAA
TMAPgCAq/z8BAAAAAAAAAAAAAADwhf4/AAAAAAAAAADDQw+AQCr/PwgAAACZk0E/
7IX+PwEAAABoKv8/0Cr/P/gMD4DgKv8/ENv+PxDb/j+wK/8/EHj+P8NDD4BAKv8/
sCv/P+yF/j8QeP4/HIb+P02UQT8yAAAApaWlpaWlpaWlpaWlpaWlpfgMD4DgKv8/
ENv+PxDb/j/msg+AcZNBPwwAAAAHAAAAHIb+PwAAAAAAAAAA0IX+PxyG/j8Yhv4/
CwAAAEAr/z+lpaWlpaWlpeyF/j8AAAAAMP///5qTQT8NMA+AICv/PxDd/j8BAAAA
YpNBP6WlpaWlpaWlpaWlpQAAAABAK/8/9Fn8P7gr/z/Qhf4/PAAAAAwAAADgKv8/
+AwPgEAr/z9gGP8/AAAAAAAAAABAK/8/AQAAAAAAAAB2sA+AkCv/P2AY/z8AAAAA
UOj+PwAAAAABAAAA5jIIQJQm/D8AAAAAAAAAAAAAAABAK/8/AAAAAAAAAAAAAAAA
AAAAAEhk/j8AAAAAYCv/P8TQDYCwK/8/AAAAADBk/j8AAAAASGT+P9gr/z8wLP8/
AAAAAEAs/z8wZP4/AAAAAAAAAAAAAAAAxNANgLAr/z8AAAAAMGT+PyMABgAAAAAA
BAAAAP///38AAAAAAAAAAAAAAAAAAAAAAAAAAEAs/z8wZP4/AAAAAGWwD4CAXvw/
ENv+P0Aq/z8QLP8/ABAAADBk/j8AAAAAAAAAAAAAAAAwZP4/AAAAAAQAAAD///9/
AAAAAGAs/z8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAABsLP8/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAPAs/z+wLP8/BAAAAAAAAAAAAAAAEC3/P/Mv/D8yAAAA
QQAAAAAAAAAAAAAA
ZI39P8Dn/T8g6f0/
wOf9P8Do/T/cqQAAjIr9PxxP/D9kjf0/FE/8PxQAAAAAAAAAAAAAAGSN/T8AAAAA
BQAAACTh/T9TZXJ2ZXJzAAAAAAAAAAAAAQAAACDp/T8AAAAAIQAGAAUAAAAAAAAA
XHL7PwAAAACQNA1AAAAAAAsAAAAAEf0/aBH9P9AR/T8AAAAAAAAAAAEAAAAAAAAA
11dAPwAAAAAUoQlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
xDIIQGyyCEAwAQYAF84NgIDo/T/cqQAAIFH8PwQZ/D8BAAAAAAD/AAAAAP9ssgiA
YOj9PwEAAADcqQAAZI39PwEAAAD+AAAAIwAGAAAAAACniQ6AQOj9PzSZCUBimQlA
/////700CEABAAAASMAIQPTi+j8AAAAAAAAAAAAAAAD//z+zAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAP//P7MAAAAAAAAAAAAAAAAAAAAAoOj9PwAAAAABAAAA
IE1APwEAAAAAAP8AAAAA/wAAAADA6P0/AAAAAAAAAAAAAAAAAQAAAM5W/D8AAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzOj9PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAA==
2KX9P4Ck/T/Qpf0/
gKT9P3Cl/T8AAAAACE/8PwhP/D/Ypf0/AE/8Pw8AAAAIm/0/CJv9P9il/T8Am/0/
CgAAANSb/T9UbXIgU3ZjAD7k/Lffe0AAAAAAANCl/T8AAAAAIQAGAAoAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAEf0/aBH9P9AR/T8AAAAAAAAAAAEAAAAAAAAA
11dAPwAAAAAUoQlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALy0sQ==
xDIIQJm+CEAwAAYAAAAAAECl/T8AAAAAAAAAAAAAAAAsUfw/JFH8PwEAAACZvgiA
IKX9PwAAAAAEGfw/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAL00CEAAAAAASMAIQKSf+j8AAAAAAAAAAAAAAAD//z+zAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAKSf+j8AAAAAAAAAAAAAAAAAAAAAcKX9PwAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAB8pf0/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
9Iv9P2Df/T8c4f0/
YN/9P7Dg/T8AAL0A+FH7P0x2/T/0i/0/pE78PwUAAAD0zv0/9M79P/SL/T/szv0/
FAAAACDV/T9ldmVudFRhc2sAAAAgAAAAAAAAABzh/T8AAAAAIQAGABQAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAEf0/aBH9P9AR/T8AAAAAAAAAAAEAAAAAAAAA
11dAPwAAAAAUoQlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
xDIIQCSlCEAwCwYAUDkUgCDg/T/Izv0/YOD9PxTP/T8AAAAAHM/9PwAAAAAkpQiA
AOD9PwAAAAD/////HFH8PwAAAAAEGfw/AAAAAAAAAAD0i/0/AAAAADSZCUBimQlA
AAAAAL00CEAAAAAASMAIQOTa+j8AAAAAAAAAAAAAAAD//z+zAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAABxR/D8AAAAABBn8PyAMBgAAAAAAYOD9P2yQ/D8AAAAA
AAAAAD0pAAD+AAAAIAwGAP////9g4P0/bJD8PwAAAAAUz/0/AAAAAKzP/T8BAAAA
AAAAALDg/T8AAAAAAAAAAAcAAADAqAFw////AMCoAQEBAAAAlHT7PwEAAAAGAAAA
i3YVgFCJ/T+ofvs/vPv9PwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAC84P0/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAA
8FH7P1BQ+z/oUfs/
UFD7P4BR+z+Idvb/gHD9P/yL/T/wUfs/pE78PwQAAAAIR/s/CEf7P/BR+z8AR/s/
FQAAAOxH+z9wbVQAp93FOzj9+KFH0FoA////f+hR+z8AAAAAIQAGABUAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAEf0/aBH9P9AR/T8AAAAAAAAAAAEAAAAAAAAA
11dAPwAAAAAUoQlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOCklw==
xDIIQCSlCEAwBwYAMT0SgBBR+z/cRvs/UFH7PyhH+z8AAAAAMEf7PwAAAAAkpQiA
8FD7PwEAAAD/////IFH8PwEAAAAEGfw/AAAAAAAAAAAzMzMDAFH7PzSZCUBimQlA
/////700CEABAAAASMAIQLRL+D8AAAAAAAAAAAAAAAD//z+zAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAADoAwAgUfs/MHb8P2x3/D8AAAAAUFH7PzB2/D/E6UE/
AAAAANyoAAAwdvw/xOlBP/////8AAAAAAAAAAAAAAAAAAAwAAQAAAP4AAAABAAAA
AAAAAIBR+z8AAAAAAAAAAAYAAAADAAAAAAAAAAAAAABsd/w/MHb8PywBAAAAAAAg
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjFH7PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
eHD9P/Bu/T9wcP0/
8G79PxBw/T/4feHWCB/9P/hR+z94cP0/pE78PwEAAABIbP0/SGz9P3hw/T9AbP0/
GAAAAHRs/T9pcGMwAFsUPEAiDcldlkIAAAAAAHBw/T8AAAAAIQAGABgAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAEf0/aBH9P9AR/T8AAAAAAAAAAAEAAAAAAAAA
11dAPwAAAAAUoQlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOz8lA==
xDIIQCSlCEAwCwYA/BwIgLBv/T8cbP0/AAAAAGhs/T8AAAAAHGz9PwAAAAAkpQiA
kG/9PwAAAAD/////HFH8PwAAAAAEGfw/FwAAAAAAAAD//z+zAAAAAAAAAAAAAAAA
AAAAAL00CEAAAAAASMAIQERq+j8AAAAAAAAAAAAAAAD//z+zAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAHhw/T8BAAAA/gAAABcAAAAAAAAA8G/9PwBO/D8AAAAA
AAAAABupAAAAAAAAFwAAAP////8AAAAAAE78P/BN/D9obP0/AAAAABxs/T8BAAAA
AAAAABBw/T8AAAAAAAAAAPRKCEAAAAAAAAAAAAAAAADFEQiAYDz+P4xO/D+UTvw/
AAAAAAAAAAAccP0/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AB/9P3Ad/T/4Hv0/
cB39P5Ae/T8zcriwjNj7P4Bw/T8AH/0/pE78PwMAAADQEv0/0BL9PwAf/T/IEv0/
FgAAAPwS/T9lc3BfdGltZXIAveP2zfgAAAAAAPge/T8AAAAAIQAGABYAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAEf0/aBH9P9AR/T8AAAAAAAAAAAEAAAAAAAAA
11dAPwAAAAAUoQlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANDq3w==
xDIIQCSlCEAwCwYAVSMNgDAe/T+kEv0/AAAAAPAS/T8AAAAApBL9PwAAAAAkpQiA
EB79PwAAAAD/////HFH8PwAAAAAEGfw/IwAGAAAAAAD/////vTQIQDSZCUBimQlA
/////700CEAAAAAASMAIQMQY+j8AAAAAAAAAAAAAAAD//z+zAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAPEVCIAwHv0/yBj8PwAAAAAAAAAAcB79P6xN/D+0Tfw/
AAAAAKGpAAD+AAAAIwAGAP////9wHv0/zNr7P7RN/D/QGPw/AAAAAFAAAABicqIC
AAAAAJAe/T8AAAAAAAAAAAAAAAAAAAAAtE38PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAACcHv0/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAA=
hNj7P9DW+z982Ps/
0Nb7PxDY+z/gj0OwrE78Pwgf/T+E2Ps/pE78PwIAAAAUwvs/FML7P4TY+z8Mwvs/
FwAAAIDI+z93aWZpABNcsCt2XYYIQFkAAAAAAHzY+z8AAAAAIQAGABcAAAABAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAEf0/aBH9P9AR/T8AAAAAAAAAAAEAAAAAAAAA
11dAPwAAAAAUoQlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJSZKg==
xDIIQCSlCEAwCwYABGkSgJDX+z/owfs/4Nf7PzTC+z8AAAAAPML7PwAAAAAkpQiA
cNf7PwAAAAD/////HFH8PwAAAAAEGfw/2NT/Px8AAAAlFxKAcNf7PzSZCUBimQlA
/////700CEAAAAAASMAIQETS+D8AAAAAAAAAAAAAAAD//z+zAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAANBpEoCg1/s/CTBMAAgABAAAAAAA0Nf7P8C3/D+Ad/w/
AAAAANepAADAt/w/gHf8P/////8AAAAAAAAAAAAAAAAJMEwAxAAAAPAi/j/kKPw/
AAAAABDY+z8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAAAAAAAAAAAAAAAAAAAA
GgAAAAAAAAD/////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABzY+z8AAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
RHb9P7B0/T88dv0/
sHT9P9B1/T81WeFC/Iv9P6xO/D9Edv0/pE78PwEAAAAUcv0/FHL9P0R2/T8Mcv0/
GAAAAEBy/T9pcGMxAErf3lr/NmBJ0zAAAQAAADx2/T8AAAAAIQAGABgAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAEf0/aBH9P9AR/T8AAAAAAAAAAAEAAAAAAAAA
11dAPwAAAAAUoQlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANm2HA==
xDIIQCSlCEAwAwYA/BwIgHB1/T/ocf0/AAAAADRy/T8AAAAA6HH9PwAAAAAkpQiA
UHX9PwEAAAD/////IFH8PwEAAAAEGfw/IAMGAAAAAAD//z+zAAAAAAAAAAAAAAAA
AAAAAL00CEABAAAASMAIQARw+j8AAAAAAAAAAAAAAAD//z+zAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAER2/T8BAAAA/gAAACMABgAAAAAAsHX9PwRO/D8AAAAA
AAAAAFoEAAAAAAAAIAMGAP////8AAAAABE78P/BN/D8QbP0/AAAAAAEAAAAAAAAA
AAAAANB1/T8AAAAAAAAAAPRKCEABAAAAAAAAAAAAAABhEgiAgH3+PwEAAAAAAAAA
AAAAAAAAAADcdf0/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAA
================= CORE DUMP END =================
Rebooting...
MicroPython 7c0b797 on 2018-05-05; WiPy with ESP32
Type "help()" for more information.
>>>

httpResponse doesn't send the response after reconnecting wifi

Hi,

I have an API which is used to connet/reconnet to a Wifi AP, I wanted this API to WriteResponseOK after the connection is established, however it does send back any response even though the connection was made. For other APIs in my code, httpResponse worked flawlessly, so I think it may be related to wlan methods.

This is the API.

        @MicroWebSrv.route('/wifi', 'POST')
        def wifi_post(httpClient, httpResponse):
            wifi_dict = httpClient.ReadRequestContentAsJSON()
            new_ip = wifi.sta_connect(wifi_dict['ssid'], wifi_dict['pass'])
            if wifi.is_connected():
                if not rtc.is_synced():
                    print('Syncing RTC...')
                    rtc.sync()
                print(new_ip)
                httpResponse.WriteResponseOk()
            else:
                httpResponse.WriteResponseInternalServerError()

So the above API gets a post request with below json data:

{
  "ssid": "new-wifi-ap",
  "pass": "12345678"
}

Below is the wifi.sta_connect() method:

    def sta_connect(self, ap_ssid, ap_pass, verify_ap=False):
        """
        Connect to an Access Point by its SSID and Password
        return: string; the IP of the STA
        """
        # Attempt connection only if SSID can be found
        if verify_ap:
            if not self.verify_ap(ap_ssid):
                print('Network "' + ap_ssid + '" does not present')
                return None

        # Disconnect current wifi network
        if self.sta.isconnected():
            print('Disconnecting from current network...')
            self.sta.disconnect()
            utime.sleep(1)
            self.sta.active(False)
            utime.sleep_ms(200)
            self.sta.active(True)
            utime.sleep_ms(200)
        start = utime.ticks_ms()
        timeout = 10000
        while not self.sta.isconnected():
            if utime.ticks_diff(utime.ticks_ms(), start) > timeout:
                print('Connecting to "' + ap_ssid + '" Timeout')
                if self.ssid and self.pwd:
                    print('Restore the connection with "' + self.ssid + '"')
                    try:
                        self.sta_connect(self.ssid, self.pwd)
                    except:
                        pass
                else:
                    return None
                break
            print('Connecting to "' + ap_ssid + '"...')
            self.sta.connect(ap_ssid, ap_pass)
            while not self.sta.isconnected() and utime.ticks_diff(utime.ticks_ms(), start) < timeout:
                print('Connecting...')
                utime.sleep_ms(1500)
        else:
            print('Network "' + ap_ssid + '" Connected!')
            # if successfully connected, store the SSID & Password
            self.ssid = ap_ssid
            self.pwd = ap_pass
            return self.get_sta_ip_addr()

In the REPL I can see the connection was successfully made, then it just got stuck right at where httpResponse.WriteResponseOk() is, in the browser console, that request was in pending status until timeout.

What can be the issue?

Firmware: MicroPython v1.11-240-g519746cae on 2019-08-26; ESP32 module (spiram) with ESP32

Thanks.
Kaiyuan

Out of memory on main.py startup

Running micropython on nodemcu. Copied MicroWebServ.py and main.py using webrepl.
Upon restart of the board

Traceback (most recent call last):
File "main.py", line 2, in
MemoryError: memory allocation failed, allocating %u bytes

MicroPython v1.9.4-8-ga9a3caad0 on 2018-05-11; ESP module with ESP82

Any suggestions? THanks

MicroWebSrv not started when in AP mode

Hello JC,
I have a new issue maybe in side effect of loboris network status improvements.
Your server code checks WLAN connection before starting. But in AP mode, the connection is not made, thus not starting the web server.

Maybe you could follow the example of lemariva in his FTP server ?


        self.wlan = network.WLAN(network.AP_IF)
        if self.wlan.active():
            ifconfig = self.wlan.ifconfig()
        else:
            self.wlan = network.WLAN(network.STA_IF)
            if self.wlan.active():
                ifconfig = self.wlan.ifconfig()
            else:
                dbg("No active connection")

Memory importing MicroWebSrv on LoPy 1

When running the basic example, in the import statement:
from microWebSrv import MicroWebSrv

I get the following exception:
MemoryError: memory allocation failed, allocating 56 bytes

According to print(gc.mem_free()) my free memory before the import is 57072

I am trying this on a LoPy with firmware version '1.17.3.b1'

noob question- examples not working.

Hello,
I was switching to micropython and start to looking for web server, found this wonderful server and decided to test it. I was able to start the server from basic example and access root "/" also open PDF example file, but when decided to test .pyhtml it returns an error (http://192.168.7.96/test.pyhtml):

PyHTML page execution error
unexpected indent (line 1)

another error seen when try (http://192.168.7.96/wstest.html):

MicroWebSocket Test :

Connection to ws://192.168.7.96...

ERROR : undefined

-- DISCONNECTED --

perhaps I'm missing something, my python knowledge is far from good :)
I'm using micropython 1.9.4 on ESP32

WebSocket 501 error

Thanks for creating the WebSocket support!
When I run the wstest.html example on an ESP32:

websocket = new WebSocket(wsUri);
is throwing the following error:

WebSocket connection to 'ws://192.168.0.39/' failed: Error during WebSocket handshake: Unexpected response code: 501

Looks like there are 2 issues.

  1. def _getConnUpgrade() checks if connection == 'upgrade'. The problem is connection can hold more than 1 attribute such as 'upgrade, keep-alive'. I changed == to in to fix:
    if 'upgrade' in self._headers.get('Connection', '').lower()

  2. A bigger problem is that uhashlib is not implemented. MicroWebSocket.py imports sha1 from uhashlib. I don't have a fix. MicroPython lib contains a hashlib library. It contains sha256, but not sha1. Is it possible to use sha256 instead of sha1?

can't convert 'bytearray' object to str implicitly

I am having trouble running the example with regard to browsing index.html on an ESP32.
At first the index.html file was not found so I specified webPath='/www/'
This fixed the file not found error.

But then I received a NameException: name _'tryAllocByteArray' is not defined in the ResponseWriteFile() method. I fixed the error by moving the function into the Response class.

Next I received the Exception: can't convert 'bytearray' object to str implicitly in the same ResponseWriteFile() method when it called the write() method. Looks like _client.socket.send(data) expects a string and not a byte array. Normally I would convert with decode('utf-8') but it does not appear to be implemented. Therefore I did an ugly hack of the write() method:

if type(data) == str:
                return self._client._socket.send(data)
            else:
                for b in data:
                    self._client._socket.send(chr(b))

The page is now loading as HTML with CSS formatting. However, the image is not loading. My write() method hack is throwing an [Errno 104] ECONNRESET. I'm don't know why.

error throw out when init webserver on lobo ESP32 micropython

hi jczic:
i meant to try the code below:

from microWebSrv import MicroWebSrv
mws = MicroWebSrv() # TCP port 80 and files in /flash/www
mws.Start() # Starts server in a new thread

i got the error message when i import microWebSrv, is there any dependent library i didnt use or compiled with?Thanks..

from microWebSrv import MicroWebSrv
Traceback (most recent call last):
File "", line 1, in

Separe port/services for Websocket and Webserver

Hi Christophe
Congratulations for your work ¡¡¡. I have a question about the constructor:

Is it possible to change the ports of the websocket process and the webserver process?
For example, the webserver works on port 80 and websocket on 81. I notice that while I have port 80 opened by ws: // the protocol http: // the web server stops working
A lot of thanks

html and js gzip support

Hello,

First of all, congrats for the great project and for sharing!.

I'm trying to make MicroWebSrv serve gzipped index and js files (just testing doing an app with react). But at the moment can't make it work.

I've modified microwebsrv.py file adding:
"index.html.gz" under _indexPages
And
".gz" : "application/gzip" under _mimeTypes

I'm really novice, i'll investigate further, just asking if someone has better knowledge to help me

No socket write when run in thread

Hi , is it weird that when the Start() run in main thread , everything work , but if I do
start_new_thread(Start , ())
, there seem to be no socket._write() occur ! .
Is there anyway to make it async ?

nmap scan stops MicroWebSrv

Hello,
thank you for this nice web server project!

I'm using nmap to discover devices in my network. However, as soon as I start the scan in the linux console, MicroWebSrv on my WiPy 3.0 stops working. After that, restarting the server with srv.Start() fails due to [Errno 12] ENOMEM. I found that I need to close the socket first. srv.Stop() will not help, because it closes only, if srv._started is true, which is not the case. Maybe this can be changed? srv._server.close() helps. After that a restart of the server is possible without reseting the whole device.

To trace the cause of the server stop error, I changed the try/except block in microWebSrv.py line 239 to

try :
   client, cliAddr = self._server.accept()
except Exception as e :
   print(str(e))
   break

I get [Errno 128] ENOTCONN when nmap starts.

It seems some connection is being lost. Is there a way to prevent MicroWebSrv from stopping at this position?

nmap has version 7.60
wipy firmware is 1.19.0.b4
micropython has version 1.9.4
Server is started with:

srv = MicroWebSrv(routeHandlers = routeHandlers)
srv.MaxWebSocketRecvLen = 256
srv.WebSocketThreaded = True
srv.AcceptWebSocketCallback = _acceptWebSocketCallback
srv.Start(threaded = True)

response too slow

thanks for sharing this amazing project!
the average of http-responsing time is too slow, about 3 seconds.
Is there a way to optimize?

Handling multipart/form-data requests

First of all thanks a lot for your excellent work on the HTTP server!

I'm wondering whether you support multipart/form-data requests. I'm trying to upload a file using curl:

curl -v http://192.168.1.100/test -F "[email protected]"

but I'm getting an empty bytearray from a call to ReadRequestContent(). Am I doing something wrong or it's not supported yet?

Here's the output from curl:

*   Trying 192.168.1.100...
* TCP_NODELAY set
* Connected to 192.168.1.100 (192.168.1.100) port 80 (#0)
> POST /test HTTP/1.1
> Host: 192.168.1.100
> User-Agent: curl/7.54.0
> Accept: */*
> Content-Length: 90842
> Expect: 100-continue
> Content-Type: multipart/form-data; boundary=------------------------fa4b1f9e0d76e70b
> 
* HTTP 1.0, assume close after body
< HTTP/1.0 500 Internal Server Error
< Content-Type: text/html; charset=UTF-8
< Content-Length: 250
< Server: MicroWebSrv by JC`zic
< Connection: close
< 
        <html>
            <head>
                <title>Error</title>
            </head>
            <body>
                <h1>500 Internal Server Error</h1>
                Server got itself in trouble
            </body>
        </html>
* Closing connection 0

Chrome not load all files ?

Why Chrome, Opera not loading all files (index.html. style.css, bootstrap.css, jquery.js, app.js). Every F5 load only some files?

FireFox works.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.