How to execute python script on the BaseHTTPSERVER created by python? - 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

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.

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

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.

Django/Python http.server access 404s via proxy, works locally

I've previously had the issue that I couldn't pinpoint the culprit in my Django app, causing all requests to 404. See the previous Stackoverflow question.
Since then I've tried to narrow down the issue and therefore started a new, VERY basic, Django app.
All the project consists of is:
$ django-admin startproject tempor
I've added the test directory and imported the test function
$ vi tempor/tempor/urls.py
from django.conf.urls import url
from django.contrib import admin
from tempor.views import test
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^test/$', test),
]
The views.py and the test function
$ vi tempor/tempor/views.py
from django.http import HttpResponse
def test(request):
return HttpResponse("OKAY")
Then I migrated the project - as suggested by Django:
$ python manage.py check
$ python manage.py migrate
Now I run the server:
$ python3 manage.py runserver 0.0.0.0:8282
Access from the server locally:
$ curl localhost:8282/test/
OKAY
$ curl <server-public-IP>:8282/test/
OKAY
Access from an external system (via proxy)
$ curl <server-public-IP>:8282/test/
<!DOCTYPE html>
<html lang="en">
[...]
<h1>Page not found <span>(404)</span></h1>
[...]
</html>
In the settings.py I have:
ALLOWED_HOSTS = ['*']
If I don't use '*', the external system is informed accordingly, as debugging is on:
$ curl <server-public-IP>:8282/test/
[...]
DisallowedHost at http://<server-public-IP>:8282/test/
[...]
This also occurs, if I try the same with a simple Python HTTP server - which the Django admin.py basically uses.
echo "OKAY" > /tmp/test/index.html
cd /tmp/test/
python -m http.server 8282
[...]
Local access:
$ curl localhost:8282/index.html
OKAY
$ curl <server-public-IP>:8282/index.html
OKAY
Remote access:
$ curl <server-public-IP>:8282/index.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
[...]
<p>Error code explanation: HTTPStatus.NOT_FOUND - Nothing matches the given URI.</p>
[...]
</html>
http.server log:
Serving HTTP on 0.0.0.0 port 8282 ...
<server-public-ip> - - [<timestamp>] "GET /index.html HTTP/1.1" 200 -
<proxy-ip> - - [<timestamp>] code 404, message File not found
<proxy-ip> - - [<timestamp>] "GET http://<server-public-ip>:8282/index.html HTTP/1.1" 404 -
For the moment, the proxy is a simple SSH port forwarding - which will later be replaces by an NGINX.
edit: The very same applies if I run uwsgi for the Django app:
$ uwsgi --http :8282 --module tempor.wsgi
Local accesses work - external requests 404.
Why do requests via a proxy 404 for me and how can I fix this issue?
Solved, but I don't understand why.
The issue was the direct access to the Python server using SSH port forwarding. An intermediate Nginx resolved the problem.
See my ServerFault question for further details.
For the server setup see the ServerFault question.
Client setup boils down to:
# SSH port forwarding, port 80 for Nginx access, port 8282 for direct Python webserver access
ssh -L 8181:<farawayhost-ip>:<80 or 8282> <sshuser>#<remotehost-ip>
# on a second terminal
export http_proxy=127.0.0.1:8181
curl <farawayhost-ip>

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

Serving Python scripts with CGIHTTPServer on Mac OS X

I'm trying to set up Python's CGIHTTPServer on Mac OS X to be able to serve CGI scripts locally, but I seem to be unable to do this.
I've got a simple test script:
#!/usr/bin/env python
import cgi
cgi.test()
It has permissions -rwxr-xr-x# and is located in ~/WWW (with permissions drwxr-xr-x). It runs just fine from the shell and I have this script to serve them using CGIHTTPServer:
import CGIHTTPServer
import BaseHTTPServer
class Handler(CGIHTTPServer.CGIHTTPRequestHandler):
cgi_directories = ["~/WWW"]
PORT = 8000
httpd = BaseHTTPServer.HTTPServer(("", PORT), Handler)
print "serving at port", PORT
But when I run it, going to localhost:8000 just serves the content of the script, not the result (i.e. it gives back the code, not the output).
What am I doing wrong?
The paths in cgi_directories are matched against the path part of the URL, not the actual filesystem path. Setting it to ["/"] or [""] will probably work better.

Categories