Apache2 "Response header name '<!--' contains invalid characters, aborting request" - python

Edit
The problem had nothing to do with the http header. It was a variable that was called in the cgi/python script before it was defined. Just in case others also try to work with an error message like that but can't find the reason for it.
I have inherited a website based on apache2/python/cgi scripts that I'm trying to maintain, but sometimes I'm struggling with really unhelpful errors. In this case, I get The server encountered an internal error or misconfiguration and was unable to complete your request. when clicking on an element on a page. The error log gives me the following information:
[Fri Jul 28 14:11:15.150877 2017] [http:error] [pid 1727] [client 193.174.111.250:53426] AH02429: Response header name '<!--' contains invalid characters, aborting request
Based on a similar question, I'm assuming the error is quite new, but I can't find the problem. Especially since the link / the script name stays the same. It works when first opening the site, but then stops working when I click something which does not refer me to a different site/script. How can that be the header's fault?
Just in case, here is the code that generates the beginning of the web page:
Code = "Content-Type: text/html\n\n"
Code += "<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.0 Transitional//EN'>\n<html>\n"
Code += "<head>\n <title>BACTOME: RELATIVE EXPRESSIONS</title>\n"
...
As far as I understand now, the first line constitutes the only HTTP header I have. There is no '<!--' as stated in the error log. Does the header need anything else to be functional?
PS: Alternatively, if there's any easy way to turn these generic errors into more verbose ones, I'd also be very interested in that.

The answers from #eorochena and #dogacan are special cases. In general:
You get this error if an exception is raised in a Python CGI script.
A good way of figuring out what went wrong is to invoke Python's CGI module debug helper function at the beginning of your CGI script like this:
cgitb.enable(display=0, logdir=OUTDIR)
where OUTDIR is a directory name. If your CGI scripts raises some exception, then Apache puts an HTML file into that directory. The file has some garbage name such as tmpw4olz3xr.html, and at its end it contains the Python stack trace enclosed within HTML comments (<!-- ... -->). This is the information that will help you fix the problem.
Notes:
The display=0 parameter means that the error details are not shown
in the browser to your users.
You should probably comment out
cgitb.enable(...) when you are sure your script works OK.

Purpose
I think the purpose using cgitb is to get the whole information from web browser to help debugging.So we sholud correct the problem, not avoid the problem.
Do some research
Let us have a look at the information:
AH02429: Response header name '<!--' contains invalid characters, aborting request
It indicates the header name contains invalid characters, so i do some research on cgitb.py code as follow:
def reset():
"""Return a string that resets the CGI and browser to a known state."""
return '''<!--: spam
Content-Type: text/html
<body bgcolor="#f0f0f8"><font color="#f0f0f8" size="-5"> -->
<body bgcolor="#f0f0f8"><font color="#f0f0f8" size="-5"> --> -->
</font> </font> </font> </script> </object> </blockquote> </pre>
</table> </table> </table> </table> </table> </font> </font> </font>'''
This function returns the characters <!--. But apache httpd treat it as response header name which should not contain <!--.
There is also a open issue8704 in the Issue Tracker of python.
Maybe not a good solution
I do not know the should we delete the code in cgitb.py or adjust the configration of apache httpd. My solution is deleting some code as follows:
return '''
<body bgcolor="#f0f0f8"><font color="#f0f0f8" size="-5"> -->
<body bgcolor="#f0f0f8"><font color="#f0f0f8" size="-5"> --> -->
</font> </font> </font> </script> </object> </blockquote> </pre>
</table> </table> </table> </table> </table> </font> </font> </font>'''
Then it works very well, and it has good view.Anyone know what is the situation in ngix?

In my case the problem was the way the aligment of the output from the print statement
Before:
try:
if <some-condition>
message = "%s" % filename
else:
message = "file not found"
print """\n
Content-Type: text/html\n
<html><body>
<p>%s</p>
</body></html>
""" % (message,)
except Exception as e:
print e
After:
try:
if <some-condition>:
message = "%s" % filename
else:
message = "file not found"
print """\
Content-Type: text/html\n
<html><body>
<p>%s</p>
</body></html>
""" % (message,)
except Exception as e:
print e

For the same error, in a similar printing case, it was due to database collation; changing it to a UTF-8 helped me.

Related

Python CGI internal error login.html login.cgi

I'm currently trying to create a simple login in page to my actual local webpage that I'm running with on a virtual machine with Ubuntu.
I created the LoginPage.html at the location /var/www/html.
The HTML file then calls the login.cgi file in the /usr/lib/cgi-bin/login.cgi.
I get an Internal Server Error. The logs basically only shows this:
"POST /cgi-bin/login.cgi HTTP/1.1" 500 799
"http://localhost/LoginPage.html" "Mozialla/5.0 (X11; Ubtuntu; Linux
x86_64; rv:84.0) Geck/201000101 Firefox/84.0
The HTML file seems to be working as intended, but when I press login and get redirected to the CGI file, I get the error on the CGI file. I have tried to remove everything the in the CGI file to leave only a couple of lines but still get the error.
My other project-files in the cgi-bin folder still work without an error.
<HTML>
<HEAD><TITLE>Login Page</TITLE></HEAD>
<BODY>
<CENTER>
<FORM method="POST" action="/cgi-bin/login.cgi">
<paragraph> Enter your login name: <input type="text" name="login">
<paragraph> Enter your password: <input type=password name="password">
<paragraph> <input type="submit" value="Connect">
</FORM>
</CENTER>
<HR>
</form>
</BODY>
</HTML>
#!/usr/bin/python3
import sys
import cgi
import os
import cgitb
sys.path.insert(0,'/usr/lib/project_name')
def header():
#print "Content-type: text/html\n"
print("<HEAD>")
print("<TITLE> title </TITLE>")
print("</HEAD>")
def Log():
print("<!DOCTYPE html>")
print("<HTML>")
print("<html lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\">")
print(" <meta charset=\"utf-8\" />")
header()
print("BODY")
form = cgi.FieldStorage()
login = "login"
password = "test123"
if not (form):
header("Login Response")
print("<BODY>")
elsif (form.has_key("login") and form["login"].value == login and form.has_key("password") and form["password"].value == password):
header("Connected ...")
print("<BODY>")
print("<center><hr><H3>Welcome back,\" , form[\"login\"].value, \".</H3><hr></center>")
print("r\"\"\"<form><input type=\"hidden\" name=\"session\" value=\"%s\"></form>\"\"\" % (form[\"login\"].value)")
print("<H3>Click here to start browsing</H3>")
else:
header("No success!")
print("<BODY>")
print("<H3>Please go back and enter a valid login.</H3>")
def footer():
print("</BODY>")
print("</HTML>")
print("Content-type:text/html\r\n\r\n")
cgitb.enable()
Log()
footer()
Edit:
Here is the content of error.log after resolving the Internal Server Error:
[Tue Feb 02 08:40:41.199152 2021] [cgi:error] [pid 10292:tid
140490049578752] [client 127.0.0.1:38888] AH01215: (2)No such file or
directory: exec of '/usr/lib/cgi-bin/login.cgi' failed:
/usr/lib/cgi-bin/login.cgi, referer: http://localhost/LoginPage.html
[Tue Feb 02 08:40:41.199411 2021] [cgi:error] [pid 10292:tid
140490049578752] [client 127.0.0.1:38888] End of script output before
headers: login.cgi, referer: http://localhost/LoginPage.html
Correcting the setup:
No such file or directory: exec of '/usr/lib/cgi-bin/login.cgi' failed: /usr/lib/cgi-bin/login.cgi, referer: http://localhost/LoginPage.html
Make sure the CGI script and its parent directory have the right permissions:
chmod 755 /usr/lib/cgi-bin/ /usr/lib/cgi-bin/login.cgi
Also, it appears the CGI script may have windows line endings, so make sure you remove those as well, e.g. by running dos2unix login.cgi (see this post for more details).
Resolving the Internal Server Error:
First, make at least the following changes to correct your syntax (which is what's causing the Internal Server Error):
elsif should be elif
Your header function should take in an argument, i.e. def header(title)
Where you have form.has_key, change it to use in since has_key is now deprecated, e.g. "password" in form instead of form.has_key("password")
The corrected condition would look like this:
elif "login" in form and form["login"].value == login and "password" in form and form["password"].value == password:
As an aside, stick to HTML5, which is supported by all the latest browsers, and the center tag is now deprecated (its gone the way of the marquee tag). Use CSS instead.
Also, as a complete side note, these days, its uncommon to see ALL CAPS used for HTML tags. You have used that style in some places, but I suggest dropping it in favor of lowercase tag names.
Simplfying the HTML generation:
In addition to the above, I recommend using f-strings for string formatting and also multi-line strings to simplify the logic a bit.
Below are some examples of how you can enhance your code.
Your header function may look like this using f-strings and multi-line strings as suggested. The title argument is optional.
def header(title=""):
print(f"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title> {title} </title>
</head>
<body>
""")
Your footer function could look like this:
def footer():
print("""
</body>
</html>
""")
Finally, your HTML form could look like this, using text-align: center; for the centering:
print(f"""
<hr>
<h3 style="text-align: center;">Welcome back { form["login"].value }</h3>
<hr>
<form>
<input type="hidden" name="session" value="{ form["login"].value }">
</form>
<h3>
Click here to start browsing
</h3>
""")
Beautifying the HTML:
To beautify the HTML further, you can import textwrap and then use textwrap.dedent() to remove the common leading spaces from the HTML (due to the indentation in Python), e.g.
print(textwrap.dedent(f"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title> {title} </title>
</head>
<body>
"""))
This gives two advantages:
It removes the unnecessary leading spaces before sending it over the network -- so you send less data, saving bandwidth
The HTML source is prettier when you inspect it using a client browser -- useful for debugging
Alternatively, use HTML templating:
A further enhancement is to make use of a HTML templating framework, such as Jinja2. This will allow you to store the HTML into files and then render the HTML files by passing variables.
Then, your Python code would become a lot simpler. You would just render the template and pass the variables you want. For example, for you header, it could be like this:
template = env.get_template('header.html')
print(template.render(title='Connected ...'))
You will need to set up the Environment like this first:
from jinja2 import Environment
env = Environment(
loader=PackageLoader('package', 'templates')
autoescape=select_autoescape(['html'])
)
And place your header.html file in a directory called templates.
You may also want to read about the seperation of concerns principle and the MVC architecture. Using templates like this is just one step closer to achieving MVC.
Final point on security:
It looks like you are using a HTML hidden field to store the username, and treating that as a session token. This is highly insecure and won't scale. Though, it may be sufficient for your purposes. A simple way to improve on it is to store it as a cookie using the Set-cookie header, and make it HttpOnly, e.g.
Set-cookie: session=value; HttpOnly
where value could be some unique token (e.g. a uuid).
This is much better than your current approach.
But, even better yet, you could implement security using a library like PyJWT instead.

Textarea event handling with Python3

I wonder if someone can help me. I'm trying to do something like the following to get input events from a HTML text box and send them to a python function.
textarea = cgi.FieldStorage()
chars = textarea.getvalue('1')
def MyPythonFunction():
'Do something with chars'
print(<textarea oninput=MyPythonFunction() </textarea>)
I've tried all kinds of things but can't get it to work.
Thanks in advance
First, the oninput keyword of the textarea HTML tag expects JavaScript code and would interpret mypythonfunction to be a JavaScript function. You need to output an HTML form that contains a SUBMIT tag such that when the form is submitted it invokes your server-side script: the form might look like:
<form name="f" action="my_script.py" method="post">
<textarea name="chars"></textarea>
<br>
<input type="submit" name="submit" value="Submit">
</form>
Your server side script, my_script.py, which must be executable, might look like:
#!/usr/bin/env python
import cgi
import cgitb
cgitb.enable()
form = cgi.FieldStorage()
chars = form.getvalue('chars')
If you really wanted to process input a character at a time, then you would remove the SUBMIT HTML tag, put back the oninput keyword. But then you would have to specify a JavaScript function that would get invoked whenever the contents of the textarea changed. This function would have to use a technique called AJAX to invoke your server-side Python script passing the contents of the TEXTAREA as an argument. This is a rather advanced topic, but you can investigate this.

Turbogears abort function automatically escapes HTML code

I would like to use some HTML messages in the turbogears abort function.
Although the name does not match exactly (I use the 'tg.abort' function), this is the abort definition I found :
abort
The code used currently :
from tg import abort
message="The following {} occured, this is due to {}, please visit this url : {}".format(error, reason, url)
abort(status_code=502, detail=message)
I would like to have something like this :
from tg import abort
message="""The following error occured : {}</br>
The most probable reason would be {} </br>
Your solution might be found here
""".format(error, reason, url)
abort(status_code=502, detail=message)
I think the content is automatically escaped.
The Html page generated from the abort function, endering something like this :
<html>
<head>
<title>502 Bad Gateway</title>
</head>
<body>
<h1>502 Bad Gateway</h1>
Bad gateway.<br /><br />
The following error occured : hungry<br/>
The most probable reason would be : maybe you should eat </br>
<a href="http://dummyurl">Your solution might be found here</a>
</body>
</html>
If you have any idea of how to insert html code without escaping, I would be very interested.
Also I really am focused on the abort method here, I am aware that I could use some dedicated page that would use a templating framework (like the rest of the website).
Thank you very much.
Regards
The error message is actually exposed by the controllers/error.py code in your application. So if you want to expose the message from abort details you should fetch it and return it in the ErrorController.
This is now done by default on newly quickstarted projects ( see https://github.com/TurboGears/tg2devtools/blob/master/devtools/templates/turbogears/%2Bpackage%2B/controllers/error.py_tmpl#L27 ) but it was not done on old versions.

Generating XML/Feed for your Python Blog

I've been trying to add RSS feeds in my blog(webapp2 application - Jinja2 templates), this is what I have:
class XMLHandler(Handler):
def get(self):
posts = db.GqlQuery("SELECT * FROM Post WHERE is_draft = FALSE ORDER BY created DESC")
self.render("xmltemplate.xml", posts=posts, mimetype='application/xml')
xmltemplate.xml looks like this:
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<channel>
<title>Blag</title>
<link>http://www.blagonudacity.appspot.com/</link>
<description>Yet Another Blag</description>
{%for post in posts %}
<entry>
<title>{{post.subject}}></title>
<link href="http://www.blagonudacity.appspot.com/post/{{ post.key().id()}}" rel="alternate" />
<updated>{{post.created}}</updated>
<author><name>Prakhar Srivastav</name></author>
<summary type="html"> {{ post.content }} </summary>
</entry>
{%endfor%}
</channel>
</feed>
What i'm getting in my browser when I migrate to the relevant page /feeds/all.atom.xml
is just a html page with the markup. It doesn't look like how XML pages look in browser. What am I doing wrong here? Here is the demo
I saw that the page is delivered with content type text/html, this could be one problem, i suggest you should set this to text/xml (more details can be found here.
Also it highly depends on the browser on how this is displayed, i guess you are using chrome (like me) where the link provided by you looks like a webpage, if you open it in firefox you will see the "live bookmark" styled page, however the entries don't show. I'm not sure if this is because of some problem with your markup or some problem with firefox and atom feeds.
The xml file itself seems to be ok (checked with w3 validator).
UPDATE: Ok, there seems to be something wrong with your atom XML (it is valid xml, as mentioned above) however it does not seem to be valid Atom data (according to the feed validator).
I tried to bookmark it in firefox and it does not show any entries (just like the preview mentioned above).
So i think you should take a look at the atom feed e.g. this and this could help.
I'm not really sure but when looking at your XML i think that you may have mixed up Atom and Rss a little.

Problem with python cgi in Firefox

I have written an html form and am trying to incorporate a python cgi script with it. I have already configured my apache server to execute cgi scripts from the cgi-bin directory. Here's the html form:
<html>
<body>
<form name="input" action="c:/xampp/cgi-bin/test2.py" method="post">
<input type="text" name="qry" />
<input type="submit" value="GO!" />
</form>
</body>
</html>
And here's the test2.py cgi script:
#!c:/Python27/python.exe -u
import cgi
import cgitb
cgitb.enable()
form = cgi.FieldStorage()
qry = form["qry"].value
print "Content-Type: text/html"
print
print "<html"
print "<body>"
print qry
print "</body>"
print "</html>"
The html page is located in my htdocs folder and the cgi script is in the cgi-bin directory. However, when I enter something into the form and submit, firefox returns an error message saying: "Firefox doesn't know how to open this address, because the protocol (c) isn't associated with any program". Why is this error occurring? Does it have something to do with my path to the cgi script in my html page? Thanks in advance!
You are correct: it has something to do with the path to the CGI script on the HTML page. The form's action attribute should refer to the path where the CGI script is getting interpreted on the server, e.g., /cgi-bin/test2.py.
Since you made this mistake, I'm assuming you are new to web development. Consider using mod_wsgi and a framework like Django instead of CGI, especially if you expect a lot of traffic or you are making a web application and not just handling a single form.

Categories

Resources