circumvent CGI 1.1 specs (PATH_INFO is quoted)
This commit is contained in:
parent
3cb623e7c2
commit
f2eff22ff7
@ -20,7 +20,7 @@
|
||||
#
|
||||
# Isso – a lightweight Disqus alternative
|
||||
|
||||
__version__ = '0.1'
|
||||
__version__ = '0.2'
|
||||
|
||||
import json
|
||||
|
||||
@ -33,22 +33,24 @@ from werkzeug.exceptions import HTTPException, NotFound, InternalServerError
|
||||
|
||||
from isso import admin, comment, db, utils
|
||||
|
||||
|
||||
# override default json :func:`dumps`.
|
||||
_dumps = json.dumps
|
||||
setattr(json, 'dumps', lambda obj, **kw: _dumps(obj, cls=utils.IssoEncoder, **kw))
|
||||
|
||||
|
||||
# yep. lazy.
|
||||
url = lambda path, endpoint, methods: Rule(path, endpoint=endpoint, methods=methods)
|
||||
|
||||
url_map = Map([
|
||||
# moderation panel
|
||||
url('/', 'admin.index', ['GET', 'POST']),
|
||||
|
||||
# comments API
|
||||
url('/comment/<string:path>/', 'comment.get', ['GET']),
|
||||
url('/comment/<string:path>/new', 'comment.create', ['POST']),
|
||||
url('/comment/<string:path>/<int:id>', 'comment.get', ['GET']),
|
||||
url('/comment/<string:path>/<int:id>', 'comment.modify', ['PUT', 'DELETE']),
|
||||
])
|
||||
# comment API, note that the client side quotes the URL, but this is
|
||||
# actually unnecessary. PEP 333 aka WSGI always unquotes PATH_INFO.
|
||||
url('/comment/<re(".+"):path>/', 'comment.get', ['GET']),
|
||||
url('/comment/<re(".+"):path>/new', 'comment.create', ['POST']),
|
||||
url('/comment/<re(".+"):path>/<int:id>', 'comment.get', ['GET']),
|
||||
url('/comment/<re(".+"):path>/<int:id>', 'comment.modify', ['PUT', 'DELETE']),
|
||||
], converters={'re': utils.RegexConverter})
|
||||
|
||||
|
||||
class Isso:
|
||||
@ -59,7 +61,7 @@ class Isso:
|
||||
SQLITE = None
|
||||
|
||||
HOST = 'http://localhost:8000/'
|
||||
MAX_AGE = 15*60
|
||||
MAX_AGE = 15 * 60
|
||||
|
||||
def __init__(self, conf):
|
||||
|
||||
@ -101,5 +103,10 @@ class Isso:
|
||||
|
||||
def main():
|
||||
|
||||
app = Isso({'SQLITE': '/tmp/sqlite.db'})
|
||||
run_simple('127.0.0.1', 8080, app)
|
||||
from os.path import join, dirname
|
||||
from werkzeug.wsgi import SharedDataMiddleware
|
||||
|
||||
app = Isso({'SQLITE': '/tmp/sqlite.db', 'PRODUCTION': False})
|
||||
app = SharedDataMiddleware(app,{
|
||||
'/static': join(dirname(__file__), 'static')})
|
||||
run_simple('127.0.0.1', 8000, app, use_reloader=True)
|
||||
|
@ -13,7 +13,7 @@ from isso import json, models, utils
|
||||
|
||||
def create(app, environ, request, path):
|
||||
|
||||
if app.PRODUCTION and not utils.urlexists(app.HOST, path):
|
||||
if app.PRODUCTION and not utils.urlexists(app.HOST, '/' + path):
|
||||
return abort(404)
|
||||
|
||||
try:
|
||||
|
@ -99,7 +99,7 @@ class SQLite(Abstract):
|
||||
def add(self, path, c):
|
||||
with sqlite3.connect(self.dbpath) as con:
|
||||
keys = ','.join(self.fields)
|
||||
values = ','.join('?'*len(self.fields))
|
||||
values = ','.join('?' * len(self.fields))
|
||||
con.execute('INSERT INTO comments (%s) VALUES (%s);' % (keys, values), (
|
||||
0, path, c.created, c.modified, c.text, c.author, c.email, c.website,
|
||||
c.parent, self.mode)
|
||||
|
@ -8,6 +8,7 @@ import socket
|
||||
import httplib
|
||||
import urlparse
|
||||
import contextlib
|
||||
import werkzeug.routing
|
||||
|
||||
from isso.models import Comment
|
||||
|
||||
@ -21,6 +22,12 @@ class IssoEncoder(json.JSONEncoder):
|
||||
return json.JSONEncoder.default(self, obj)
|
||||
|
||||
|
||||
class RegexConverter(werkzeug.routing.BaseConverter):
|
||||
def __init__(self, url_map, *items):
|
||||
super(RegexConverter, self).__init__(url_map)
|
||||
self.regex = items[0]
|
||||
|
||||
|
||||
def urlexists(host, path):
|
||||
with contextlib.closing(httplib.HTTPConnection(host)) as con:
|
||||
try:
|
||||
|
@ -1,4 +1,5 @@
|
||||
|
||||
import urllib
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
@ -64,7 +65,7 @@ class TestComments(unittest.TestCase):
|
||||
def testGetInvalid(self):
|
||||
|
||||
assert self.get('/comment/path/123').status_code == 404
|
||||
assert self.get('/comment/path/spam').status_code == 404
|
||||
assert self.get('/comment/path/spam/123').status_code == 404
|
||||
assert self.get('/comment/foo/').status_code == 404
|
||||
|
||||
def testUpdate(self):
|
||||
@ -102,3 +103,15 @@ class TestComments(unittest.TestCase):
|
||||
|
||||
assert self.get('/comment/path/1').status_code == 200
|
||||
assert self.get('/comment/path/2').status_code == 200
|
||||
|
||||
def testPathVariations(self):
|
||||
|
||||
paths = ['/sub/path/', '/path.html', '/sub/path.html', '%2Fpath/%2F']
|
||||
|
||||
for path in paths:
|
||||
assert self.post('/comment/' + path + '/new',
|
||||
data=json.dumps(comment(text='...'))).status_code == 201
|
||||
|
||||
for path in paths:
|
||||
assert self.get('/comment/' + path)
|
||||
assert self.get('/comment/' + path + '/1')
|
||||
|
Loading…
Reference in New Issue
Block a user