How do you execute a server-side python script using http.server? - python

I have a collection of python scripts, that I would like to be able to execute with a button press, from a web browser.
Currently, I run python -m http.server 8000 to start a server on port 8000. It serves up html pages well, but that's about all it does. Is it possible to have it execute a python script (via ajax) and return the output, instead of just returning the full text of the .py file.
Additionally, if not, is there a simple (as in only 1 or 2 files) way to make this work? I'm looking for the equivalent of PHP -s, but for python.
For completeness, this is my html
<h1>Hello World</h1>
<button>
Click me!
</button>
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.3.1.js"> </script>
<script>
$('button').click(function(){
$.get('/gui/run_bash.py');
});
</script>

Add --cgi to your command line.
python -m http.server --cgi 8000
Then place your python scripts in ./cgi-bin and mark them as executable.
$ mkdir cgi-bin
$ cp hello.py cgi-bin/hello.py
$ chmod +x cgi-bin/hello.py
You may need to slightly modify your python scripts to support the CGI protocol.
Here is the server running:
$ cat cgi-bin/hello.py
#! /usr/bin/env python3
print("Content-Type: application/json")
print()
print('{"hello": "world"}')
radams#wombat:/tmp/z/h$ python -m http.server --cgi
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
127.0.0.1 - - [20/Mar/2018 18:04:16] "GET /cgi-bin/hello.py HTTP/1.1" 200 -
Reference: https://docs.python.org/3/library/http.server.html#http.server.CGIHTTPRequestHandler

http.server merely serves static files, it does not do any serverside processing or execute any code when you hit a python file. If you want to run some python code, you'll have to write an application to do that. Flask is a Python web framework that is probably well-suited to this task.
Your flask application might look something like this for executing scripts...
import subprocess
from flask import Flask
app = Flask(__name__)
SCRIPTS_ROOT = '/path/to/script_dir'
#app.route('/run/<script_name>')
def run_script(script_name):
fp = os.path.join(SCRIPTS_ROOT, script_name)
try:
output = subprocess.check_output(['python', fp])
except subprocess.CalledProcessError as call:
output = call.output # if exit code was non-zero
return output.encode('utf-8') # or your system encoding
if __name__ == '__main__':
app.run(host='127.0.0.1', port=8000)
And of course, I should include an obligatory warning 'having a webserver execute commands like this is insecure', etc, etc. Check out the Flask quickstart for more details.

Related

Python runs on terminal, not on web browser

I'm trying to run a simple python script on my webserver, but it's not showing up in the web browser.
In terminal I check if python is installed:
whereis python
python: /usr/bin/python2.7 /usr/bin/python2.7-config /usr/bin/python /usr/lib/python2.7 /usr/lib64/python2.7 /etc/python /usr/local/bin/python3.9-config /usr/local/bin/python3.9 /usr/local/lib/python3.9 /usr/include/python2.7 /opt/imh-python/bin/python2.7 /opt/imh-python/bin/python2.7-config /opt/imh-python/bin/python3.9 /opt/imh-python/bin/python /usr/share/man/man1/python.1.gz
This tells me that I have python installed. I created a simple file that contains this code:
#! /usr/bin/python
print('Content-Type: text/html\r\n\r\n')
print('\r\n')
print('Hello World')
I ran dos2unix and chmod a+x on the file.
I ran the file in terminal and get this output:
Content-Type: text/html
Hello World
When I try to open the file in the web browser this is the output I get:
#! /usr/bin/python
print('Content-Type: text/html\r\n\r\n')
print('\r\n')
print('Hello World')
I changed the single quotes in the print statement to double. I tried different ways of entering new lines, but nothing seems to work. Am I missing or overlooking something crucial here?
The browser doesn't have a Python interpreter. So opening the file in a browser is just going to show your source code. If you want it to show on a browser you need to run it on a server where it can be interpreted. A simple solution is to use Flask, which comes with a development server. Once you've installed flask:
from flask import Flask
app = Flask(__name__)
#app.route('/')
def hello():
return 'Hello World'
app.run()
Then navigate to http://localhost:5000 in your browser.

Python Local Server For Callback URL

I am working on an oauth project that requires me to have a callback url that can be loaded upon successful authorization in order to request access tokens, but I'm not sure how I can run that server in the proper manner. I am familiar with the useful one-line python server setup python -m http.server, but this will just load the directory in which I started the server and act as a server for navigating the files within that directory.
Is there a preferred way to set up a simple server that can be used for this redirect process and make the additional server call I need? Would I need to use a web framework like Django?
Using python -m http.server you can serve only static files but you need to run some code which gets argument(s) and uses it.
You could use option --cgi in python -m http.server --cgi and then you could put script (in any language) in folder cgi-bin and run it http://localhost/cgi-bin/script.py.
But method with CGI is very old and it can be much easier to use some of web microframework like Flask or bottle
script.py
from flask import Flask, request
app = Flask(__name__)
#app.route('/')
def index():
print('args:', request.args) # display text in console
#print('form:', request.form)
#print('data:', request.data)
#print('json:', request.json)
#print('files:', request.files)
return request.args.get('data', 'none') # send text to web browser
if __name__ == '__main__':
app.run(port=80, debug=True)
And run it as python script.py and test in web browser
http://127.0.0.1/?data=qwerty
And request.args.get("data") should gives you qwerty which you can use in Python code.

Run python files through browser on localhost [duplicate]

When I run python -m SimpleHTTPServer 8000 or python -m CGIHTTPServer 8000 in my shell I am hosting the content of my current directory to the internet.
I would like to make the following cgi_script.py work correctly using the above command in the command line when I browse to 192.xxx.x.xx:8000/cgi_script.py
#!/usr/bin/env python
print "Content-Type: text/html"
print
print """\
<html>
<body>
<h2>Hello World!</h2>
</body>
</html>
"""
But this script is displayed literally and not only the "Hello World!" part.
Btw I changed the file permissions to 755 for cgi_script.py as well as the folder I am hosting it from.
Try with python -m CGIHTTPServer 8000.
Note that you have to move the script to a cgi-bin or htbin directory in order to be runnable.
SO doesn't allow me to comment so I'm adding this as a separate answer, addition to rodrigo's.
You can use another parameter cgi_directories which defaults to ['/cgi-bin', '/htbin']. More info here
In Python3 the command line is simply
python3 -m http.server --cgi 8000
When I ran into this issue I found that depending on which directory you are in when you run the python -m CGIHTTPServer 8000 command yields different results. When attempting to run the command while in the cgi-bin directory the browser continued to return the raw script code. once I cd'ed one level higher and ran the python -m CGIHTTPServer 8000 command again my script began executing.
#Bentley4 -ifyou are still not able to do,
try importing cgi.
#!C:\Python34\python.exe -u
import cgi
print ("Content-type:text/html")
HTH
This work for me, run the python -m CGIHTTPServer 8000 command same menu level with cgi-bin,and move cgi_script.py into cgi-bin folder.In browser type http://localhost:8000/cgi-bin/cgi_script.py

How to execute python script on the BaseHTTPSERVER created by python?

I have simply created a python server with :
python -m SimpleHTTPServer
I had a .htaccess (I don't know if it is usefull with python server)
with:
AddHandler cgi-script .py
Options +ExecCGI
Now I am writing a simple python script :
#!/usr/bin/python
import cgitb
cgitb.enable()
print 'Content-type: text/html'
print '''
<html>
<head>
<title>My website</title>
</head>
<body>
<p>Here I am</p>
</body>
</html>
'''
I make test.py (name of my script) an executed file with:
chmod +x test.py
I am launching in firefox with this addres: (http : //) 0.0.0.0:8000/test.py
Problem, the script is not executed... I see the code in the web page...
And server error is:
localhost - - [25/Oct/2012 10:47:12] "GET / HTTP/1.1" 200 -
localhost - - [25/Oct/2012 10:47:13] code 404, message File not found
localhost - - [25/Oct/2012 10:47:13] "GET /favicon.ico HTTP/1.1" 404 -
How can I manage the execution of python code simply? Is it possible to write in a python server to execute the python script like with something like that:
import BaseHTTPServer
import CGIHTTPServer
httpd = BaseHTTPServer.HTTPServer(\
('localhost', 8123), \
CGIHTTPServer.CGIHTTPRequestHandler)
###  here some code to say, hey please execute python script on the webserver... ;-)
httpd.serve_forever()
Or something else...
You are on the right track with CGIHTTPRequestHandler, as .htaccess files mean nothing to the the built-in http server. There is a CGIHTTPRequestHandler.cgi_directories variable that specifies the directories under which an executable file is considered a cgi script (here is the check itself). You should consider moving test.py to a cgi-bin or htbin directory and use the following script:
cgiserver.py:
#!/usr/bin/env python3
from http.server import CGIHTTPRequestHandler, HTTPServer
handler = CGIHTTPRequestHandler
handler.cgi_directories = ['/cgi-bin', '/htbin'] # this is the default
server = HTTPServer(('localhost', 8123), handler)
server.serve_forever()
cgi-bin/test.py:
#!/usr/bin/env python3
print('Content-type: text/html\n')
print('<title>Hello World</title>')
You should end up with:
|- cgiserver.py
|- cgi-bin/
` test.py
Run with python3 cgiserver.py and send requests to localhost:8123/cgi-bin/test.py. Cheers.
Have you tried using Flask? It's a lightweight server library that makes this really easy.
from flask import Flask
app = Flask(__name__)
#app.route('/')
def hello_world():
return '<title>Hello World</title>'
if __name__ == '__main__':
app.run(debug=True)
The return value, in this case <title>Hello World</title>, is rendered has HTML. You can also use HTML template files for more complex pages.
Here's a good, short, youtube tutorial that explains it better.
You can use a simpler approach and use the --cgi option launching the python3 version of http server:
python3 -m http.server --cgi
as pointed out by the command:
python3 -m http.server --help

Deploying CherryPy (daemon)

I've followed the basic CherryPy tutorial (http://www.cherrypy.org/wiki/CherryPyTutorial). One thing not discussed is deployment.
How can I launch a CherryPy app as a daemon and "forget about it"? What happens if the server reboots?
Is there a standard recipe? Maybe something that will create a service script (/etc/init.d/cherrypy...)
Thanks!
Daemonizer can be pretty simple to use:
# this works for cherrypy 3.1.2 on Ubuntu 10.04
from cherrypy.process.plugins import Daemonizer
# before mounting anything
Daemonizer(cherrypy.engine).subscribe()
cherrypy.tree.mount(MyDaemonApp, "/")
cherrypy.engine.start()
cherrypy.engine.block()
There is a decent HOWTO for SysV style here.
To summarize:
Create a file named for your application in /etc/init.d that calls /bin/sh
sudo vim /etc/init.d/MyDaemonApp
#!/bin/sh
echo "Invoking MyDaemonApp";
/path/to/MyDaemonApp
echo "Started MyDaemonApp. Tremble, Ye Mighty."
Make it executable
sudo chmod +x /etc/init.d/MyDaemonApp
Run update-rc.d to create our proper links in the proper runtime dir.
sudo update-rc.d MyDaemonApp defaults 80
sudo /etc/init.d/MyDaemonApp
There is a Daemonizer plugin for CherryPy included by default which is useful for getting it to start but by far the easiest way for simple cases is to use the cherryd script:
> cherryd -h
Usage: cherryd [options]
Options:
-h, --help show this help message and exit
-c CONFIG, --config=CONFIG
specify config file(s)
-d run the server as a daemon
-e ENVIRONMENT, --environment=ENVIRONMENT
apply the given config environment
-f start a fastcgi server instead of the default HTTP
server
-s start a scgi server instead of the default HTTP server
-i IMPORTS, --import=IMPORTS
specify modules to import
-p PIDFILE, --pidfile=PIDFILE
store the process id in the given file
As far as an init.d script goes I think there are examples that can be Googled.
And the cherryd is found in your:
virtualenv/lib/python2.7/site-packages/cherrypy/cherryd
or in: https://bitbucket.org/cherrypy/cherrypy/src/default/cherrypy/cherryd
I wrote a tutorial/project skeleton, cherrypy-webapp-skeleton, which goal was to fill the gaps for deploying a real-world CherryPy application on Debian* for a web-developer. It features extended cherryd for daemon privilege drop. There's also a number of important script and config files for init.d, nginx, monit, logrotate. The tutorial part describes how to put things together and eventually forget about it. The skeleton part proposes a way of possible arrangement of CherryPy webapp project assets.
* It was written for Squeeze but practically it should be same for Wheezy.
Info on Daemonizer options
When using Daemonizer, the docs don't state the options, e.g. how to redirect stdout or stderr. From the source of the Daemonizer class you can find the options. As a reference take this example from my project:
# run server as a daemon
d = Daemonizer(cherrypy.engine,
stdout='/home/pi/Gate/log/gate_access.log',
stderr='/home/pi/Gate/log/gate_error.log')
d.subscribe()

Categories