I have created a CGIHTTPServer which works fine, problem is no matter what I do, the python pages are never rendered and the source code is always shown in the browser.
pyhttpd.py
#!/usr/bin/python
import CGIHTTPServer
import BaseHTTPServer
class Handler(CGIHTTPServer.CGIHTTPRequestHandler):
cgi_directories = [""]
PORT = 8080
httpd = BaseHTTPServer.HTTPServer(("", PORT), Handler)
print "serving at port", PORT
httpd.serve_forever()
cgi-bin/hello.py
#!/usr/bin/python
print 'Content-Type: text/html'
print
print '<html>'
print '<head><title>Hello</title></head>'
print '<body>'
print '<h2>Hello World</h2>'
print '</body></html>'
http://some.ip.address:8080/cgi-bin/hello.py:
#!/usr/bin/python
print 'Content-Type: text/html'
print
print '<html>'
print '<head><title>Hello</title></head>'
print '<body>'
print '<h2>Hello World</h2>'
print '</body></html>'
I have set the permission on all files to executable, .html files render fine, even moving the file back to the root folder where the server is running makes no difference, I have tried running as root as well as another normal user, exactly the same results.
Tried googling "python pages not rendered" but have not found anything useful !
EDIT
I have also tried running a simpler server with no overrides, but the result is identical, pything code is never rendered:
pyserv.py
#!/usr/bin/python
from BaseHTTPServer import HTTPServer
from CGIHTTPServer import CGIHTTPRequestHandler
serve = HTTPServer(("",80),CGIHTTPRequestHandler)
serve.serve_forever()
I believe you're having this issue because you have overridden cgi_directories.
The relevant portion of the documentation reads:
"This defaults to ['/cgi-bin', '/htbin'] and describes directories to treat as containing CGI scripts."
Either place your script in the root directory, or remove the override for cgi_directories and place the scrips in the /cgi-bin directory.
Here is a good link that describes a similar simple setup line by line:
https://pointlessprogramming.wordpress.com/2011/02/13/python-cgi-tutorial-1/
UPDATE:
According to a comment on the above page, it appears that setting cgi_directories = [""] results in disabling the cgi directory feature. Instead, set cgi_directories = ["/"], which sets it to the current directory.
Related
Environment:
Python 3.7.7
Windows 10 64bits
Purpose of the code:
Display an HTML report of my software activity. It uses http.server module loaded by file Report.py and the data report are extracted by index.py.
I have a script myscript.py which launches the server by calling a method StartReportTool() inside the module Report.py.
Report.py launch the server and load the index.py.
Files & Folder tree:
- myscript.py <= call the method in module Report.py to launch web server
- /report
- /report/Report.py <= launch the web server
- /report/index.py <= extract the data and display them in html
Source code:
myscript.py:
def report():
from report import Report
Report.StartReportTool()
report()
/report/Report.py
#coding:utf-8
import http.server
import webbrowser
def StartReportTool():
port=8888
address=("",port)
server=http.server.HTTPServer
handler=http.server.CGIHTTPRequestHandler
handler.cgi_directories=["/"]
httpd=server(address,handler)
print(f"Report tool server started on port {port}")
webbrowser.open('http://localhost:8888/index.py', new=2)
httpd.serve_forever()
index.py:
#coding:utf-8
import cgi
import cgitb
cgitb.enable()
form = cgi.FieldStorage()
print("Content-type: text/html; charset=utf-8\n")
html=f"""
<!DOCTYPE html>
My html code
"""
Problem:
When I run myscript.py which launches my http.server, my browser open url 'http://localhost:8888/index.py' and show error 404:
Error response
Error code: 404
Message: No such CGI script ('//index.py').
Error code explanation: HTTPStatus.NOT_FOUND - Nothing matches the given URI.
After investigation, I realized everything is fine when the server is launched by its own script Report.py:
#coding:utf-8
import http.server
import webbrowser
def StartReportTool():
port=8888
address=("",port)
server=http.server.HTTPServer
handler=http.server.CGIHTTPRequestHandler
handler.cgi_directories=["/"]
httpd=server(address,handler)
print(f"Report tool server started on port {port}")
webbrowser.open('http://localhost:8888/index.py', new=2)
httpd.serve_forever()
StartReportTool() # <======= Here is the line of code which launch the server itself inside the same module
You noticed here the last line of code StartReportTool() which calls the method inside the module itself. And it is working fine by this way. My index.py is loaded correctly.
The problem comes when the method StartReportTool() is called from outside the method.
I don't understand the reasons for the issue. Does anyone understand the source of the problem, please?
Consider a simple server.py
from http.server import CGIHTTPRequestHandler, HTTPServer
PORT = 5005
handler = CGIHTTPRequestHandler
handler.cgi_directories = ['/'] # this is the current directory
server = HTTPServer(('localhost', PORT), handler)
print ('Server is ready at', PORT, 'PORT')
server.serve_forever()
If I call this file using python.exe -u server.py in command line I'll be able to serve a python script in '/' main directory.
I could use also python -m http.server --bind localhost --cgi 5005 directly.
In both cases I need to open in the browser a specific python file, lets say: http://localhost:5005/myfunction.py
Is there an alternative to include the file.py using http.server directly in command line?
For example, something equivalent to micro -p 5005 file.js according to micro npm module?
it seems redirecting to anything other then index.html or index.htm (or a list of files) is not supported by the base code:
#if <path is a directory>:
for index in "index.html", "index.htm":
index = os.path.join(path, index)
if os.path.exists(index):
path = index
break
else:
return self.list_directory(path)
one solution would be to simply modify the original source so the tuple ("index.html", "index.htm") points to something that can more easily be altered at runtime. Alternatively you can define your own wrapper that makes the check yourself, basically just copy the whole def send_head function and override that loop to just assign path to the file you want to redirect to.
Wish I had a solution that doesn't involve rewriting the source code but I can't think of another (sane) solution.
#!/usr/bin/python
print "Content-type:text/html\r\n\r\n"
print '<html>'
print '<head>'
print '<title>Hello Word - First CGI Program</title>'
print '</head>'
print '<body>'
from wsgiref.handlers import CGIHandler
from app import app
CGIHandler().run(app)
a=9
b=8
c=a+b
import test
d=test.addd(77,88)
print c
print d
print '<h2>Hello Word! This is my first CGI program</h2>'
print '</body>'
print '</html>'
"""The above code is in my cgi-bin folder as sumitup.py which works fine and gives the add part of the code as result in the browser when I remove the below import part."""
from wsgiref.handlers import CGIHandler
from app import app
CGIHandler().run(app)
"""I had created a test.py and tried calling the addd method which is also working fine.
Do I need to add the code of wsgiref.handlers library explicity in the same folder.
Note:- I am trying to deploy flask app on a shared hosting www.techpython.com
Can you help me for this.Thanks in advance."""
CGIHandler handles the CGI request for you.
There is no need to print content-length or something like this.
On top of the CGIHandler you could use something like Werkzeug ( http://werkzeug.pocoo.net/ ).
If I do python -m SimpleHTTPServer it serves the files in the current directory.
My directory structure looks like this:
/protected/public
/protected/private
/test
I want to start the server in my /test directory and I want it to serve files in the /test directory. But I want all requests to the server starting with '/public' to be pulled from the /protected/public directory.
e.g.a request to http://localhost:8000/public/index.html would serve the file at /protected/public/index.html
Is this possible with the built in server or will I have to write a custom one?
I think it is absolutely possible to do that. You can start the server inside /test directory and override translate_path method of SimpleHTTPRequestHandler as follows:
import BaseHTTPServer
import SimpleHTTPServer
server_address = ("", 8888)
PUBLIC_RESOURCE_PREFIX = '/public'
PUBLIC_DIRECTORY = '/path/to/protected/public'
class MyRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
def translate_path(self, path):
if self.path.startswith(PUBLIC_RESOURCE_PREFIX):
if self.path == PUBLIC_RESOURCE_PREFIX or self.path == PUBLIC_RESOURCE_PREFIX + '/':
return PUBLIC_DIRECTORY + '/index.html'
else:
return PUBLIC_DIRECTORY + path[len(PUBLIC_RESOURCE_PREFIX):]
else:
return SimpleHTTPServer.SimpleHTTPRequestHandler.translate_path(self, path)
httpd = BaseHTTPServer.HTTPServer(server_address, MyRequestHandler)
httpd.serve_forever()
Hope this helps.
I think I have found the answer to this, basically it involves changing the current working directory, starting the server and then returning back to your original working directory.
This is how I achieved it, I've commented out two sets of options for you, as the solution for me was just moving to a folder within my app directory and then back up one level to the original app directory. But, you might want to go to an entire other directory in your file system and then return someplace else or not at all.
#Setup file server
import SimpleHTTPServer
import SocketServer
import os
PORT = 5002
# -- OPTION 1 --
#os.chdir(os.path.join(os.path.abspath(os.curdir),'PATH_TO_FOLDER_IN_APP_DIR'))
# -- OPTION 2 --
#os.chdir('PATH_TO_ROOT_DIRECTORY')
Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
httpd = SocketServer.TCPServer(("", PORT), Handler)
print "serving at port", PORT
httpd.serve_forever()
# -- OPTION 1 --
#os.chdir(os.path.abspath('..'))
# -- OPTION 2 --
#os.chdir('PATH_TO_ORIGINAL_WORKING_DIR')
Let me know how it works out!
I do not believe SimpleHTTPServer has this feature, however if you use a symbolic link inside of /test that points to /protected/public, that should effectively do the same thing.
My .py file executes ok in terminal, but gives this error in the browser
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>500 Internal Server Error</title>
</head><body>
<h1>Internal Server Error</h1>
...
...
Here is the .py file:
#!/usr/bin/python
import cgi
import cgitb; cgitb.enable()
print "Content-Type: text/html\n\n" # HTML is following
print # blank line, end of headers
print "<TITLE>CGI script output</TITLE>"
print "<H1>This is my first CGI script</H1>"
print "Hello, world!"
Should i be saving this as a .cgi file? I have tried with the same errors, i have tried many files like this and none work, i am sure the apache server is working as there are other .cgi scripts running from the same directory without issues.
I have also tried:
#!/usr/local/bin/python &
#!/usr/bin/local/python
Any help appreciated.
EDIT
error log output:
(2) No such file or directory: exec of '.../.../.../test.py' failed
Premature end of script headers: test.py
Here is something I wrote up a while ago. These are some good things to look for when troubleshooting Python CGI.
There are some tips to getting Python working in CGI.
Apache setup: This may be old
Add python as a CGI by modifying the following in the configuration:
Options Indexes FollowSymLinks ExecCGI
AddHandler cgi-script .cgi .py
Always browse the pages through Apache.
Note that viewing files in the filesystem through a browser works for most things on an html page but will not work for CGI. For scripts to work they must be opened through the htdocs file system. The address line of your browser should look like:
\\127.0.0.1\index.html or
\\localhost\index.html
If you open a file up through the file system the CGI will not work. Such as if this is in the location bar of your browser:
c:\Apache\htdocs\index.html (or some other example location)
Convert end of lines of scripts to Unix format:
Most editors have options to "show end of lines" and then a tool to convert from Unix to PC format. You must have the end of lines set to Unix format.
State the path to the Python interpreter on the first line of the CGI script:
You must have one of the following lines as the first line of your Python CGI script:
#!C:\Python25\Python.exe
#!/usr/bin/python
The top line is used when you are debugging on a PC and the bottom is for a server such as 1and1. I leave the lines as shown and then edit them once they are up on the server by deleting the first line.
Print a content type specifying HTML before printing any other output:
This can be done simply by adding the following line somewhere very early in your script:
print "Content-Type: text/html\n\n"
Note that 2 end of lines are required.
Setup Python scripts to give debugging information:
Import the following to get detailed debugging information.
import cgitb; cgitb.enable()
An alternative if cgitb is not available is to do the following:
import sys
sys.stderr = sys.stdout
On the server the python script permissions must be set to execute.
After uploading your files be sure to edit the first line and set the permissions for the file to execute.
Check to see if you can hit the python script directly. If you can't, fix with the above steps (2-6). Then when the Python script is working, debug the shtml.