CGI not executing python - 500 internal server error - python

I have a few python scripts that I'd like to execute and the following configuration:
Ubuntu 10.04, Apache2, Python 2.6, mod_python and mod_wsgi installed.
I've followed the instructions on the following sites:
http://bytes.com/topic/python/answers/474462-apache-python-ubuntu
http://apache.active-venture.com/cgi-configure.html
http://modpython.org/live/current/doc-html/inst-testing.html
http://code.google.com/p/modwsgi/wiki/QuickInstallationGuide
http://wiki.apache.org/httpd/DistrosDefaultLayout
The default file in sites-available :
<VirtualHost *:80>
ServerAdmin webmaster#localhost
DocumentRoot /var/www
<Directory />
Options FollowSymLinks
AllowOverride None
</Directory>
<Directory /var/www/>
Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
allow from all
</Directory>
ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
<Directory "/usr/lib/cgi-bin">
AddHandler mod_python .py
AddHandler cgi-script .cgi py
AllowOverride None
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
Order allow,deny
Allow from all
</Directory>
I'm getting the 500 internal server error.
I've also changed the permissions of the files to 755
The py files simply prints some text that should appear on the page.
What should I do?
Thanks
[edit]: Update, it's related to bugs in the py file
error log shown below.
Traceback (most recent call last):
File "/usr/lib/cgi-bin/amissa2.py", line 80, in <module>
zoom_factor = int(parms.getfirst('zoom')) * int(parms.getfirst('zsize'))
TypeError: int() argument must be a string or a number, not 'NoneType'
It appears to be an error in converting from None to int, over here:
zoom_factor = int(parms.getfirst('zoom')) * int(parms.getfirst('zsize'))
Any hint on how this can such a conversion be done?

If parms.getfirst('zoom') or parms.getfirst('zsize') return None, you are probably not providing these in your URL (? dunno what these parms are, just guessing). Define the behaviour you want when these are missing (will it mean a "0" zoom, or since you are multiplying, "1" makes more sense?).
Then create your own conversion function that knows how to translate a None to int (depending on your defined behaviour) and call it instead of int().
def convert(value):
if value is None:
return 0 # or 1, or whatever
else:
return int(value)

You're not loading the wsgi module.
LoadModule wsgi_module modules/mod_wsgi.so
Also, you need only mod_wsgi OR mod_python installed. Not both unless you have a specific need to do so.

Related

wordpress on apache2 running python as cgi

So here is what I want to do:
On my Raspi a python program is running. On a wordpress site the current state of the program should be displayed and some configurations should be changeable.
Here is the problem:
Whenever I want to execute the python script, I get a 500 error code. It doesn't matter if I just want to display the value or change it. I'm new to html, cgi and apache, tried a lot but now I have no clue how to continue. I'd appreciate it a lot if someone could point me in the right direction.
Here are my configurations:
Apache:
Edited the file /etc/apache2/apache2.conf:
<Directory /var/www/>
Options +ExecCGI +Indexes +FollowSymLinks
AddHandler cgi-script .cgi .py
AllowOverride None
Require all granted
</Directory>
<Directory "/var/www/cgi-bin">
AllowOverride None
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
Require all granted
</Directory>
<Directory "/var/www/cgi-bin">
Options All
</Directory>
I also ran sudo a2enmod cgi
The webserver directory (/var/www/) looks like this:
.
├── cgi-bin
└── html
├── pma
│   └── ...
└── wordpress
└── ...
Wordpress:
On a wordpress site, I go into the "text" mode and have the following html code:
Curent Value: <form action="/cgi-bin/apfautostartval.py" method="get"></form>
<form action="/cgi-bin/apfcgi.py" method="post" target="_blank">
<input name="autoTest" type="radio" value="True" /> True (do automatic scan)
<input name="autoTest" type="radio" value="False" /> False (do manual scan)
<input type="submit" value="Submit" /></form>
Python files:
The apfautostartval.py should just get the value from the config.ini and post it:
#!/usr/bin/python3
import configparser
import os
import cgi, cgitb
cgitb.enable()
# Create config parser
config = configparser.ConfigParser()
configFilePath = os.path.join(os.path.sep,"home","pi",..., "config.ini")
config.read(configFilePath)
print("Content-type: text/html")
print()
print("<!DOCTYPE html>")
print("<html>")
print("<body>")
print(str(config['SETTINGS']["autoTest"]))
print("</body>")
print("</html>")
And finally the apfcgi.py should receive the submitted new value and write it to the config.ini:
#!/usr/bin/python3
import configparser
import os
import cgi, cgitb
# Create instance of FieldStorage
form = cgi.FieldStorage()
cgitb.enable()
# Create config parser
config = configparser.ConfigParser()
configFilePath = os.path.join(os.path.sep,"home","pi",..., "config.ini")
print("Content-type: text/html")
print()
print("<!DOCTYPE html>")
print("<html>")
print("<body>")
# Receive autotest command from web site
if form.getvalue("autoTest"):
config.read(configFilePath)
if form.getvalue("autoTest").lower() == "true":
config['SETTINGS']["autoTest"] = "True"
else:
config['SETTINGS']["autoTest"] = "False"
with open(configFilePath, 'w') as configfile:
config.write(configfile)
print("</body>")
print("</html>")
I had the same problem. The problem was in the encoding. By default, ConfigParser.read() uses the encoding=none parameter. I specified utf-8 and it worked.
config = configparser.ConfigParser()
config.read(configFilePath, encoding='utf-8')
Ok I have found the solution for one part of the problem:
When changing the value make sure, you granted permissions to the file for cgi scripts:
in /etc/apache2/apache2.config add:
<Directory "/home/pi/dirToTheConfigFile/">
Options +ExecCGI +Indexes +FollowSymLinks
AddHandler cgi-script .cgi .py
AllowOverride None
Require all granted
</Directory>
And make sure, the user www-data is allowed to modify the file.
In general add cgitb.enable() to your python scripts, so for html 500 errors you will get a detailed error message in the /var/log/apache2/error.log file
For receiving data the following Solution was found:
The Python script was unfortunately owned by root and therefore cound not be executed. I changed the permissions.
The receiving html in the wordpress has been rewritten, too:
<iframe src="/cgi-bin/apfautostartval.py" width="100" height="29.5" frameborder="0" marginwidth="8" marginheight="0" scrolling="no" align="bottom"></iframe>
It's now an iframe and displays whatever is returned.

malformed header from script index.py Bad header

I want to run python code in apache2(ubuntu 14.04) server. I have followed these steps and getting Error:
Step 1:
Configuration 1: I have created a directory and file under
/var/www/cgi-bin
Configuration 2 : I have edited /etc/apache2/sites-available/000-default.conf
Alias /cgi-bin /var/www/cgi-bin
<Directory "/var/www/cgi-bin">
Options Indexes FollowSymLinks ExecCGI
AddHandler cgi-script .cgi .py
Allow from all
</Directory>
<Directory /var/www/cgi-bin>
Options All
</Directory>
Step 2:
and my python script is: index.py
#!/usr/bin/env python
import cgi;
import cgitb;cgitb.enable()
print "Content-Type: text/plain\n"
print "<b>Hello python</b>"
step 3:
When i ran through chrome browser using:
URL : http://localhost/cgi-bin/index.py
step 4:
I am getting this Error in error-log
malformed header from script 'index.py': Bad header: Hello Python
You should end your header with \r\n, then you must print out yet another \r\n to signal that the body is coming.
(In other words, it's interpreting your body as a Header because the headers were never terminated)
Try this script
#!/usr/bin/env python
import cgi;
import cgitb;cgitb.enable()
print "Content-Type: text/html"
print "" #use this double quote print statement to add a blank line in the script
print "<b>Hello python</b>"
There should be one line space between header and main html content. That's why we have to use extra print statement before starting html tags in script.
I had this issue with the flush mechanism when you need to print a file.
This code responds to a http request if it is called via e.g. apache2.
import sys
print("Content-type: image/png", end="\r\n\r\n", flush=True)
sys.stdout.buffer.write(bytes(open("file.png","rb").read()))
end="\r\n\r\n" adds an empty line to begin the body
flush=True forces python to print the lines as intended. In my case, the header was printed wrong.

How to make MOD_WSGI app to run Python in 32-bit mode?

I seemingly tried everything and I failed to achieve to run Python in 32-bit mode.
So here is my situation:
I am running OSX 10.8. I developed CherryPy app that has to connect to Oracle 10g2 database. There is a well-known issue that prevent CX_Oracle to work in 64-bit, thus the requirement to run in 32.
<IfModule wsgi_module>
<Directory "/Library/WebServer/WSGI-Executables">
AllowOverride None
Options None FollowSymLinks
Order allow,deny
Allow from all
SetEnv CONFIG_PATH /Users/bioffe/src/Icap/trunk/cgi-bin
SetEnv ORACLE_HOME /Applications/ORACLE/instantclient_10_2
SetEnv TNS_ADMIN /Applications/ORACLE/instantclient_10_2
SetEnv LD_LIBRARY_PATH /Applications/ORACLE/instantclient_10_2
SetEnv DYLD_LIBRARY_PATH /Applications/ORACLE/instantclient_10_2
SetEnv VERSIONER_PYTHON_PREFER_32_BIT yes
</Directory>
WSGIPythonHome /usr/local/bin/python2.7-32
WSGIPythonPath /Library/WebServer/WSGI-Executables
WSGIScriptAlias /etc /Library/WebServer/WSGI-Executables/ETCConfWebApp.py
#WSGIDaemonProcess etc_config user=bioffe group=wheel threads=4 python_path=/Library/Python/2.7/site-packages/
ProxyPreserveHost On
SetEnv VERSIONER_PYTHON_PREFER_32_BIT yes
</IfModule>
App's code
#cherrypy.expose
def index(self):
result = ''
for key, value in os.environ.items():
result += key + '=' + value + '\r\n'
cherrypy.response.headers['Content-Type']= 'text/plain'
result += '*' * 10
result += '\rCurrent Dir = %s \r' % os.getcwd()
result += '__file__ = %s \r' % __file__
result += 'PID=%d \r' % os.getpid()
result += 'PPID=%d \r' % os.getppid()
result += 'UID=%d \r' % os.getuid()
import threading
th = threading.current_thread()
result += "ThreadID=%d name=%s \r" %(th.ident,th.name)
result += "ThreadPool Size=%d \r" %(cherrypy.server.thread_pool)
result += "ThreadPool Max Size=%d \r" %(cherrypy.server.thread_pool_max)
import sys
result += "%s \r" %(sys.version)
result += "%d \r" %(sys.maxint)
Output
PATH=/usr/bin:/bin:/usr/sbin:/sbin
**********
Current Dir = /Library/WebServer/WSGI-Executables
__file__ = /Library/WebServer/WSGI-Executables/ETCConfWebApp.py
PID=16170
PPID=16167
UID=70
ThreadID=140735313402208 name=MainThread
ThreadPool Size=10
ThreadPool Max Size=-1
2.7.1 (r271:86832, Jun 25 2011, 05:09:01)
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)]
9223372036854775807 <- 64 bit, I want to see 32-bit's 2147483647
Here is what tried so far:
To force Python by setting environment variable
export VERSIONER_PYTHON_PREFER_32_BIT=yes
This one is ignored by WSGI_mod. os.environ contains only one PATH environment variable
To force Python by setting defaults value and make it accessible to _www(70) user.
defaults write com.apple.versioner.python Prefer-32-Bit -bool yes
To create virtualenv and lipo thin i386 executable out of it
WSGIPythonHome /usr/local/bin/python2.7-32
To create thin executable into default python environment, didn't work.
To compile mod_wsgi link using python2.7-32's headers and *.sos.
Nothing works. I was wondering of someone could shed some light on this issue.
BONUS Q:
I added
WSGIDaemonProcess etc_config user=bioffe group=wheel threads=4 python_path=/Library/Python/2.7/site-packages/
I see extra https process that is run with UID bioffe, however my app still being processed by httpd process with UID _www. How come my request is being processed by different httpd process ?
Have you read:
http://code.google.com/p/modwsgi/wiki/InstallationOnMacOSX#Forcing_32_Bit_Execution
Also be aware SetEnv doesn't set environment variables. For mod_wsgi it sets per request environ variables which are passed in a dictionary to the WSGI application on each request. Thus, you cannot SetEnv to set process environment variables.
http://code.google.com/p/modwsgi/wiki/ConfigurationGuidelines#Application_Configuration
As to WSGIDaemonProcess, you likely are missing the required WSGIProcessGroup that needs to go with it.
Please ensure you are reading the mod_wsgi documentation on the official mod_wsgi site as such details are covered there.
http://code.google.com/p/modwsgi/wiki/ConfigurationGuidelines#Defining_Process_Groups
http://code.google.com/p/modwsgi/wiki/QuickConfigurationGuide#Delegation_To_Daemon_Process
You possibly have some other things wrong, but too hard to tell as no detail provided which would help to confirm that.

Creation of virtual host through python

I have created a python (I m using 2.4) script to automatically create a virtual host in httpd.conf. But when I run it it gives the following error:
Traceback (most recent call last):
File "ApaPy2.py", line 2, in ?
from io import open
ImportError: No module named io
This is my script
import os
from io import open
project = raw_input(u'Enter the name of project ')
domain = raw_input (u'Enter the domain ')
docroot = raw_input(u'Enter root folder ')
virtualhost=u"""
<VirtualHost *:80>
ServerAdmin abhishek.verma#laitkor.com
DocumentRoot /""" +docroot+ u"""/""" +project+ u"""
ServerName """ +project+ u""".""" +domain+ u""".com
ErrorLog logs/""" +project+ u""".com-error_log
CustomLog logs/""" +project+ u""".com-access_log common
</VirtualHost>"""
f = open(u'/etc/httpd/conf/httpd.conf', u'a')
f.write(virtualhost)
f.close()
The io module doesn't exist in 2.4 (and you don't need it to use open in this case). I would also simplify your code to use string formatting using % instead:
project = raw_input(u'Enter the name of project ')
domain = raw_input (u'Enter the domain ')
docroot = raw_input(u'Enter root folder ')
virtualhost=u"""
<VirtualHost *:80>
ServerAdmin abhishek.verma#laitkor.com
DocumentRoot /%(docroot)s/%(project)s
ServerName %(project)s.%(domain)s.com
ErrorLog logs/%(project)s.com-error_log
CustomLog logs/%(project)s.com-access_log common
</VirtualHost>"""
f = open(u'/etc/httpd/conf/httpd.conf', u'a')
f.write(virtualhost % dict(project=project, docroot=docroot, domain=domain)
f.close()
The io module was introduced in Python 2.6, so it doesn't exist in 2.4. From the documentation:
New in version 2.6.
The open keyword should work fine for what you're doing here.
I've never used python 2.4, but the documentation says the io module has been added in the 2.6 version, so you can't import it in 2.4.
I'd assume open was already a built in function in 2.4, though, so simply removing the from io import open line should be enough.
The io module didn't exist in Python 2.4. Your usage of open is simple, so you can omit that line and the open statement will still work correctly.

How do I deal with URL reroutes in Python Bottle and Apache .htaccess?

I am currently trying to create a simple standalone application using Python Bottle.
My entire project is under pytest/, where I have dispatch.fcgi and .htaccess.
dispatch.fcgi:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import bottle
import os
from bottle import route, run, view
#route('<foo:path>')
#view('index')
def pytest(foo = ''):
return dict(foo=foo)
APP_ROOT = os.path.abspath(os.path.dirname(__file__))
bottle.TEMPLATE_PATH.append(os.path.join(APP_ROOT, 'templates'))
app = bottle.default_app()
if __name__ == '__main__':
from flup.server.fcgi import WSGIServer
WSGIServer(app).run()
.htaccess:
DirectoryIndex dispatch.fcgi
The following URLs give me the corresponding values of foo:
url.com/pytest/
> /pytest/
url.com/pytest/dispatch.fcgi
> /pytest/dispatch.fcgi
url.com/pytest/dispatch.fcgi/
> /
url.com/pytest/dispatch.fcgi/foo/bar
> /foo/bar
url.com/pytest/dispatch.fcgi/pytest/
> /pytest/
How can I make the URLs uniform? Should I deal with the rerouting with the .htaccess file or within the Python code? What would be considered most pythonic, or best practices?
I am running Python 2.6.6, Bottle 0.11.6, Flup 1.0.2, and Apache 2.2.24. I would also like to point out that I'm using shared hosting, and mod_wsgi is out of the question (if that makes a difference).
EDIT
This is what I expect to see:
url.com/pytest/
> <redirect to url.com/pytest/dispatch.fcgi>
url.com/pytest/dispatch.fcgi
> <empty string>
url.com/pytest/dispatch.fcgi/
> /
url.com/pytest/dispatch.fcgi/foo/bar
> /foo/bar
url.com/pytest/dispatch.fcgi/pytest/
> /pytest/
If there is a more efficient way of tackling this problem, please let me know.
Couple of thoughts. Hopefully some or all of these will help.
1) You can do the redirect from '/' to '/pytest/dispatch.fcgi' like this:
#route('/')
def home():
bottle.redirect('/pytest/dispatch.fcgi')
2) Can you use ScriptAlias instead of DirectoryIndex? I see you're on a shared environment, so I'm not sure. My bottle/apache servers use ScriptAlias (or WSGIScriptAlias) and it works perfectly there; and it'd make more clear the way your code interacts with apache.
3) If worse came to worst, could you hackishly detect the case where foo == '/pytest/dispatch.fcgi' and act accordingly? (E.g., treat it as empty string.)
Hope this helps. Please keep us posted!
Bottle seems to be confused because it expects a trailing slash, followed by parameters. For that reason I changed my .htaccess file to read like this:
DirectoryIndex dispatch.fcgi/
Another option would be to have all errors fall back onto the dispatch script. That can be done with mod_rewrite:
<IfModule mod_rewrite.c>
Options -MultiViews
# rewrite for current folder
RewriteEngine On
RewriteBase /pytest
# redirect to front controller
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ dispatch.fcgi/ [R=301,QSA,L]
</IfModule>
or FallbackResource:
FallbackResource /pytest/dispatch.fcgi/

Categories