Does Python CGIHTTPServer decode plus sign(+) in URL into blank space? - python

In my html, I have below form:
<form method=GET action="/cgi-bin/encry.sh">
<table nowrap>
<tr>
<td>Plain Text:</TD>
<TD><input type="text" name="PlainText"></td>
</tr>
</table>
<input type="submit" value="Encrypt">
</form>
After inputing "aaa +=" and clicking the button,
in my cgi-bin/encry.sh, the QUERY_STRING is assigned as "aaa++=" rather than "aaa +=", nor "a+%2B%3D".
Is that correct behavior, and if so how can I get the blank space correctly?
If not, is that fixed in any later CGIHTTPServer version?
Below provides some info about CGIHTTPServer.py in my CentOS 7.2:
HiAccount-4# md5sum /usr/lib64/python2.7/CGIHTTPServer.py
564afe4defc63001f236b0b2ef899b58 /usr/lib64/python2.7/CGIHTTPServer.py
HiAccount-4# grep __version /usr/lib64/python2.7/CGIHTTPServer.py -i
__version__ = "0.4"
HiAccount-4# grep unquote /usr/lib64/python2.7/CGIHTTPServer.py -i -C 3 -n
84- path begins with one of the strings in self.cgi_directories
85- (and the next character is a '/' or the end of the string).
86- """
87: collapsed_path = _url_collapse_path(urllib.unquote(self.path))
88- dir_sep = collapsed_path.find('/', 1)
89- head, tail = collapsed_path[:dir_sep], collapsed_path[dir_sep+1:]
90- if head in self.cgi_directories:
--
164- env['SERVER_PROTOCOL'] = self.protocol_version
165- env['SERVER_PORT'] = str(self.server.server_port)
166- env['REQUEST_METHOD'] = self.command
167: uqrest = urllib.unquote(rest)
168- env['PATH_INFO'] = uqrest
169- env['PATH_TRANSLATED'] = self.translate_path(uqrest)
170- env['SCRIPT_NAME'] = scriptname
Thanks in advance!

After trying the CGIHTTPServer from python2.7.18, I think the asked question is a known issue in 2.7.5, which was my version, and not sure which version fixed it.
The problem is in:
/usr/lib64/python2.7/CGIHTTPServer.py:
87: collapsed_path = _url_collapse_path(urllib.unquote(self.path))
In 2.7.18, the QUERY_STRING isn't decoded by CGIHTTPServer, and I need to decode it in my CGI script, but that's OK as it's "correct" encoded QUERY_STRING.
BTW, I didn't upgrade my python in OS from 2.7.5 to 2.7.18, but just extract CGIHTTPServer from python 2.7.18 source code and use it as:
nohup python ./CGIHTTPServer.py 7070 &
rather than
nohup python -m CGIHTTPServer 7070 &

Related

Python returns "invalid syntax" with Jinja2 set tag

I have version 2.11.2 of Jinja2 installed.
~]$ pip3 list
Package Version
---------------------------------- ------------------
Jinja2 2.11.2
And version 3.6.8 of Python
~]$ python --version
Python 3.6.8
I've a Python script named test.py. Here is the content of test.py.
from jinja2 import Template
name = "John Doe"
template = Template("Hello {{ name }}")
message = template.render(name=name)
print(message)
Invoking test.py is successful, "John Doe" is returned.
~]# python test.py
John Doe
I update test.py to have the following.
import jinja2
{% set foo = 'bar' %}
When I invoke test.py, I get "invalid syntax".
~]$ python test.py
File "testing.py", line 4
{% set foo = 'bar' %}
^
SyntaxError: invalid syntax
Best I can tell, I am using a valid syntax for the set tag, thus I'm not sure how to debug this issue.
This is because test.py is file executed by Python and not the template file interpreted by Jinja. Python interpreter has no idea how to interpret {% set foo = 'bar' %}.
Usually your code (test.py) needs to load template in Jinja format from file (e.g. test.j2) and then interpret it using Jinja API. Here is very simple example:
test.py (Python code):
from jinja2 import Template
name = "John Doe"
template = Template(open('test.j2').read()) # Read template from file test.j2
print(template.render(name=name))
test.j2 (template, in same directory from where you run code):
Hello {{ name }}
{% set foo = 'bar' %}
Note the code above is not ideal (just generally demonstrates how Jinja works) and you should consult https://jinja.palletsprojects.com/en/2.11.x/api/ and eventually https://jinja.palletsprojects.com/en/2.11.x/api/#loaders on how to properly load templates and render them from your code.
{% set foo = 'bar' %} is not a valid python code but you use it inside test.py. It maybe a valid jinja2 code but you are mixing python and jinja2 here..

Python CGI to invoke another CGI script that runs a sensor in Raspberry

I have a python CGI program (says: scrip1), that I am using to set values for some variable for another python CGI script (says: script 2) using web browser. I am using the script 2 to run a Lidar Sensor. The problem is I can set the variable in script 2 using script 1. But script 2 is not executing after receiving variable. Script 2 suppose to start my sensor. Any possible solutions. (I would like to stick on CGI scripts)
#script 1
#!/usr/bin/python
import os
import cgi
import cgitb
print("Content-Type: text/html\r\n")
print("")
print'''<html>
<head><title>Form to enter sleep time</title></head>
<body>
<form action="/cgi-bin/test.py" method="post">
<html><label> enter sleep time</label>
<input type="number" name="sleeptime"/>
<input type="submit" name ="Submit" "></form>
</body>
</html>'''
#### second script is######
#!/usr/bin/python
import os
import cgi
import cgitb
import smbus
import time
print("Content-Type: text/html\r\n")
form = cgi.FieldStorage()
sleeptime = form.getfirst("sleeptime") #getting value from script 1 (form data)
#script to run the Lidar is as follows#
bus=smbus.SMBus(1)
addr=0x62
while True:
bus.write_byte_data(0x62,0x00, 0x04)
val_high=bus.read_byte_data(0x62,0x0f)
val_low=bus.read_byte_data(0x62,0x10)
dist_cm=val_high*256+val_low
print (dist_cm , " cm ")
time.sleep(sleeptime)
The extension of the first file is .py as well? Have you tried using .cgi extension (with contents remaining the same)

python3 default encoding UnicodeDecodeError ascii using apache WSGI

import locale
prefered_encoding = locale.getpreferredencoding()
prefered_encoding 'ANSI_X3.4-1968'
I'm using a framework called inginious and it's using web.py to render its template.
web.template.render(os.path.join(root_path, dir_path),
globals=self._template_globals,
base=layout_path)
The rendering works on my localhost but not on my staging server.
They both run python3. I see that web.py enforces utf-8 on
the encoding in Python2 only (that's out of my hands)
def __str__(self):
self._prepare_body()
if PY2:
return self["__body__"].encode('utf-8')
else:
return self["__body__"]
here is the stack trace
t = self._template(name),
File "/lib/python3.5/site-packages/web/template.py", line 1028, in _template,
self._cache[name] = self._load_template(name),
File "/lib/python3.5/site-packages/web/template.py", line 1016, in _load_template
return Template(open(path).read(), filename=path, **self._keywords)
File "/lib64/python3.5/encodings/ascii.py", line 26, in decode
return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 83: ordinal not in range(128),
My html do include hebew chars, small example
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title feedback-modal-title">
חישוב האיברים הראשונים בסדרה של איבר ראשון חיובי ויחס שלילי:
<span class="red-text">אי הצלחה</span>
and I open it like so :
open('/path/to/feedback.html').read()
and the line where the encoding fails is where the Hebrew chars are.
I tried setting some environment variables in ~/.bashrc:
export PYTHONIOENCODING=utf8
export LC_ALL=en_US.UTF-8
export LANG=en_US.UTF-8
export LANGUAGE=en_US.UTF-8
under the user centos
The ingenious framework is installed as a pip under python3.5 site-packages. and it served by an apache server under the user apache
Tried setting the environment variables in the code (during the init of the app) so that the apache WSGI will be aware of them
import os
os.environ['LC_ALL'] = 'en_US.UTF-8'
os.environ['LANG'] = 'en_US.UTF-8'
os.environ['LANGUAGE'] = 'en_US.UTF-8'
I have edited the /etc/httpd/conf/httpd.conf using the setenv method:
SetEnv LC_ALL en_US.UTF-8
SetEnv LANG en_US.UTF-8
SetEnv LANGUAGE en_US.UTF-8
SetEnv PYTHONIOENCODING utf8
and restarted using sudo service httpd restart and still no luck.
My question is, what is the best practice to solve this. I understand there are hacks for this, but I want to understand what is the underline cause as well as how to solve it.
Thanks!
finally found the answer when reading the file
changed from
open('/path/to/feedback.html').read()
to
import codecs
with codecs.open(file_path,'r',encoding='utf8') as f:
text = f.read()
if anyone has a more general approach that will work, I'll accept his answer
A Python 2+3 solution would be:
import io
with io.open(file_path, mode='r', encoding='utf8') as f:
text = f.read()
See the documentation of io.open.

Executing Python cgi files in Apache on Windows

I am trying to run a very simple "Hello World" program with Apache.
However, Apache returns a 500 Internal Server Error when it tries to execute my python file.
I've read several similar topics on here and tried the suggestions, no luck.
Things I have tried:
Including the AddHandler with .py files to the .conf file
Adding ExecCGI to the "Options Indexes" line in the .conf.
Making sure the first thing output is ""Content-Type:text/html" with 2 end of line characters.
Adding a shebang line to the top of the python file to direct to the Python interpreter. I'm not sure if I'm doing this part right.
Restarting Apache
The tools I am using include:
Windows 7
Python 3.5
Apache 2.4
My code:
The HTML File (in the htdocs folder in the Apache folder):
<form action="/cgi-bin/hello_get.py" method="post">
First Name: <input type="text" name="first_name"> <br />
Last Name: <input type="text" name="last_name" />
<input type="submit" value="Submit" />
</form>
The python file (in the cgi-bin folder):
# Note that I tried this without the C:/ also
#!C:/Users/MyName/workspace/Flask/flask/Scripts
# Import modules for CGI handling
import cgi, cgitb
# Create instance of FieldStorage
form = cgi.FieldStorage()
# Get data from fields
first_name = form.getvalue('first_name')
last_name = form.getvalue('last_name')
print("Content-Type:text/html\r\n\r\n")
print("<html>")
print("<head>")
print("<title>Hello - Second CGI Program</title>")
print("</head>")
print("<body>")
print("<h2>Hello %s %s</h2>" % (first_name, last_name))
print("</body>")
print("</html>")
I figured it out.
In my shebang line, instead of:
#!C:/Users/MyName/workspace/Flask/flask/Scripts
I should have:
#!C:/Users/MyName/workspace/Flask/flask/Scripts/python.exe
I thought my shebang should have a path to where the python interpreter lives, I didn't realize I needed the actual full path of the interpreter.
It is working now.
So to recap, if you are having this issue after following these instructions:
http://editrocket.com/articles/python_apache_windows.html
Make sure that if you are using Windows the path is the full absolute path from the C:/ drive to the python.exe executable.

What is the correct way to deal with emoji in Flask / Python?

I'm working on an API and I'm getting crazy with emoji Flask/Python+emoji encoding :P
In the local server I have no problems, the emoji icons "take two positions" of the total string length, and the client (written in HTML+Javascript) does that in the same way. But when I deploy it to AWS EB, the emoji icons "just take one position", and the total length of a string is smaller, and I have absolutely no idea why that happens..
I have written a small code example to illustrate what is happening:
#api10.route('/prueba2', methods=['GET','POST'])
def prueba2():
que = request.form.get("que", None)
SEP = "\n"
if request.form.get("web", None) == "ok":
SEP = "<br />"
out = "QUE: '%s'%s" % (que,SEP)
out += "REP: '%s'%s%s" % (repr(que),SEP,SEP)
out += "LENGTH: '%d'%s%s" % (len(que),SEP,SEP)
out += "TYPE: '%s'%s%s" % (str(type(que)).replace("<", ""),SEP,SEP)
for index,letter in enumerate(que):
out += "%d -> %s%s" % (index,letter,SEP)
return out, 200, {'Content-Type': 'text/html; charset=utf-8'}
Local Response:
AWS EB Response:
The Response headers are the same in both:
Content-Type →text/html; charset=utf-8
Date →Tue, 09 Sep 2014 11:47:03 GMT
Server →Werkzeug/0.9.6 Python/2.6.8
But in AWS EB the "Connection" "Keeps-Alive" (of course the "Content-Length" is not equal)
Both implementations running on Python 2.6 (EC2 use that version and in local I have a Virtualenv whit python26)
OK, I know now why that was happening...
> Server side
Although both version run over Python 2.6, the AWS EB Python version was compiled with UCS4 support, and the local (Mac OS X) Python 2.6 with UCS2. More info about UCS here.
AWS EB EC2:
>>> import sys
>>> print sys.maxunicode
1114111
Local Python 2.6.8 installation:
>>> import sys
>>> print sys.maxunicode
65535
At the end I decide that is better for our project to use Python 2.6 whit UCS4 support, so I have to update my Python Installation (Mac OS X 10.9.4):
Download and Install Python 2.6.8 (same as EC2 instance):
$ curl -O https://www.python.org/ftp/python/2.6.8/Python-2.6.8.tgz
$ tar xzvf Python-2.6.8.tgz
$ cd Python-2.6.8
$ ./configure --disable-framework --disable-toolbox-glue OPT="-fast -arch x86_64 -Wall -Wstrict-prototypes -fno-common -fPIC" --enable-unicode=ucs4 LDFLAGS="-arch x86_64"
$ make
$ sudo make install
Creating new virtualenv and install dependencies:
$ virtualenv -p /usr/local/bin/python2.6 venv_ayf_eb_26
$ . venv_ayf_eb_26/bin/activate
$ pip install -r requirements.txt
> Client Side
Now in the Client (Javascript) we need to update the way we loop the string because ECMAScript 5- use UCS2.
So to read the "real string/symbols length" we use:
String.prototype.getSymbols = function() {
var length = this.length;
var index = -1;
var output = [];
var character;
var charCode;
while (++index < length) {
character = this.charAt(index);
charCode = character.charCodeAt(0);
if (charCode >= 0xD800 && charCode <= 0xDBFF) {
// note: this doesn’t account for lone high surrogates
output.push(character + this.charAt(++index));
} else {
output.push(character);
}
}
return output;
};
String.prototype.realLength = function() {
return this.getSymbols().length;
};
Looping:
// GET original_text over REST API
text = original_text.getSymbols();
for ( var i=0; i<original_text.length; i++) { /* DO SOMETHING */ }
References
The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!) - Joel Spolsky
Unipain: Pragmatic Unicode - Ned Batchelder
Universal Character Set - Wikipedia
ECMAScript - Wikipedia
ECMAScript® Language Specification (5.1) - Ecma International
JavaScript has a Unicode problem - Mathias Bynens
Python, convert 4-byte char to avoid MySQL error “Incorrect string value:” - StackOverflow
How to find out if Python is compiled with UCS-2 or UCS-4? - StackOverflow

Categories