From ef09bd8b7723ce2513b2417ce2b90ccb0fad282f Mon Sep 17 00:00:00 2001 From: cluke009 Date: Sun, 6 Jan 2013 02:08:36 -0500 Subject: [PATCH 1/2] Add preflight header support --- sleepymongoose/httpd.py | 46 +++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/sleepymongoose/httpd.py b/sleepymongoose/httpd.py index 53629d5..4a5bdfb 100644 --- a/sleepymongoose/httpd.py +++ b/sleepymongoose/httpd.py @@ -51,7 +51,7 @@ def __init__(self, server_address, HandlerClass): fpem = MongoServer.pem ctx.use_privatekey_file(fpem) ctx.use_certificate_file(fpem) - + self.socket = SSL.Connection(ctx, socket.socket(self.address_family, self.socket_type)) self.server_bind() @@ -76,8 +76,8 @@ class MongoHTTPRequest(BaseHTTPRequestHandler): jsonp_callback = None; def _parse_call(self, uri): - """ - this turns a uri like: /foo/bar/_query into properties: using the db + """ + this turns a uri like: /foo/bar/_query into properties: using the db foo, the collection bar, executing a query. returns the database, collection, and action @@ -117,7 +117,7 @@ def call_handler(self, uri, args): self.jsonp_callback = args["callback"][0] else: self.jsonp_callback = args.getvalue("callback") - + func = getattr(MongoHandler.mh, func_name, None) if callable(func): self.send_response(200, 'OK') @@ -134,12 +134,12 @@ def call_handler(self, uri, args): return else: self.send_error(404, 'Script Not Found: '+uri) - return - + return + def prependJSONPCallback(self, str): jsonp_output = '%s(' % self.jsonp_callback + str + ')' self.wfile.write( jsonp_output ) - + # TODO: check for ..s def process_uri(self, method): if method == "GET": @@ -175,10 +175,10 @@ def process_uri(self, method): return (uri, args, type) - def do_GET(self): + def do_GET(self): (uri, args, type) = self.process_uri("GET") - + # serve up a plain file if len(type) != 0: if type in MongoHTTPRequest.mimetypes and os.path.exists(MongoHTTPRequest.docroot+uri): @@ -216,6 +216,24 @@ def do_POST(self): return self.call_handler(uri, args) + def do_OPTIONS(self): + (uri, args, type) = self.process_uri("OPTIONS") + + if self.process_uri("OPTIONS"): + + self.send_response(200, 'OK') + + for header in self.response_headers: + self.send_header(header[0], header[1]) + self.end_headers() + + return + + else: + self.send_error(404, 'File Not Found: '+uri) + + return + @staticmethod def serve_forever(port): print "\n=================================" @@ -236,7 +254,7 @@ def serve_forever(port): server = MongoServer(('', port), MongoHTTPSRequest) MongoHandler.mh = MongoHandler(MongoHTTPRequest.mongos) - + print "listening for connections on http://localhost:27080\n" try: server.serve_forever() @@ -256,6 +274,7 @@ def setup(self): def usage(): print "python httpd.py [-x] [-d docroot/dir] [-s certificate.pem] [-m list,of,mongods]" print "\t-x|--xorigin\tAllow cross-origin http requests" + print "\t-p|--preflight\tAdds preflight header support" print "\t-d|--docroot\tlocation from which to load files" print "\t-s|--secure\tlocation of .pem file if ssl is desired" print "\t-m|--mongos\tcomma-separated list of mongo servers to connect to" @@ -263,8 +282,8 @@ def usage(): def main(): try: - opts, args = getopt.getopt(sys.argv[1:], "xd:s:m:", ["xorigin", "docroot=", - "secure=", "mongos="]) + opts, args = getopt.getopt(sys.argv[1:], "xpd:s:m:", ["xorigin", "docroot=", + "secure=", "mongos=", "preflight"]) for o, a in opts: if o == "-d" or o == "--docroot": @@ -277,6 +296,8 @@ def main(): MongoHTTPRequest.mongos = a.split(',') if o == "-x" or o == "--xorigin": MongoHTTPRequest.response_headers.append(("Access-Control-Allow-Origin","*")) + if o == "-p" or o == "--preflight": + MongoHTTPRequest.response_headers.append(("Access-Control-Allow-Headers","X-Requested-With, Content-Type")) except getopt.GetoptError: print "error parsing cmd line args." @@ -286,4 +307,3 @@ def main(): MongoHTTPRequest.serve_forever(27080) if __name__ == "__main__": main() - From 5cb3821d318e6a0f68a85a18dc457274f61b4f05 Mon Sep 17 00:00:00 2001 From: cluke009 Date: Tue, 19 Feb 2013 08:59:10 -0500 Subject: [PATCH 2/2] Update preflight support --- sleepymongoose/handlers.py | 42 +++++++++++++++++++------------------- sleepymongoose/httpd.py | 11 +++------- 2 files changed, 24 insertions(+), 29 deletions(-) diff --git a/sleepymongoose/handlers.py b/sleepymongoose/handlers.py index 0e6a9b0..721fe5d 100644 --- a/sleepymongoose/handlers.py +++ b/sleepymongoose/handlers.py @@ -38,18 +38,18 @@ def __init__(self, mongos): if len(mongos) == 1: name = "default" else: - name = host.replace(".", "") + name = host.replace(".", "") name = name.replace(":", "") self._connect(args, out.ostream, name = name) - + def _get_connection(self, name = None, uri='mongodb://localhost:27017'): if name == None: name = "default" if name in self.connections: return self.connections[name] - + try: connection = Connection(uri, network_timeout = 2) except (ConnectionFailure, ConfigurationError): @@ -98,7 +98,7 @@ def _get_son(self, str, out): if getattr(obj, '__iter__', False) == False: out('{"ok" : 0, "errmsg" : "type is not iterable: %s"}' % str) return None - + return obj @@ -130,13 +130,13 @@ def _cmd(self, args, out, name = None, db = None, collection = None): result['cmd'] = args.getvalue('cmd') out(json.dumps(result, default=json_util.default)) - + def _hello(self, args, out, name = None, db = None, collection = None): - out('{"ok" : 1, "msg" : "Uh, we had a slight weapons malfunction, but ' + + out('{"ok" : 1, "msg" : "Uh, we had a slight weapons malfunction, but ' + 'uh... everything\'s perfectly all right now. We\'re fine. We\'re ' + 'all fine here now, thank you. How are you?"}') return - + def _status(self, args, out, name = None, db = None, collection = None): result = {"ok" : 1, "connections" : {}} @@ -144,7 +144,7 @@ def _status(self, args, out, name = None, db = None, collection = None): result['connections'][name] = "%s:%d" % (conn.host, conn.port) out(json.dumps(result)) - + def _connect(self, args, out, name = None, db = None, collection = None): """ connect to a mongod @@ -197,12 +197,12 @@ def _authenticate(self, args, out, name = None, db = None, collection = None): if not 'password' in args: out('{"ok" : 0, "errmsg" : "password must be defined"}') - + if not conn[db].authenticate(args.getvalue('username'), args.getvalue('password')): out('{"ok" : 0, "errmsg" : "authentication failed"}') else: out('{"ok" : 1}') - + def _find(self, args, out, name = None, db = None, collection = None): """ query the database. @@ -219,7 +219,7 @@ def _find(self, args, out, name = None, db = None, collection = None): if db == None or collection == None: out('{"ok" : 0, "errmsg" : "db and collection must be defined"}') - return + return criteria = {} if 'criteria' in args: @@ -276,7 +276,7 @@ def _find(self, args, out, name = None, db = None, collection = None): batch_size = 15 if 'batch_size' in args: batch_size = int(args['batch_size'][0]) - + self.__output_results(cursor, out, batch_size) @@ -328,7 +328,7 @@ def __output_results(self, cursor, out, batch_size=15): except StopIteration: # this is so stupid, there's no has_next? pass - + out(json.dumps({"results" : batch, "id" : cursor.id, "ok" : 1}, default=json_util.default)) @@ -350,7 +350,7 @@ def _insert(self, args, out, name = None, db = None, collection = None): out('{"ok" : 0, "errmsg" : "db and collection must be defined"}') return - if "docs" not in args: + if "docs" not in args: out('{"ok" : 0, "errmsg" : "missing docs"}') return @@ -399,8 +399,8 @@ def _update(self, args, out, name = None, db = None, collection = None): if db == None or collection == None: out('{"ok" : 0, "errmsg" : "db and collection must be defined"}') return - - if "criteria" not in args: + + if "criteria" not in args: out('{"ok" : 0, "errmsg" : "missing criteria"}') return criteria = self._get_son(args.getvalue('criteria'), out) @@ -413,7 +413,7 @@ def _update(self, args, out, name = None, db = None, collection = None): newobj = self._get_son(args.getvalue('newobj'), out) if newobj == None: return - + upsert = False if "upsert" in args: upsert = bool(args.getvalue('upsert')) @@ -443,13 +443,13 @@ def _remove(self, args, out, name = None, db = None, collection = None): if db == None or collection == None: out('{"ok" : 0, "errmsg" : "db and collection must be defined"}') return - + criteria = {} if "criteria" in args: criteria = self._get_son(args.getvalue('criteria'), out) if criteria == None: return - + result = conn[db][collection].remove(criteria) self.__safety_check(args, out, conn[db]) @@ -478,7 +478,7 @@ def _batch(self, args, out, name = None, db = None, collection = None): method = "GET" if 'method' in request: method = request['method'] - + db = None if 'db' in request: db = request['db'] @@ -511,7 +511,7 @@ def _batch(self, args, out, name = None, db = None, collection = None): out("]") - + class MongoFakeStream: def __init__(self): self.str = "" diff --git a/sleepymongoose/httpd.py b/sleepymongoose/httpd.py index 4a5bdfb..dd5d39e 100644 --- a/sleepymongoose/httpd.py +++ b/sleepymongoose/httpd.py @@ -178,7 +178,6 @@ def process_uri(self, method): def do_GET(self): (uri, args, type) = self.process_uri("GET") - # serve up a plain file if len(type) != 0: if type in MongoHTTPRequest.mimetypes and os.path.exists(MongoHTTPRequest.docroot+uri): @@ -219,7 +218,7 @@ def do_POST(self): def do_OPTIONS(self): (uri, args, type) = self.process_uri("OPTIONS") - if self.process_uri("OPTIONS"): + if uri == None: self.send_response(200, 'OK') @@ -227,13 +226,9 @@ def do_OPTIONS(self): self.send_header(header[0], header[1]) self.end_headers() - return - else: self.send_error(404, 'File Not Found: '+uri) - return - @staticmethod def serve_forever(port): print "\n=================================" @@ -282,8 +277,8 @@ def usage(): def main(): try: - opts, args = getopt.getopt(sys.argv[1:], "xpd:s:m:", ["xorigin", "docroot=", - "secure=", "mongos=", "preflight"]) + opts, args = getopt.getopt(sys.argv[1:], "xpd:s:m:", ["xorigin", "preflight", "docroot=", + "secure=", "mongos="]) for o, a in opts: if o == "-d" or o == "--docroot":