How to run Python CGI script - python

I have never setup a server (let alone a python server) before and i am a bit lost. How do i utilize the following code? I have tried to put in in the cgi bin directory but that didnt work. It returned an internal server error. have a look at this here
#!/usr/bin/env python
#
# Funf: Open Sensing Framework
# Copyright (C) 2010-2011 Nadav Aharony, Wei Pan, Alex Pentland.
# Acknowledgments: Alan Gardner
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from SocketServer import ThreadingMixIn
import sys
import cgi
import urlparse
import os.path
import shutil
import time
server_dir = os.path.dirname(__file__)
config_path = '/config'
config_file_path = os.path.join(server_dir, 'config.json')
upload_path = '/data'
upload_dir = os.path.join(server_dir, 'uploads')
def read_config():
config = None
try:
with open(config_file_path) as config_file:
config = config_file.read()
except IOError:
pass
return config
def backup_file(filepath):
shutil.move(filepath, filepath + '.' + str(int(time.time()*1000)) + '.bak')
def write_file(filename, file):
if not os.path.exists(upload_dir):
os.mkdir(upload_dir)
filepath = os.path.join(upload_dir, filename)
if os.path.exists(filepath):
backup_file(filepath)
with open(filepath, 'wb') as output_file:
while True:
chunk = file.read(1024)
if not chunk:
break
output_file.write(chunk)
class RequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
parsed_url = urlparse.urlparse(self.path)
if parsed_url.path == config_path:
config = read_config()
if config:
self.send_response(200)
self.end_headers()
self.wfile.write(config)
else:
self.send_error(500)
elif parsed_url.path == upload_path:
self.send_error(405)
else:
self.send_error(404)
def do_POST(self):
parsed_url = urlparse.urlparse(self.path)
path = parsed_url.path
ctype, pdict = cgi.parse_header(self.headers['Content-Type'])
if path == upload_path:
if ctype=='multipart/form-data':
form = cgi.FieldStorage(self.rfile, self.headers, environ={'REQUEST_METHOD':'POST'})
try:
fileitem = form["uploadedfile"]
if fileitem.file:
try:
write_file(fileitem.filename, fileitem.file)
except Exception as e:
print e
self.send_error(500)
else:
self.send_response(200)
self.end_headers()
self.wfile.write("OK")
return
except KeyError:
pass
# Bad request
self.send_error(400)
elif parsed_url.path == config_path:
self.send_error(405)
else:
self.send_error(404)
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
"""Handle requests in a separate thread."""
if __name__ == '__main__':
if sys.argv[1:]:
port = int(sys.argv[1])
else:
port = 8000
server_address = ('', port)
httpd = ThreadedHTTPServer(server_address, RequestHandler)
sa = httpd.socket.getsockname()
print "Serving HTTP on", sa[0], "port", sa[1], "..."
print 'use <Ctrl-C> to stop'
httpd.serve_forever()

If you want to run a CGI on something like Apache (as opposed via custom server code like you pasted above), you can create a .py file like this in a (.py) CGI-enabled directory.
#!/usr/bin/env python
print "Content-Type: text/html"
print
print 'Hello World'
If you're using Apache, here's some info on how to set up CGI executables.
edit: (As Adrien P. says, the Python script should be made executable.)

You do not have to place it into a cgi-bin directory.
If you are running windows, you can launch Idle from your start menu under the python entry. Paste the code in, and hit F5 to run the code.
If you are running *nix, look to Adrien's answer for the commands and copy what is output when you run ./your_script.py.
Are you attempting to program a website in Python? This is code to create a web server, not site, so navigating to the program in a web browser will yield no results.

$ chmod +x your_script.py
$ ./your_script.py
A quick look a your code: it launch a simple http server who listen on port 8000

Heroku is a good place to host and python scripts.
Pre-req
pythonscripts.py
procfile
requirements.txt
and After add, commit and push the scripts to heroku app. Just run the following command on terminal to run the scripts.
heroku run python your_scripts.py
More if you want to run this scripts on a schedule timing. then heroku provides lots of adds-on. just search it on heroku

Related

Getting error file not found when executing python server file

I'm getting file not found error on executing python server file. Python version is 3.7.5. To produce the same output copy the shared code and run on local system. Run the python file using python webserver.py in terminal then in browser type localhost:8080/hello to get error.
What I want is to dynamically render html output when url path matches with /hello. I'm not using additional files or any declarations in any other file in same directory. Code used in server file is as below:
from http.server import BaseHTTPRequestHandler,SimpleHTTPRequestHandler, HTTPServer
class webhandler(SimpleHTTPRequestHandler):
def do_Get(self):
try:
if self.path.endswith('/hello'):
self.send_response(200)
self.send_header('Content-type','text/html')
self.end_headers()
output = ''
output +=f"<html><body>Hello!</body></html>"
self.wfile.write(bytes(output,"utf8"))
return
except IOError:
self.send_error(404,"File not found %s" % self.path)
def main():
try:
port = 8080
server = HTTPServer(("",port),webhandler)
print("Web server running on port %s" % port)
server.serve_forever()
except KeyboardInterrupt:
print("^c entered Stopping webserver...")
server.socket.close()
if __name__=='__main__':
main()

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 BaseHTTPServer, how to redirect multiple hosts to ip/port?

I currently have the following code:
from BaseHTTPServer import BaseHTTPRequestHandler
from pathlib import Path
from random import randint
import json
import random
example = 'logs/example.json'
class GetHandler(BaseHTTPRequestHandler):
# Slurp data from file
def dummy_data(self):
json_result = Path(example)
if json_result.is_file():
return json.load(open(example))
# Return data or empty
def random_selection(self):
data = self.dummy_data()
try:
return random.sample(data, randint(1, len(data)+50))
# Purposefully introduce entropy
except ValueError:
return ''
def do_GET(self):
self.send_response(200)
self.send_header('Content-Type', 'application/json')
self.end_headers()
self.wfile.write(json.dumps(self.random_selection()))
return
if __name__ == '__main__':
from BaseHTTPServer import HTTPServer
server = HTTPServer(('localhost', 8080), GetHandler)
print 'Starting server at http://127.0.0.1:8080'
server.serve_forever()
I have patched /etc/hosts as follows:
server-0001 server-0002 server-0003 server-0004 127.0.0.1
I am looking for a way for servers 0001-4 to redirect to 127.0.0.1:8080 but am not seeing how? Is this something to do with /etc/resolv.conf? I am using OSX but hopefully any *nix solution should work I'm hoping (unless ipfw evidently, since we no longer have it like sane people).
Looks like the sanest answer was to patch /etc/hosts, then change port of BaseHTTPServer to 80. This does not solve the origional question but is a fair compromise.
Patching Script:
#!/bin/bash
# ensure running as root
if [ "$(id -u)" != "0" ] ; then
exec sudo "$0" "$#"
fi
if ! grep "^#- marker " /etc/hosts ; then
echo -e '\n##+ marker' >> /etc/hosts
while read server ; do
[ 'x' != "${server}x" ] && echo -e "127.0.0.1 ${server}.io www.${server}.io" >> /etc/hosts
done <read/servers.txt
echo -e '\n##- marker' >> /etc/hosts
fi
Modification to Python
....
def main():
try:
server = HTTPServer(('', 80), GetHandler)
print '->> Starting server at http://127.0.0.1:80 and all patched hosts'
server.serve_forever()
except KeyboardInterrupt:
print '->> Interrupt received; closing server socket'
server.socket.close()
if __name__ == '__main__':
main()

How to serve an mp3 file with built-in python http server

I am currently trying to serve MP3 Files using Python. The problem is that I can only play the MP3 once. Afterwards media controls stop responding and I need to reload entirely the page to be able to listen again to the MP3. (tested in Chrome)
Problem: running the script below, and entering http://127.0.0.1/test.mp3 on my browser will return an MP3 files which can be replayed only if I refresh the page
Notes:
Saving the page as HTML and loading it directly with Chrome (without Python server) would make the problem disappear.
Serving the file with Apache would solve the problem, but this is overkilled: I want to make the script very easy to use and not require installing Apache.
Here is the code I use:
import string
import os
import urllib
import socket
# Setup web server import string,cgi,time
import string,cgi,time
from os import curdir, sep
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import hashlib
class MyHandler(BaseHTTPRequestHandler):
def do_GET(self):
try:
# serve mp3 files
if self.path.endswith(".mp3"):
print curdir + sep + self.path
f = open(curdir + sep + self.path, 'rb')
st = os.fstat( f.fileno() )
length = st.st_size
data = f.read()
md5 = hashlib.md5()
md5.update(data)
md5_key = self.headers.getheader('If-None-Match')
if md5_key:
if md5_key[1:-1] == md5.hexdigest():
self.send_response(304)
self.send_header('ETag', '"{0}"'.format(md5.hexdigest()))
self.send_header('Keep-Alive', 'timeout=5, max=100')
self.end_headers()
return
self.send_response(200)
self.send_header('Content-type', 'audio/mpeg')
self.send_header('Content-Length', length )
self.send_header('ETag', '"{0}"'.format(md5.hexdigest()))
self.send_header('Accept-Ranges', 'bytes')
self.send_header('Last-Modified', time.strftime("%a %d %b %Y %H:%M:%S GMT",time.localtime(os.path.getmtime('test.mp3'))))
self.end_headers()
self.wfile.write(data)
f.close()
return
except IOError:
self.send_error(404,'File Not Found: %s' % self.path)
from SocketServer import ThreadingMixIn
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
pass
if __name__ == "__main__":
try:
server = ThreadedHTTPServer(('', 80), MyHandler)
print 'started httpserver...'
server.serve_forever()
except KeyboardInterrupt:
print '^C received, shutting down server'
server.socket.close()
BaseServer is single-threaded, you should use either ForkingMixIn or ThreadingMixIn to support multiple connections.
For example replace line:
server = HTTPServer(('', 80), MyHandler)
with
from SocketServer import ThreadingMixIn
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
pass
server = ThreadedHTTPServer(('', 80), MyHandler)
EDIT: I wrote much of this before I realized Mapadd only planned to use this in a lab. WSGI probably is not required for his use case.
If you are willing to run this as a wsgi app (which I would recommend over vanilla CGI for any real scalability), you can use the script I have included below.
I took the liberty of modifying your source... this works with the assumptions above.. btw, you should spend some time checking that your html is reasonably compliant... this will help ensure that you get better cross-browser compatibility... the original didn't have <head> or <body> tags... mine (below) is strictly prototype html, and could be improved.
To run this, you just run the python executable in your shell and surf to the ipaddress of the machine on 8080. If you were doing this for a production website, we should be using lighttpd or apache for serving files, but since this is simply for lab use, the embedded wsgi reference server should be fine. Substitute the WSGIServer line at the bottom of the file if you want to run in apache or lighttpd.
Save as mp3.py
from webob import Request
import re
import os
import sys
####
#### Run with:
#### twistd -n web --port 8080 --wsgi mp3.mp3_app
_MP3DIV = """<div id="musicHere"></div>"""
_MP3EMBED = """<embed src="mp3/" loop="true" autoplay="false" width="145" height="60"></embed>"""
_HTML = '''<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head></head><body> Hello %s %s</body></html> ''' % (_MP3DIV, _MP3EMBED)
def mp3_html(environ, start_response):
"""This function will be mounted on "/" and refer the browser to the mp3 serving URL."""
start_response('200 OK', [('Content-Type', 'text/html')])
return [_HTML]
def mp3_serve(environ, start_response):
"""Serve the MP3, one chunk at a time with a generator"""
file_path = "/file/path/to/test.mp3"
mimetype = "application/x-mplayer2"
size = os.path.getsize(file_path)
headers = [
("Content-type", mimetype),
("Content-length", str(size)),
]
start_response("200 OK", headers)
return send_file(file_path, size)
def send_file(file_path, size):
BLOCK_SIZE = 4096
fh = open(file_path, 'r')
while True:
block = fh.read(BLOCK_SIZE)
if not block:
fh.close()
break
yield block
def _not_found(environ,start_response):
"""Called if no URL matches."""
start_response('404 NOT FOUND', [('Content-Type', 'text/plain')])
return ['Not Found']
def mp3_app(environ,start_response):
"""
The main WSGI application. Dispatch the current request to
the functions andd store the regular expression
captures in the WSGI environment as `mp3app.url_args` so that
the functions from above can access the url placeholders.
If nothing matches call the `not_found` function.
"""
# map urls to functions
urls = [
(r'^$', mp3_html),
(r'mp3/?$', mp3_serve),
]
path = environ.get('PATH_INFO', '').lstrip('/')
for regex, callback in urls:
match = re.search(regex, path)
if match is not None:
# assign http environment variables...
environ['mp3app.url_args'] = match.groups()
return callback(environ, start_response)
return _not_found(environ, start_response)
Run from the bash shell with: twistd -n web --port 8080 --wsgi mp3.mp3_app from the directory where you saved mp3.py (or just put mp3.py somewhere in $PYTHONPATH).
Now surf to the external ip (i.e. http://some.ip.local:8080/) and it will serve the mp3 directly.
I tried running your original app as it was posted, and could not get it to source the mp3, it barked at me with an error in linux...

How to serve any file type with Python's BaseHTTPRequestHandler

Consider the following example:
import string,cgi,time
from os import curdir, sep
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
class MyHandler(BaseHTTPRequestHandler):
def do_GET(self):
try:
if self.path.endswith(".html"):
f = open(curdir + sep + self.path) #self.path has /test.html
#note that this potentially makes every file on your computer readable by the internet
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write(f.read())
f.close()
return
except IOError:
self.send_error(404,'File Not Found: %s' % self.path)
def main():
try:
server = HTTPServer(('', 80), MyHandler)
print 'started httpserver...'
server.serve_forever()
except KeyboardInterrupt:
print '^C received, shutting down server'
server.socket.close()
if __name__ == '__main__':
main()
What if I want to server a ZIP file also... how would I do that?
I don't think this line would work right?
self.wfile.write(f.read())
Pass binary as a parameter to open(). This:
f = open(curdir + sep + self.path, 'rb')
Instead of this:
f = open(curdir + sep + self.path)
UNIX doesn't distinguish between binary and text, but windows does. But if the script executes on UNIX, the "b" will just be ignored so you're safe.
Your line would work just fine. The problem would be setting the Content-type appropriately. You'd want to set it to application/zip instead of text/html.
If you want to share files in a folder of any type, then you can also try typing the command
python -m SimpleHTTPServer
This will start the server at port 8000 and you can browse the files (via directory listing)

Categories

Resources