aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rpki/http_simple.py78
-rw-r--r--rpki/irdbd.py18
-rw-r--r--rpki/old_irdbd.py25
-rw-r--r--rpki/pubd.py41
-rw-r--r--rpki/publication_control.py52
-rw-r--r--rpki/xml_utils.py14
6 files changed, 138 insertions, 90 deletions
diff --git a/rpki/http_simple.py b/rpki/http_simple.py
new file mode 100644
index 00000000..d50fd993
--- /dev/null
+++ b/rpki/http_simple.py
@@ -0,0 +1,78 @@
+# $Id$
+
+# Copyright (C) 2014 Dragon Research Labs ("DRL")
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND DRL DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL DRL BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+"""
+HTTP using Python standard libraries, for RPKI programs that don't
+need the full-blown rpki.http asynchronous code.
+"""
+
+import logging
+import BaseHTTPServer
+
+logger = logging.getLogger(__name__)
+
+
+rpki_content_type = "application/x-rpki"
+
+
+class HTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
+ """
+ HTTP request handler simple RPKI servers.
+ """
+
+ def do_POST(self):
+ try:
+ content_type = self.headers.get("Content-Type")
+ content_length = self.headers.get("Content-Length")
+ if content_type != rpki_content_type:
+ self.send_error(415, "No handler for Content-Type %s" % content_type)
+ else:
+ for prefix, handler in self.rpki_handlers:
+ if self.path.startswith(prefix):
+ handler(self, (self.rfile.read()
+ if content_length is None else
+ self.rfile.read(int(content_length))))
+ break
+ else:
+ self.send_error(404, "No handler for path %s" % self.path)
+ except Exception, e:
+ logger.exception("Unhandled exception")
+ self.send_error(501, "Unhandled exception")
+
+ def send_cms_response(self, der):
+ self.send_response(200)
+ self.send_header("Content-Type", rpki_content_type)
+ self.send_header("Content-Length", str(len(der)))
+ self.end_headers()
+ self.wfile.write(der)
+
+ def log_message(self, *args):
+ # Might want to use LogAdapter for connection info here?
+ logger.info(*args)
+
+
+def server(handlers, port, host = ""):
+ """
+ Run an HTTP server and wait (forever) for connections.
+ """
+
+ if not isinstance(handlers, (tuple, list)):
+ handlers = (("/", handlers),)
+
+ class RequestHandler(HTTPRequestHandler):
+ rpki_handlers = handlers
+
+ BaseHTTPServer.HTTPServer((host, port), RequestHandler).serve_forever()
diff --git a/rpki/irdbd.py b/rpki/irdbd.py
index d53ae67c..bfc48d87 100644
--- a/rpki/irdbd.py
+++ b/rpki/irdbd.py
@@ -26,7 +26,7 @@ import time
import logging
import argparse
import urlparse
-import rpki.http
+import rpki.http_simple
import rpki.config
import rpki.resource_set
import rpki.relaxng
@@ -104,7 +104,7 @@ class main(object):
r_pdu.pkcs10 = ee_req.pkcs10
r_msg.append(r_pdu)
- def handler(self, query, path, cb):
+ def handler(self, request, q_der):
try:
q_pdu = None
r_msg = rpki.left_right.msg.reply()
@@ -114,15 +114,13 @@ class main(object):
serverCA = rpki.irdb.ServerCA.objects.get()
rpkid = serverCA.ee_certificates.get(purpose = "rpkid")
try:
- q_cms = rpki.left_right.cms_msg(DER = query)
+ q_cms = rpki.left_right.cms_msg(DER = q_der)
q_msg = q_cms.unwrap((serverCA.certificate, rpkid.certificate))
- self.cms_timestamp = q_cms.check_replay(self.cms_timestamp, path)
+ self.cms_timestamp = q_cms.check_replay(self.cms_timestamp, request.path)
if not isinstance(q_msg, rpki.left_right.msg) or not q_msg.is_query():
raise rpki.exceptions.BadQuery("Unexpected %r PDU" % q_msg)
for q_pdu in q_msg:
self.dispatch(q_pdu, r_msg)
- except (rpki.async.ExitNow, SystemExit):
- raise
except Exception, e:
logger.exception("Exception while handling HTTP request")
if q_pdu is None:
@@ -130,12 +128,10 @@ class main(object):
else:
r_msg.append(rpki.left_right.report_error_elt.from_exception(e, q_pdu.self_handle, q_pdu.tag))
irdbd = serverCA.ee_certificates.get(purpose = "irdbd")
- cb(200, body = rpki.left_right.cms_msg().wrap(r_msg, irdbd.private_key, irdbd.certificate))
- except (rpki.async.ExitNow, SystemExit):
- raise
+ request.send_cms_response(rpki.left_right.cms_msg().wrap(r_msg, irdbd.private_key, irdbd.certificate))
except Exception, e:
logger.exception("Unhandled exception while processing HTTP request")
- cb(500, reason = "Unhandled exception %s: %s" % (e.__class__.__name__, e))
+ request.send_error(500, "Unhandled exception %s: %s" % (e.__class__.__name__, e))
def dispatch(self, q_pdu, r_msg):
try:
@@ -261,7 +257,7 @@ class main(object):
self.cms_timestamp = None
- rpki.http.server(
+ rpki.http_simple.server(
host = self.http_server_host,
port = self.http_server_port,
handlers = self.handler)
diff --git a/rpki/old_irdbd.py b/rpki/old_irdbd.py
index 6c026a31..a2ce4e94 100644
--- a/rpki/old_irdbd.py
+++ b/rpki/old_irdbd.py
@@ -30,7 +30,7 @@ import time
import logging
import argparse
import urlparse
-import rpki.http
+import rpki.http_simple
import rpki.config
import rpki.resource_set
import rpki.relaxng
@@ -226,7 +226,7 @@ class main(object):
rpki.left_right.list_ghostbuster_requests_elt : handle_list_ghostbuster_requests,
rpki.left_right.list_ee_certificate_requests_elt : handle_list_ee_certificate_requests }
- def handler(self, query, path, cb):
+ def handler(self, request, q_der):
try:
self.db.ping(True)
@@ -235,7 +235,7 @@ class main(object):
try:
- q_msg = rpki.left_right.cms_msg(DER = query).unwrap((self.bpki_ta, self.rpkid_cert))
+ q_msg = rpki.left_right.cms_msg(DER = q_der).unwrap((self.bpki_ta, self.rpkid_cert))
if not isinstance(q_msg, rpki.left_right.msg) or not q_msg.is_query():
raise rpki.exceptions.BadQuery("Unexpected %r PDU" % q_msg)
@@ -251,28 +251,19 @@ class main(object):
else:
h(self, q_pdu, r_msg)
- except (rpki.async.ExitNow, SystemExit):
- raise
-
except Exception, e:
logger.exception("Exception serving PDU %r", q_pdu)
r_msg.append(rpki.left_right.report_error_elt.from_exception(e, q_pdu.self_handle, q_pdu.tag))
- except (rpki.async.ExitNow, SystemExit):
- raise
-
except Exception, e:
logger.exception("Exception decoding query")
r_msg.append(rpki.left_right.report_error_elt.from_exception(e))
- cb(200, body = rpki.left_right.cms_msg().wrap(r_msg, self.irdbd_key, self.irdbd_cert))
-
- except (rpki.async.ExitNow, SystemExit):
- raise
+ request.send_cms_response(rpki.left_right.cms_msg().wrap(r_msg, self.irdbd_key, self.irdbd_cert))
except Exception, e:
logger.exception("Unhandled exception, returning HTTP failure")
- cb(500, reason = "Unhandled exception %s: %s" % (e.__class__.__name__, e))
+ request.send_error(500, "Unhandled exception %s: %s" % (e.__class__.__name__, e))
def __init__(self):
@@ -319,6 +310,6 @@ class main(object):
u.query == "" and \
u.fragment == ""
- rpki.http.server(host = u.hostname or "localhost",
- port = u.port or 443,
- handlers = ((u.path, self.handler),))
+ rpki.http_simple.server(host = u.hostname or "localhost",
+ port = u.port or 443,
+ handlers = ((u.path, self.handler),))
diff --git a/rpki/pubd.py b/rpki/pubd.py
index b6788ebd..a2f996b6 100644
--- a/rpki/pubd.py
+++ b/rpki/pubd.py
@@ -28,11 +28,11 @@ import time
import socket
import logging
import argparse
+
import rpki.resource_set
import rpki.up_down
import rpki.x509
import rpki.sql
-import rpki.http
import rpki.config
import rpki.exceptions
import rpki.relaxng
@@ -40,6 +40,7 @@ import rpki.log
import rpki.publication
import rpki.publication_control
import rpki.daemonize
+import rpki.http_simple
from lxml.etree import Element, SubElement, tostring as ElementToString
@@ -50,6 +51,8 @@ rrdp_xmlns = rpki.relaxng.rrdp.xmlns
rrdp_nsmap = rpki.relaxng.rrdp.nsmap
rrdp_version = "1"
+rpki_content_type = "application/x-rpki"
+
def DERSubElement(elt, name, der, attrib = None, **kwargs):
"""
@@ -133,7 +136,7 @@ class main(object):
self.session = session_obj.fetch(self)
- rpki.http.server(
+ rpki.http_simple.server(
host = self.http_server_host,
port = self.http_server_port,
handlers = (("/control", self.control_handler),
@@ -144,44 +147,41 @@ class main(object):
return "%s/%s" % (self.rrdp_uri_base.rstrip("/"), fn)
- def control_handler(self, query, path, cb):
+ def control_handler(self, request, q_der):
"""
Process one PDU from the IRBE.
"""
def done(r_msg):
self.sql.sweep()
- cb(code = 200,
- body = rpki.publication_control.cms_msg().wrap(r_msg, self.pubd_key, self.pubd_cert))
+ request.send_cms_response(rpki.publication_control.cms_msg().wrap(r_msg, self.pubd_key, self.pubd_cert))
try:
- q_cms = rpki.publication_control.cms_msg(DER = query)
+ q_cms = rpki.publication_control.cms_msg(DER = q_der)
q_msg = q_cms.unwrap((self.bpki_ta, self.irbe_cert))
self.irbe_cms_timestamp = q_cms.check_replay(self.irbe_cms_timestamp, "control")
q_msg.serve_top_level(self, done)
- except (rpki.async.ExitNow, SystemExit):
- raise
except Exception, e:
- logger.exception("Unhandled exception processing control query, path %r", path)
- cb(code = 500, reason = "Unhandled exception %s: %s" % (e.__class__.__name__, e))
+ logger.exception("Unhandled exception processing control query, path %r", request.path)
+ request.send_error(500, "Unhandled exception %s: %s" % (e.__class__.__name__, e))
client_url_regexp = re.compile("/client/([-A-Z0-9_/]+)$", re.I)
- def client_handler(self, query, path, cb):
+ def client_handler(self, request, q_der):
"""
Process one PDU from a client.
"""
try:
- match = self.client_url_regexp.search(path)
+ match = self.client_url_regexp.search(request.path)
if match is None:
- raise rpki.exceptions.BadContactURL("Bad path: %s" % path)
+ raise rpki.exceptions.BadContactURL("Bad path: %s" % request.path)
client_handle = match.group(1)
client = rpki.publication_control.client_elt.sql_fetch_where1(self, "client_handle = %s", (client_handle,))
if client is None:
raise rpki.exceptions.ClientNotFound("Could not find client %s" % client_handle)
- q_cms = rpki.publication.cms_msg(DER = query)
+ q_cms = rpki.publication.cms_msg(DER = q_der)
q_msg = q_cms.unwrap((self.bpki_ta, client.bpki_cert, client.bpki_glue))
q_cms.check_replay_sql(client, client.client_handle)
if not q_msg.is_query():
@@ -209,8 +209,6 @@ class main(object):
r_pdu.tag = q_pdu.tag
r_pdu.uri = q_pdu.uri
r_msg.append(r_pdu)
- except (rpki.async.ExitNow, SystemExit):
- raise
except Exception, e:
if not isinstance(e, rpki.exceptions.NotFound):
logger.exception("Exception processing PDU %r", q_pdu)
@@ -246,14 +244,11 @@ class main(object):
# database of record. This may require doing the filesystem
# updates from the delta, but that should be straightforward.
- cb(code = 200,
- body = rpki.publication.cms_msg().wrap(r_msg, self.pubd_key, self.pubd_cert, self.pubd_crl))
- except (rpki.async.ExitNow, SystemExit):
- raise
+ request.send_cms_response(rpki.publication.cms_msg().wrap(r_msg, self.pubd_key, self.pubd_cert, self.pubd_crl))
+
except Exception, e:
- logger.exception("Unhandled exception processing client query, path %r", path)
- cb(code = 500,
- reason = "Could not process PDU: %s" % e)
+ logger.exception("Unhandled exception processing client query, path %r", request.path)
+ request.send_error(500, "Could not process PDU: %s" % e)
def uri_to_filename(self, uri):
"""
diff --git a/rpki/publication_control.py b/rpki/publication_control.py
index 95751336..ab56f95f 100644
--- a/rpki/publication_control.py
+++ b/rpki/publication_control.py
@@ -1,32 +1,21 @@
# $Id$
#
-# Copyright (C) 2009--2012 Internet Systems Consortium ("ISC")
-#
-# Permission to use, copy, modify, and distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-# PERFORMANCE OF THIS SOFTWARE.
-#
+# Copyright (C) 2013--2014 Dragon Research Labs ("DRL")
+# Portions copyright (C) 2009--2012 Internet Systems Consortium ("ISC")
# Portions copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN")
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
+# copyright notices and this permission notice appear in all copies.
#
-# THE SOFTWARE IS PROVIDED "AS IS" AND ARIN DISCLAIMS ALL WARRANTIES WITH
-# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-# AND FITNESS. IN NO EVENT SHALL ARIN BE LIABLE FOR ANY SPECIAL, DIRECT,
-# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-# PERFORMANCE OF THIS SOFTWARE.
+# THE SOFTWARE IS PROVIDED "AS IS" AND DRL, ISC, AND ARIN DISCLAIM ALL
+# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DRL,
+# ISC, OR ARIN BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
"""
RPKI publication control protocol.
@@ -208,26 +197,25 @@ class msg(rpki.xml_utils.msg, publication_control_namespace):
raise rpki.exceptions.BadQuery("Message type is not query")
r_msg = self.__class__.reply()
- def loop(iterator, q_pdu):
+ for q_pdu in self:
+
+ def next():
+ # Relic of asynch I/O structure, clean up eventually
+ pass
def fail(e):
if not isinstance(e, rpki.exceptions.NotFound):
logger.exception("Exception processing PDU %r", q_pdu)
r_msg.append(report_error_elt.from_exception(e, q_pdu.tag))
- cb(r_msg)
+ return cb(r_msg)
try:
q_pdu.gctx = gctx
- q_pdu.serve_dispatch(r_msg, iterator, fail)
- except (rpki.async.ExitNow, SystemExit):
- raise
+ q_pdu.serve_dispatch(r_msg, next, fail)
except Exception, e:
- fail(e)
-
- def done():
- cb(r_msg)
+ return fail(e)
- rpki.async.iterator(self, loop, done)
+ return cb(r_msg)
class sax_handler(rpki.xml_utils.sax_handler):
diff --git a/rpki/xml_utils.py b/rpki/xml_utils.py
index 3a7b919a..9b443d0b 100644
--- a/rpki/xml_utils.py
+++ b/rpki/xml_utils.py
@@ -32,11 +32,15 @@
XML utilities.
"""
+import logging
import xml.sax
import lxml.sax
import lxml.etree
import rpki.exceptions
+logger = logging.getLogger(__name__)
+
+
class sax_handler(xml.sax.handler.ContentHandler):
"""
SAX handler for RPKI protocols.
@@ -435,14 +439,10 @@ class data_elt(base_elt):
Action dispatch handler.
"""
- dispatch = { "create" : self.serve_create,
- "set" : self.serve_set,
- "get" : self.serve_get,
- "list" : self.serve_list,
- "destroy" : self.serve_destroy }
- if self.action not in dispatch:
+ method = getattr(self, "serve_" + self.action, None)
+ if method is None:
raise rpki.exceptions.BadQuery("Unexpected query: action %s" % self.action)
- dispatch[self.action](r_msg, cb, eb)
+ method(r_msg, cb, eb)
def unimplemented_control(self, *controls):
"""