I'm trying to mount a Tornado server on an Ubuntu VM, whose task will be to generate a complete font pack, starting from a .svg file. I have run the following script without my server, that worked kinda perfectly. https://gist.github.com/jorgegarciadev/6127832
And now that I try to execute this task on my server, Fontforge seem to have trouble with the .svg file. First I thought it was a chunk problem, as if my file wasn't read or sent totally, but when I open the recently uploaded file on the server, it's complete and has the same size than the original file. And what's still more disturbing is that Fontforge informs me that this file is not a font file. That's what made me think about the chunk thing (because it seems to be parsing errors)
SVG File on pastebin right there : http://pastebin.com/ai5pr1DG
The python server code:
import tornado, tornado.ioloop, tornado.web
import os, uuid
import fontforge, re, zipfile
__UPLOADS__ = "uploads/"
EXTS = [".woff", ".ttf", ".otf", ".svg", ".eot"]
class Userform(tornado.web.RequestHandler):
def get(self):
self.render("fileuploadform.html")
class Upload(tornado.web.RequestHandler):
@staticmethod
def cssGenerator(name, fullname):
cssFile = name + ".css"
template = "@font-face {\
\n\tfont-family: '" + fullname + "';\
\n\tsrc: url('" + name + ".eot');\
\n\tsrc: url('" + name + ".eot?#iefix') format('embedded-opentype'),\
\n\turl('" + name + ".woff') format('woff'),\
\n\turl('" + name + ".ttf') format('truetype'),\
\n\turl('" + name + ".svg#ywftsvg') format('svg');\
\n\tfont-style: normal;\
\n\tfont-weight: normal;\
\n}\n\n"
open(cssFile, 'w+').writelines(template)
@staticmethod
def fontGenerator(filename):
#exts = ["woff", "ttf", "otf", "svg", "eot"]
name = os.path.splitext(filename)[0]
'''if not os.path.exists(name):
os.makedirs(name)'''
font = fontforge.open(filename)
fullname = font.fullname
for ext in EXTS:
f = name + ext
font.generate(f)
def post(self):
fileinfo = self.request.files['filearg'][0]
fname = fileinfo['filename']
extn = os.path.splitext(fname)[1]
cname = str(uuid.uuid4()) + extn
zname = os.path.splitext(fname)[0]
fh = open(cname, 'w+')
fh.write(fileinfo['body'])
os.system("mv " + cname + " " + zname + extn)
#zname is default, extn is .svg, fname is default.svg, cname is file name in the server
self.cssGenerator(zname, 'testfont')
self.fontGenerator(zname + extn)
application = tornado.web.Application([
(r"/", Userform),
(r"/upload", Upload),
], debug=True)
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
Output after launching server and clicking "upload" button on the client:
strippedname:/home/bill/proto.svg
/home/bill/proto.svg:109: parser error : AttValue: ' expected
-18 403 -18 L 403 -18 C 352 -18 301 0 251 0 C 225 0 210 15 210 41 C 210 63 225 7
^
/home/bill/proto.svg:109: parser error : attributes construct error
-18 403 -18 L 403 -18 C 352 -18 301 0 251 0 C 225 0 210 15 210 41 C 210 63 225 7
^
/home/bill/proto.svg:109: parser error : Couldn't find end of Start Tag glyph line 109
-18 403 -18 L 403 -18 C 352 -18 301 0 251 0 C 225 0 210 15 210 41 C 210 63 225 7
^
/home/bill/proto.svg:109: parser error : Premature end of data in tag font line 6
-18 403 -18 L 403 -18 C 352 -18 301 0 251 0 C 225 0 210 15 210 41 C 210 63 225 7
^
/home/bill/proto.svg:109: parser error : Premature end of data in tag defs line 5
-18 403 -18 L 403 -18 C 352 -18 301 0 251 0 C 225 0 210 15 210 41 C 210 63 225 7
^
/home/bill/proto.svg:109: parser error : Premature end of data in tag svg line 3
-18 403 -18 L 403 -18 C 352 -18 301 0 251 0 C 225 0 210 15 210 41 C 210 63 225 7
^
Couldn't find a font file named /home/bill/proto.svg
proto.svg is not in a known format (or uses features of that format fontforge does not support, or is so badly corrupted as to be unreadable)
ERROR:tornado.application:Uncaught exception POST /upload (82.225.61.131)
HTTPServerRequest(protocol='http', host='py-fontconv.cloudapp.net', method='POST', uri='/upload', version='HTTP/1.1', remote_ip='82.225.61.131', headers={'Content-Length': '32378', 'Accept-Language': 'en-us,en;q=0.8,fr;q=0.5,fr-fr;q=0.3', 'Accept-Encoding': 'gzip, deflate', 'Host': 'py-fontconv.cloudapp.net', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:28.0) Gecko/20100101 Firefox/28.0', 'Connection': 'keep-alive', 'Content-Type': 'multipart/form-data; boundary=---------------------------191335620930032341323215978'})
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/tornado/web.py", line 1332, in _execute
result = method(*self.path_args, **self.path_kwargs)
File "tornadofileupload.py", line 53, in post
self.fontGenerator(zname + extn)
File "tornadofileupload.py", line 35, in fontGenerator
font = fontforge.open(filename)
EnvironmentError: Open failed
ERROR:tornado.access:500 POST /upload (82.225.61.131) 283.75ms
If anyone finds out what's missing here, that would be such a relief because I'm really struggling on this one.
You need to flush or close fh
after writing to it. The best way to do this is with the with
statement:
with open(cname, 'w+') as f:
f.write(fileinfo['body'])
The use of mv
on the next line is dangerously insecure. Someone could upload a file with the "name" $(rm -rf *)
and that command would be executed. Never use os.system
with untrusted input. In this case the shutil
module provides alternatives. It's also problematic to use the user-supplied filename as zname directly - it's always better to generate your own filenames instead of using one supplied by the client.