#!/usr/bin/env python3
#call: python3 BPsCheck1_server.py  #allows cookies, localStorage and ServerStorageObj from
# pages like http://localhost:8000/TD1/FamilyName_GivenName_12345_TD1.html  
''' plain python3 -m http.server
      does not send Cross-Origin-Opener-Policy or Cross-Origin-Embedder-Policy
      since it is a minimal handler (http.server.SimpleHTTPRequestHandler) that
      only sets basic headers like Content-type/Content-length/Last-Modified.
      Without both COOP and COEP on the top-level document, the page is not
      "cross-origin isolated," and SharedArrayBuffer stays undefined, so the
      Atomics-based approach cannot work there either.
     Here is a lightweight fix: a subclass of that same handler and two headers:
'''
import http.server, socketserver, json, os, urllib.parse

sDocRoot= os.path.join(os.path.dirname(os.path.abspath(__file__))) #HtmlAndCss/
  #so http://localhost:8000/TD1/FamilyName_GivenName_12345_TD1.html  //no HtmlAndCss
sStorageFile= os.path.join(sDocRoot, ".BPsCheck1_server_storage.json")

def loadAllStorage ():
    try:
        with open(sStorageFile,'r',encoding='utf-8') as f: return json.load(f)
    except Exception: return {}

def oAllStorage_save (oAllSt0):
    with open(sStorageFile,'w',encoding='utf-8') as f:
        json.dump(oAllSt0,f,indent=1)

class CoiHandler (http.server.SimpleHTTPRequestHandler):
    def __init__ (self, *args, **kwargs):
        super().__init__(*args, directory=sDocRoot, **kwargs)

    #"end_headers" is predefined (so cannot be renamed) and the parameter "self" will be
    def end_headers (self):                                    # added to the call
        #COEP "require-corp" blocks the remote BPsCheck1_*.js loaded
        #    by the srcdoc iframe (phmartin.info sends no CORP header);
        #    COOP/COEP were only needed for the abandoned Atomics approach
        #  self.send_header("Cross-Origin-Opener-Policy","same-origin")
        #  self.send_header("Cross-Origin-Embedder-Policy","require-corp")
        #  no: #last line replaced by:
        #      self.send_header("Cross-Origin-Embedder-Policy","credentialless")
        #      #credentialless: cross-origin no-cors scripts (the remote BPsCheck1_*.js)
        #      #  need no CORP header; COOP kept unchanged; Firefox support for
        #      #  credentialless is unverified

        super().end_headers()
        #With this function, the .htaccess and mod_headers from 2.2 are not needed

    def do_GET (self):
        oUrl= urllib.parse.urlparse(self.path)
        if oUrl.path=="/storage/ping":
            self.send_response(200);  self.end_headers();  return
        elif oUrl.path=="/storage/get":
            oQ= urllib.parse.parse_qs(oUrl.query)
            sBaseName= oQ.get("file",[""])[0];  sKey= oQ.get("key",[""])[0]
            oAllSt= loadAllStorage();  sValue= oAllSt.get(sBaseName,{}).get(sKey)
            if sValue is None: self.send_response(404);  self.end_headers();  return
            self.send_response(200);  self.send_header("Content-Type","text/plain")
            self.end_headers();  self.wfile.write(sValue.encode('utf-8'));  return
        elif oUrl.path=="/storage/getAll":
            oQ= urllib.parse.parse_qs(oUrl.query);  sBaseName= oQ.get("file",[""])[0]
            oAllSt= loadAllStorage();  self.send_response(200)
            self.send_header("Content-Type","application/json");  self.end_headers()
            self.wfile.write(json.dumps(oAllSt.get(sBaseName,{})).encode('utf-8'))
            return
#        else if oUrl.path=="/storage/getAllWithNames":
#            oQ= urllib.parse.parse_qs(oUrl.query);  sBaseName= oQ.get("file",[""])[0]
#            oAllSt= loadAllStorage();  oFileSt= oAllSt.get(sBaseName,{})
#            aSNameValue= [sKey+": "+str(sVal) for sKey,sVal in oFileSt.items()]
#            self.send_response(200)
#            self.send_header("Content-Type","application/json");  self.end_headers()
#            self.wfile.write(json.dumps(aSNameValue).encode('utf-8'))
#            return
        super().do_GET()

    def do_POST (self):
        oUrl= urllib.parse.urlparse(self.path);  oQ= urllib.parse.parse_qs(oUrl.query)
        sBaseName= oQ.get("file",[""])[0];  sKey= oQ.get("key",[""])[0]
        nLen= int(self.headers.get('Content-Length',0))
        sBody= self.rfile.read(nLen).decode('utf-8') if nLen else ""
        oAllSt= loadAllStorage();  oAllSt.setdefault(sBaseName,{})
        if oUrl.path=="/storage/set":
            oAllSt[sBaseName][sKey]= sBody;    oAllStorage_save(oAllSt)
            self.send_response(200);  self.end_headers();  return
        elif oUrl.path=="/storage/del":
            oAllSt[sBaseName].pop(sKey,None);  oAllStorage_save(oAllSt)
            self.send_response(200); self.end_headers();  return
        self.send_response(404);  self.end_headers()

if __name__=="__main__":
    with socketserver.TCPServer(("",8000),CoiHandler) as oServer:
        print("Serving "+sDocRoot+" on http://localhost:8000/")
        oServer.serve_forever()  #orig,above: " with COOP/COEP on"
