Force reload on SimpleHTTP Server in Python - python

I have a very simple HTTPServer implemented in Python. The code is the following:
import SimpleHTTPServer
import SocketServer as socketserver
import os
import threading
class MyHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
path_to_image = 'RGBWebcam1.png'
img = open(path_to_image, 'rb')
statinfo = os.stat(path_to_image)
img_size = statinfo.st_size
print(img_size)
def do_HEAD(self):
self.send_response(200)
self.send_header("Content-type", "image/png")
self.send_header("Content-length", img_size)
self.end_headers()
def do_GET(self):
self.send_response(200)
self.send_header("Content-type", "image/png")
self.send_header("Content-length", img_size)
self.end_headers()
f = open(path_to_image, 'rb')
self.wfile.write(f.read())
f.close()
class MyServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
def __init__(self, server_adress, RequestHandlerClass):
self.allow_reuse_address = True
socketserver.TCPServer.__init__(self, server_adress, RequestHandlerClass, False)
if __name__ == "__main__":
HOST, PORT = "192.168.2.10", 9999
server = MyServer((HOST, PORT), MyHandler)
server.server_bind()
server.server_activate()
server_thread = threading.Thread(target=server.serve_forever)
server_thread.start()
while(1):
print "test"
If I connect to the given IP-Adress the page loads and everything is fine. Now it would be nice if the page would automatically refresh every n seconds.
I am very new to python and especially new to webcoding. I have found LiveReload however I cannot get my head around how I merge these two libraries together.
Thank you for your help

You'll require a connection to the client if you want the server to tell it to refresh. A HTTP server means you've sent information (HTML) and the client will process it. There is no communication beyond that. That would require AJAX or Websockets to be implemented - both protocols that allow frequent communication.
Since you can't communicate, you should automate the refresh in the content you initially send. In our example we'll say we want the page to refresh every 30 seconds. This is possible to do in either HTML or Javascript:
<meta http-equiv="refresh" content="30" />
or
setTimeout(function(){
window.location.reload(1);
}, 30000);

Related

Python HTTPServer and periodic tasks

I´m using HTTPServer to listen for incoming POST requests and serving them. All is working fine with that.
I need to add some periodic tasks in the script (every X seconds: do something). As the HTTP server takes full command after
def run(server_class=HTTPServer, handler_class=S, port=9999):
server_address = (ethernetIP, port)
httpd = server_class(server_address, handler_class)
httpd.serve_forever()
I guess if there´s any way to include a check for time.time() as part of:
class S(BaseHTTPRequestHandler):
def _set_response(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
def do_GET(self):
self._set_response()
self.wfile.write("GET request for {}".format(self.path).encode('utf-8'))
def do_POST(self):
# my stuff here
Any ideas are welcome. Thanks!
Thanks to #rdas for pointing me to the separate thread solution. I tried schedule but it didn´t work with the HTTP server, because I can´t tell the script to run the pending jobs.
I tried with threading, running my periodic task as deamon.. and it worked! Here´s the code structure:
import time
import threading
from http.server import BaseHTTPRequestHandler, HTTPServer
polTime = 60 # how often we touch the file
polFile = "myfile.abc"
# this is the deamon thread
def polUpdate():
while True:
thisSecond = int(time.time())
if thisSecond % polTime == 0: # every X seconds
f = open(polFile,"w")
f.close() # touch and close
time.sleep(1) # avoid loopbacks
return "should never come this way"
# here´s the http server starter
def run(server_class=HTTPServer, handler_class=S, port=9999):
server_address = (ethernetIP, port)
httpd = server_class(server_address, handler_class)
try:
httpd.serve_forever()
except KeyboardInterrupt:
pass
httpd.server_close()
sys.exit(1)
# init the thread as deamon
d = threading.Thread(target=polUpdate, name='Daemon')
d.setDaemon(True)
d.start()
# runs the HTTP server
run(port=conf_port)
The HTTP server doesn´t block the thread, so it works great.
By the way, I´m using the file 'touching' as proof of life for the process.

Web server in python in plainText

I am looking for a way to expose a text file with Python web server.
I get some python code to run a web server :
import http.server
import socketserver
port = 9500
address = ("", port)
handler = http.server.SimpleHTTPRequestHandler
httpd = socketserver.TCPServer(address, handler)
print(f"Serveur démarré sur le PORT {port}")
httpd.serve_forever()
It's working fine. but i would :
Run a web sever exposing textplain content (and not Html content).
Set manually the workpath and name of index file (default: index.html)
keep Python server Code simple and light
I found some help on the web :
handler.extensions_map['Content-type'] = 'text/plain'
or
handler.send_header('Content-Type','text/plain')
But none os this proposition work.
Could you help me to build a simple python code to do this ?
Thanks a lot,
Script for Python 2 with using only built-in modules, just place the absolute path of the file which you want to be served <INSERT_FILE>:
#!/usr/bin/python
from SimpleHTTPServer import SimpleHTTPRequestHandler
import BaseHTTPServer
from io import StringIO
import sys
import os
class MyHandler(SimpleHTTPRequestHandler):
def send_head(self):
# Place here the absolute path of the file
with open("<INSERT_FILE>", "r") as f:
body = unicode("".join( f.readlines()))
self.send_response(200)
self.send_header("Content-type", "text/html; charset=UTF-8")
self.send_header("Content-Length", str(len(body)))
#self.send_header("Server", "SimpleHTTP/1.1 Python/2.7.5")
self.end_headers()
# text I/O binary, and raw I/O binary
# initial value must be unicode or None
return StringIO(body)
if __name__ == "__main__":
HandlerClass = MyHandler
ServerClass = BaseHTTPServer.HTTPServer
Protocol = "HTTP/1.1"
server_address = ('', 5555)
HandlerClass.protocol_version = Protocol
httpd = ServerClass (server_address, HandlerClass)
print("serving on port 5555")
httpd.serve_forever()
For python3 (SimpleHTTPServer module has been merged into http.server), place absolute path <INSERT_FILE>:
from http.server import HTTPServer, BaseHTTPRequestHandler
class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.end_headers()
# place absolute path here
f_served = open('<INSERT_FILE>','rb')
f_content = f_served.read()
f_served.close()
self.wfile.write(f_content)
if __name__ == "__main__":
httpd = HTTPServer(('localhost', 5555), SimpleHTTPRequestHandler)
httpd.serve_forever()
I recommend using aiohttp with its lowlevel server, which is described here:
You can either return plain text, or you change the content type of your web.Response to text/html to send data that will be interpreted as html.
You can just replace the "OK" in the text="OK" with whatever plain text you wish. Or you replace it with the content of your *.html and change the content_type.
import asyncio
from aiohttp import web
async def handler(request):
return web.Response(text="OK")
async def main():
server = web.Server(handler)
runner = web.ServerRunner(server)
await runner.setup()
site = web.TCPSite(runner, 'localhost', 8080)
await site.start()
print("======= Serving on http://127.0.0.1:8080/ ======")
# pause here for very long time by serving HTTP requests and
# waiting for keyboard interruption
await asyncio.sleep(100*3600)
loop = asyncio.get_event_loop()
try:
loop.run_until_complete(main())
except KeyboardInterrupt:
pass
loop.close()

Python HTTP server keep-alive

How can I keep my Python HTTP server connected(streaming) to my browser in real time?
(Update image to infinity) Like raspberry pi's motion eye
class MyHttpRequestHandler(http.server.SimpleHTTPRequestHandler):
def _set_response(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.send_header("Connection", "keep-alive")
self.send_header("keep-alive", "timeout=999999, max=99999")
self.end_headers()
def do_GET(self):
#self.send_response(204)
#self.end_headers()
if self.path == '/':
self.path = 'abc.jpg'
return http.server.SimpleHTTPRequestHandler.do_GET(self)
# Create an object of the above class
handler_object = MyHttpRequestHandler
PORT = 8000
my_server = socketserver.TCPServer(("", PORT), handler_object)
# Star the server
my_server.serve_forever()
Just keep writing, as in:
while True:
self.wfile.write(b"data")
This however won't get you into eventstream / server sent events territory, without using helper external libraries, as far as I'm aware.
I came across the same issue, I then found by chance (after much debugging) that you need to send linebreaks (\r\n or \n\n) to have the packets sent:
import http.server
import time
class MyHttpRequestHandler(http.server.BaseHTTPRequestHandler):
value = 0
# One can also set protocol_version = 'HTTP/1.1' here
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.send_header("Connection", "keep-alive")
self.end_headers()
while True:
self.wfile.write(str(self.value).encode())
self.wfile.write(b'\r\n') # Or \n\n, necessary to flush
self.value += 1
time.sleep(1)
PORT = 8000
my_server = http.server.HTTPServer(("", PORT), MyHttpRequestHandler)
# Start the server
my_server.serve_forever()
This enables you to send Server-sent Events (SSE) or HTTP long poll, or even json/raw http streams with the http.server library.
As the comment in the code says, you can also set the protocol version to HTTP/1.1 to enable keepalive by default. If you do so, you will have to specify Content-Length for every sent packet, otherwise the connection will never be terminated.
It is probably best to combine this with a threaded server to allow concurrent connections, as well as maybe setting a keepalive on the socket itself.

Build a Simple HTTPServer inside Docker image with Python

I have a docker image running, but I have no access to management since they are given to us by an administrator.
I want to run a simple HTTP-Server from a Python script. The script is the following:
import SimpleHTTPServer
import SocketServer as socketserver
import os
import threading
class MyHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
path_to_image = 'RGBWebcam1.png'
img = open(path_to_image, 'rb')
statinfo = os.stat(path_to_image)
img_size = statinfo.st_size
print(img_size)
def do_HEAD(self):
self.send_response(200)
self.send_header("Content-type", "image/png")
self.send_header("Content-length", img_size)
self.end_headers()
def do_GET(self):
self.send_response(200)
self.send_header("Content-type", "image/png")
self.send_header("Content-length", img_size)
self.end_headers()
f = open(path_to_image, 'rb')
self.wfile.write(f.read())
f.close()
class MyServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
def __init__(self, server_adress, RequestHandlerClass):
self.allow_reuse_address = True
socketserver.TCPServer.__init__(self, server_adress, RequestHandlerClass, False)
if __name__ == "__main__":
HOST, PORT = "172.17.0.2", 9999
server = MyServer((HOST, PORT), MyHandler)
server.server_bind()
server.server_activate()
server_thread = threading.Thread(target=server.serve_forever)
server_thread.start()
while(1):
print "test"
I looked up the IP-Adress with ifconfig however it is a different adress like the one I use when connecting to the Docker Image (it is a 141.19 ... address). So now if I try to reach the page it is not available on neither one of the adresses. Is there any way to route it to the 'real' IP-Address ?

Python basehttpserver not serving requests properly

I'm trying to write down a simple local proxy for javascript: since I need to load some stuff from javascript within a web page, I wrote this simple daemon in python:
import string,cgi,time
from os import curdir, sep
import urllib
import urllib2
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
class MyHandler(BaseHTTPRequestHandler):
def fetchurl(self, url, post, useragent, cookies):
headers={"User-Agent":useragent, "Cookie":cookies}
url=urllib.quote_plus(url, ":/?.&-=")
if post:
req = urllib2.Request(url,post,headers)
else:
req=urllib2.Request(url, None, headers)
try:
response=urllib2.urlopen(req)
except urllib2.URLError, e:
print "URLERROR: "+str(e)
return False
except urllib2.HTTPError, e:
print "HTTPERROR: "+str(e)
return False
else:
return response.read()
def do_GET(self):
if self.path != "/":
[callback, url, post, useragent, cookies]=self.path[1:].split("%7C")
print "callback = "+callback
print "url = "+url
print "post = "+post
print "useragent = "+useragent
print "cookies = "+cookies
if useragent=="":
useragent="pyjproxy v. 1.0"
load=self.fetchurl(url, post, useragent, cookies)
pack=load.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n").replace("\r", "\\r").replace("\t", "\\t").replace(" </script>", "</scr\"+\"ipt>")
response=callback+"(\""+pack+"\");"
if load:
self.send_response(200)
self.send_header('Content-type', 'text/javascript')
self.end_headers()
self.wfile.write(response)
self.wfile.close()
return
else:
self.send_error(404,'File Not Found: %s' % self.path)
return
else:
embedscript="function pyjload(datadict){ if(!datadict[\"url\"] || !datadict[\"callback\"]){return false;} if(!datadict[\"post\"]) datadict[\"post\"]=\"\"; if(!datadict[\"useragent\"]) datadict[\"useragent\"]=\"\"; if(!datadict[\"cookies\"]) datadict[\"cookies\"]=\"\"; var oHead = document.getElementsByTagName('head').item(0); var oScript= document.createElement(\"script\"); oScript.type = \"text/javascript\"; oScript.src=\"http://localhost:1180/\"+datadict[\"callback\"]+\"%7C\"+datadict[\"url\"]+\"%7C\"+datadict[\"post\"]+\"%7C\"+datadict[\"useragent\"]+\"%7C\"+datadict[\"cookies\"]; oHead.appendChild( oScript);}"
self.send_response(200)
self.send_header("Content-type", "text/html")
self.end_headers()
self.wfile.write(embedscript)
self.wfile.close()
return
def main():
try:
server = HTTPServer(('127.0.0.1', 1180), MyHandler)
print 'started httpserver...'
server.serve_forever()
except KeyboardInterrupt:
print '^C received, shutting down server'
server.socket.close()
if __name__ == '__main__':
main()
And I use within a web page like this one:
<!DOCTYPE HTML>
<html><head>
<script>
function miocallback(htmlsource)
{
alert(htmlsource);
}
</script>
<script type="text/javascript" src="http://localhost:1180"></script>
</head><body>
<a onclick="pyjload({'url':'http://www.google.it','callback':'miocallback'});"> Take the Red Pill</a>
</body></html>
Now, on Firefox and Chrome looks like it works always. On Opera and Internet Explorer, however, I noticed that sometimes it doesn't work, or it hangs for a lot of time... what's up, I wonder? Did I misdo something?
Thank for any help!
Matteo
You have to understand that (modern) browsers try to optimize their browsing speed using different techniques, which is why you get different results on different browsers.
In your case, the technique that caused you trouble is concurrent HTTP/1.1 session setup: in order to utilize your bandwidth better, your browser is able to start several HTTP/1.1 sessions at the same time. This allows to retrieve multiple resources (e.g. images) simultaneously.
However, BaseHTTPServer is not threaded: as soon as your browser tries to open another connection, it will fail to do so because BaseHTTPServer is already blocked by the first session that's still open. The request will never reach the server and run into a timeout. This also means that only one user can access your service at a given time. Inconvenient? Aye, but help is here:
Threads! .. and python makes this one rather easy:
Derive a new class from HTTPServer using a MixIn from socketserver.
.
Example:
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
from SocketServer import ThreadingMixIn
import threading
class Handler(BaseHTTPRequestHandler):
def do_HEAD(self):
pass
def do_GET(self):
pass
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
""" This class allows to handle requests in separated threads.
No further content needed, don't touch this. """
if __name__ == '__main__':
server = ThreadedHTTPServer(('localhost', 80), Handler)
print 'Starting server on port 80...'
server.serve_forever()
From now on, BaseHTTPServer is threaded and ready to serve multiple connections ( and therefore requests ) at the same time which will solve your problem.
Instead of the ThreadingMixIn, you can also use the ForkingMixIn in order to spawn another process instead of another thread.
all the best,
creo
Note that Python basehttpserver is a very basic HTTP server far to be perfect, but that's not your first issue.
What is happening if you put the two scripts at the end of the document just before the </body> tag? Does it help?

Categories

Resources