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
|
# Isso – a lightweight Disqus alternative
|
||||||
|
|
||||||
__version__ = '0.1'
|
__version__ = '0.2'
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
@ -33,22 +33,24 @@ from werkzeug.exceptions import HTTPException, NotFound, InternalServerError
|
|||||||
|
|
||||||
from isso import admin, comment, db, utils
|
from isso import admin, comment, db, utils
|
||||||
|
|
||||||
|
# override default json :func:`dumps`.
|
||||||
_dumps = json.dumps
|
_dumps = json.dumps
|
||||||
setattr(json, 'dumps', lambda obj, **kw: _dumps(obj, cls=utils.IssoEncoder, **kw))
|
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 = lambda path, endpoint, methods: Rule(path, endpoint=endpoint, methods=methods)
|
||||||
|
|
||||||
url_map = Map([
|
url_map = Map([
|
||||||
# moderation panel
|
# moderation panel
|
||||||
url('/', 'admin.index', ['GET', 'POST']),
|
url('/', 'admin.index', ['GET', 'POST']),
|
||||||
|
|
||||||
# comments API
|
# comment API, note that the client side quotes the URL, but this is
|
||||||
url('/comment/<string:path>/', 'comment.get', ['GET']),
|
# actually unnecessary. PEP 333 aka WSGI always unquotes PATH_INFO.
|
||||||
url('/comment/<string:path>/new', 'comment.create', ['POST']),
|
url('/comment/<re(".+"):path>/', 'comment.get', ['GET']),
|
||||||
url('/comment/<string:path>/<int:id>', 'comment.get', ['GET']),
|
url('/comment/<re(".+"):path>/new', 'comment.create', ['POST']),
|
||||||
url('/comment/<string:path>/<int:id>', 'comment.modify', ['PUT', 'DELETE']),
|
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:
|
class Isso:
|
||||||
@ -59,7 +61,7 @@ class Isso:
|
|||||||
SQLITE = None
|
SQLITE = None
|
||||||
|
|
||||||
HOST = 'http://localhost:8000/'
|
HOST = 'http://localhost:8000/'
|
||||||
MAX_AGE = 15*60
|
MAX_AGE = 15 * 60
|
||||||
|
|
||||||
def __init__(self, conf):
|
def __init__(self, conf):
|
||||||
|
|
||||||
@ -101,5 +103,10 @@ class Isso:
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
||||||
app = Isso({'SQLITE': '/tmp/sqlite.db'})
|
from os.path import join, dirname
|
||||||
run_simple('127.0.0.1', 8080, app)
|
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):
|
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)
|
return abort(404)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -99,7 +99,7 @@ class SQLite(Abstract):
|
|||||||
def add(self, path, c):
|
def add(self, path, c):
|
||||||
with sqlite3.connect(self.dbpath) as con:
|
with sqlite3.connect(self.dbpath) as con:
|
||||||
keys = ','.join(self.fields)
|
keys = ','.join(self.fields)
|
||||||
values = ','.join('?'*len(self.fields))
|
values = ','.join('?' * len(self.fields))
|
||||||
con.execute('INSERT INTO comments (%s) VALUES (%s);' % (keys, values), (
|
con.execute('INSERT INTO comments (%s) VALUES (%s);' % (keys, values), (
|
||||||
0, path, c.created, c.modified, c.text, c.author, c.email, c.website,
|
0, path, c.created, c.modified, c.text, c.author, c.email, c.website,
|
||||||
c.parent, self.mode)
|
c.parent, self.mode)
|
||||||
|
@ -8,6 +8,7 @@ import socket
|
|||||||
import httplib
|
import httplib
|
||||||
import urlparse
|
import urlparse
|
||||||
import contextlib
|
import contextlib
|
||||||
|
import werkzeug.routing
|
||||||
|
|
||||||
from isso.models import Comment
|
from isso.models import Comment
|
||||||
|
|
||||||
@ -21,6 +22,12 @@ class IssoEncoder(json.JSONEncoder):
|
|||||||
return json.JSONEncoder.default(self, obj)
|
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):
|
def urlexists(host, path):
|
||||||
with contextlib.closing(httplib.HTTPConnection(host)) as con:
|
with contextlib.closing(httplib.HTTPConnection(host)) as con:
|
||||||
try:
|
try:
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
|
|
||||||
|
import urllib
|
||||||
import tempfile
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
@ -64,7 +65,7 @@ class TestComments(unittest.TestCase):
|
|||||||
def testGetInvalid(self):
|
def testGetInvalid(self):
|
||||||
|
|
||||||
assert self.get('/comment/path/123').status_code == 404
|
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
|
assert self.get('/comment/foo/').status_code == 404
|
||||||
|
|
||||||
def testUpdate(self):
|
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/1').status_code == 200
|
||||||
assert self.get('/comment/path/2').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