aboutsummaryrefslogtreecommitdiffstats
path: root/libbe/command/serve.py
diff options
context:
space:
mode:
authorW. Trevor King <wking@drexel.edu>2010-01-01 16:11:48 -0500
committerW. Trevor King <wking@drexel.edu>2010-01-01 16:11:48 -0500
commitecc2dd71287b46db316d8ef050a0bdb22bfc0fa5 (patch)
tree6ce92f20a73ef8c721aab94877ff1ad28340a30a /libbe/command/serve.py
parent4112da95162240eae73b00f53078451f5b38d610 (diff)
downloadbugseverywhere-ecc2dd71287b46db316d8ef050a0bdb22bfc0fa5.tar.gz
Improved POST and error handling in `be serve`
POST handling: Drop the cgi.FieldStorage() in favor of the old urlparse.parse_qs(). We need a dictionary, which FieldStorage is not. However, I added .read_post_data() since my old self.rfile.read() was hanging. The read_post_data() implementation comes from the FieldStorage.__init__(). Error handling: wrap .handle_*() blocks in try/except to handle Storage errors
Diffstat (limited to 'libbe/command/serve.py')
-rw-r--r--libbe/command/serve.py65
1 files changed, 43 insertions, 22 deletions
diff --git a/libbe/command/serve.py b/libbe/command/serve.py
index 9afaa90..1aa2305 100644
--- a/libbe/command/serve.py
+++ b/libbe/command/serve.py
@@ -18,7 +18,6 @@
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
import BaseHTTPServer as server
-import cgi
import posixpath
import urllib
import urlparse
@@ -32,6 +31,10 @@ HTTP_USER_ERROR = 418
STORAGE = None
COMMAND = None
+# Maximum input we will accept when REQUEST_METHOD is POST
+# 0 ==> unlimited input
+MAXLEN = 0
+
class BERequestHandler (server.BaseHTTPRequestHandler):
"""Simple HTTP request handler for serving the
libbe.storage.http.HTTP backend with GET, POST, and HEAD commands.
@@ -61,16 +64,23 @@ class BERequestHandler (server.BaseHTTPRequestHandler):
return None
data = self.parse_query(query)
- if path == ['children']:
- content,ctype = self.handle_children(data)
- elif len(path) > 1 and path[0] == 'get':
- content,ctype = self.handle_get('/'.join(path[1:]), data)
- elif path == ['revision-id']:
- content,ctype = self.handle_revision_id(data)
- elif path == ['version']:
- content,ctype = self.handle_version(data)
- else:
- self.send_error(400, 'File not found')
+ try:
+ if path == ['children']:
+ content,ctype = self.handle_children(data)
+ elif len(path) > 1 and path[0] == 'get':
+ content,ctype = self.handle_get('/'.join(path[1:]), data)
+ elif path == ['revision-id']:
+ content,ctype = self.handle_revision_id(data)
+ elif path == ['version']:
+ content,ctype = self.handle_version(data)
+ else:
+ self.send_error(400, 'File not found')
+ return None
+ except libbe.storage.NotReadable, e:
+ self.send_error(403, 'Read permission denied')
+ return None
+ except libbe.storage.InvalidID, e:
+ self.send_error(HTTP_USER_ERROR, 'InvalidID %s' % e)
return None
if content != None:
self.send_header('Content-type', ctype)
@@ -88,12 +98,8 @@ class BERequestHandler (server.BaseHTTPRequestHandler):
self.s = STORAGE
self.c = COMMAND
self.log_request('POST')
- data = cgi.FieldStorage(
- fp=self.rfile,
- headers=self.headers,
- environ={'REQUEST_METHOD':'POST',
- 'CONTENT_TYPE':self.headers['Content-Type'],
- })
+ post_data = self.read_post_data()
+ data = self.parse_post(post_data)
path,query,fragment = self.parse_path(self.path)
if query != '':
self.send_error(
@@ -118,6 +124,10 @@ class BERequestHandler (server.BaseHTTPRequestHandler):
except libbe.storage.NotWriteable, e:
self.send_error(403, 'Write permission denied')
return None
+ except libbe.storage.InvalidID, e:
+ raise
+ self.send_error(HTTP_USER_ERROR, 'InvalidID %s' % e)
+ return None
if content != None:
self.send_header('Content-type', ctype)
self.send_header('Content-Length', len(content))
@@ -184,11 +194,7 @@ class BERequestHandler (server.BaseHTTPRequestHandler):
if not 'revision' in data or data['revision'] == 'None':
data['revision'] = None
revision = data['revision']
- try:
- content = self.s.get(id, revision)
- except libbe.storage.InvalidID, e:
- self.send_error(HTTP_USER_ERROR, 'InvalidID %s' % e)
- return None
+ content = self.s.get(id, revision)
be_version = self.s.storage_version(revision)
ctype = 'application/octet-stream'
self.send_response(200)
@@ -262,6 +268,21 @@ class BERequestHandler (server.BaseHTTPRequestHandler):
data[k] = v[0]
return data
+ def parse_post(self, post):
+ return self.parse_query(post)
+
+ def read_post_data(self):
+ clen = -1
+ if 'content-length' in self.headers:
+ try:
+ clen = int(self.headers['content-length'])
+ except ValueError:
+ pass
+ if MAXLEN > 0 and clen > MAXLEN:
+ raise ValueError, 'Maximum content length exceeded'
+ post_data = self.rfile.read(clen)
+ return post_data
+
class Serve (libbe.command.Command):
"""Serve a Storage backend for the HTTP storage client