lilzz
Posts: 411
Joined: Sat Nov 30, 2013 5:27 pm

http.py from webIOPi

Sat Mar 08, 2014 4:37 am

Code: Select all

import os
import threading
import re
import codecs
import mimetypes as mime
import logging

from webiopi.utils import *

if PYTHON_MAJOR >= 3:
    import http.server as BaseHTTPServer
else:
    import BaseHTTPServer

try :
    import _webiopi.GPIO as GPIO
except:
    pass

WEBIOPI_DOCROOT = "/usr/share/webiopi/htdocs"

class HTTPServer(BaseHTTPServer.HTTPServer, threading.Thread):
    def __init__(self, host, port, handler, context, docroot, index, auth=None):
        BaseHTTPServer.HTTPServer.__init__(self, ("", port), HTTPHandler)
        threading.Thread.__init__(self, name="HTTPThread")
        self.host = host
        self.port = port

        if context:
            self.context = context
            if not self.context.startswith("/"):
                self.context = "/" + self.context
            if not self.context.endswith("/"):
                self.context += "/"
        else:
            self.context = "/"

        self.docroot = docroot

        if index:
            self.index = index
        else:
            self.index = "index.html"
            
        self.handler = handler
        self.auth = auth

        self.running = True
        self.start()
            
    def get_request(self):
        sock, addr = self.socket.accept()
        sock.settimeout(10.0)
        return (sock, addr)

    def run(self):
        info("HTTP Server binded on http://%s:%s%s" % (self.host, self.port, self.context))
        try:
            self.serve_forever()
        except Exception as e:
            if self.running == True:
                exception(e)
        info("HTTP Server stopped")

    def stop(self):
        self.running = False
        self.server_close()

class HTTPHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    logger = logging.getLogger("HTTP")

    def log_message(self, fmt, *args):
        self.logger.debug(fmt % args)
    
    def log_error(self, fmt, *args):
        pass
        
    def version_string(self):
        return VERSION_STRING
    
    def checkAuthentication(self):
        if self.server.auth == None or len(self.server.auth) == 0:
            return True
        
        authHeader = self.headers.get('Authorization')
        if authHeader == None:
            return False
        
        if not authHeader.startswith("Basic "):
            return False
        
        auth = authHeader.replace("Basic ", "")
        if PYTHON_MAJOR >= 3:
            auth_hash = encrypt(auth.encode())
        else:
            auth_hash = encrypt(auth)
            
        if auth_hash == self.server.auth:
            return True
        return False

    def requestAuthentication(self):
        self.send_response(401)
        self.send_header("WWW-Authenticate", 'Basic realm="webiopi"')
        self.end_headers();
    
    def sendResponse(self, code, body=None, type="text/plain"):
        if code >= 400:
            if body != None:
                self.send_error(code, body)
            else:
                self.send_error(code)
        else:
            self.send_response(code)
            self.send_header("Cache-Control", "no-cache")
            if body != None:
                self.send_header("Content-Type", type);
                self.end_headers();
                self.wfile.write(body.encode())
                
    def findFile(self, filepath):
        if os.path.exists(filepath):
            if os.path.isdir(filepath):
                filepath += "/" + self.server.index
                if os.path.exists(filepath):
                    return filepath
            else:
                return filepath
        return None
        
                
    def serveFile(self, relativePath):
        if self.server.docroot != None:
            path = self.findFile(self.server.docroot + "/" + relativePath)
            if path == None:
                path = self.findFile("./" + relativePath)

        else:
            path = self.findFile("./" + relativePath)                
            if path == None:
                path = self.findFile(WEBIOPI_DOCROOT + "/" + relativePath)

        if path == None and (relativePath.startswith("webiopi.") or relativePath.startswith("jquery")):
            path = self.findFile(WEBIOPI_DOCROOT + "/" + relativePath)

        if path == None:
            return self.sendResponse(404, "Not Found")

        realPath = os.path.realpath(path)
        
        if realPath.endswith(".py"):
            return self.sendResponse(403, "Not Authorized")
        
        if not (realPath.startswith(os.getcwd()) 
                or (self.server.docroot and realPath.startswith(self.server.docroot))
                or realPath.startswith(WEBIOPI_DOCROOT)):
            return self.sendResponse(403, "Not Authorized")
        
        (type, encoding) = mime.guess_type(path)
        f = codecs.open(path, encoding=encoding)
        data = f.read()
        f.close()
        self.send_response(200)
        self.send_header("Content-Type", type);
        self.send_header("Content-Length", os.path.getsize(realPath))
        self.end_headers()
        self.wfile.write(data)
        
    def processRequest(self):
        self.request.settimeout(None)
        if not self.checkAuthentication():
            return self.requestAuthentication()
        
        request = self.path.replace(self.server.context, "/").split('?')
        relativePath = request[0]
        if relativePath[0] == "/":
            relativePath = relativePath[1:]
            
        if relativePath == "webiopi" or relativePath == "webiopi/":
            self.send_response(301)
            self.send_header("Location", "/")
            self.end_headers()
            return

        params = {}
        if len(request) > 1:
            for s in request[1].split('&'):
                if s.find('=') > 0:
                    (name, value) = s.split('=')
                    params[name] = value
                else:
                    params[s] = None
        
        compact = False
        if 'compact' in params:
            compact = str2bool(params['compact'])

        try:
            result = (None, None, None)
            if self.command == "GET":
                result = self.server.handler.do_GET(relativePath, compact)
            elif self.command == "POST":
                length = 0
                length_header = 'content-length'
                if length_header in self.headers:
                    length = int(self.headers[length_header])
                result = self.server.handler.do_POST(relativePath, self.rfile.read(length), compact)
            else:
                result = (405, None, None)
                
            (code, body, type) = result
            
            if code > 0:
                self.sendResponse(code, body, type)
            else:
                if self.command == "GET":
                    self.serveFile(relativePath)
                else:
                    self.sendResponse(404)

        except (GPIO.InvalidDirectionException, GPIO.InvalidChannelException, GPIO.SetupException) as e:
            self.sendResponse(403, "%s" % e)
        except ValueError as e:
            self.sendResponse(403, "%s" % e)
        except Exception as e:
            self.sendResponse(500)
            raise e
            
    def do_GET(self):
        self.processRequest()

    def do_POST(self):
        self.processRequest()
1)self.server is not defined anywhere. Anyone know where's defined?
2)what's that piece of code does?

Code: Select all

 for s in request[1].split('&'):
                if s.find('=') > 0:
                    (name, value) = s.split('=')
                    params[name] = value
3)what this? compact = str2bool(params['compact'])
4)what's self.server.context is ?

User avatar
elParaguayo
Posts: 1943
Joined: Wed May 16, 2012 12:46 pm
Location: London, UK

Re: http.py from webIOPi

Sat Mar 08, 2014 7:36 am

I can answer 2 and 3.

2 Looks takes the query string from the web page address and turns it into a dictionary object called params.

3 Looks for a specific key in the dictionary called "compact" and then turns the string value into a python Boolean.

As for 1, my guess is that it will be defined in BaseHTTPServer.HTTPServer but that's really just a guess as I've never used that module before.
RPi Information Screen: plugin based system for displaying weather, travel information, football scores etc.

Return to “Python”