Add HTTP content negotiation. Closes #10

master
Stephane Bortzmeyer 10 years ago
parent 11cd895adf
commit 66955cba01
  1. 59
      DNSLG/__init__.py
  2. 22
      README
  3. 4
      setup.py

@ -14,6 +14,10 @@ import dns.reversename
# http://code.google.com/p/netaddr/ https://github.com/drkjam/netaddr
import netaddr
# http://webob.org/
# Debian package python-webob
from webob import Request
# Internal modules
import Formatter
from LeakyBucket import LeakyBucket
@ -110,7 +114,7 @@ Disallow: /
send_response(start_response, '404 Not Found' , output, 'text/plain')
return [output]
def query(self, start_response, path, client, format="HTML", alt_resolver=None,
def query(self, start_response, req, path, client, format="", alt_resolver=None,
do_dnssec=False, tcp=False, cd=False, edns_size=default_edns_size,
reverse=False):
""" path must starts with a /, then the domain name then an
@ -119,22 +123,40 @@ Disallow: /
if not path.startswith('/'):
raise Exception("Internal error: no / at the beginning of %s" % path)
plaintype = 'text/plain; charset=%s' % self.encoding
if format == "TEXT" or format == "TXT":
format = "TEXT"
mtype = 'text/plain; charset=%s' % self.encoding
elif format == "HTML":
mtype = 'text/html; charset=%s' % self.encoding
elif format == "JSON":
mtype = 'application/json'
elif format == "ZONE":
mtype = 'text/dns' # RFC 4027
# TODO: application/dns, "detached" DNS (binary), see issue #20
elif format == "XML":
mtype = 'application/xml'
if not format:
mformat = req.accept.best_match(['text/html', 'application/xml',
'application/json', 'text/dns',
'text/plain'])
if mformat == "text/html":
format = "HTML"
elif mformat == "application/xml":
format = "XML"
elif mformat == "application/json":
format = "JSON"
elif mformat == "text/dns":
format = "ZONE"
elif mformat == "text/plain":
format = "TEXT"
if not mformat:
mformat = "text/html"
mtype = '%s; charset=%s' % (mformat, self.encoding)
else:
output = "Unsupported format \"%s\"\n" % format
send_response(start_response, '400 Bad request', output, plaintype)
return [output]
if format == "TEXT" or format == "TXT":
format = "TEXT"
mtype = 'text/plain; charset=%s' % self.encoding
elif format == "HTML":
mtype = 'text/html; charset=%s' % self.encoding
elif format == "JSON":
mtype = 'application/json'
elif format == "ZONE":
mtype = 'text/dns' # RFC 4027
# TODO: application/dns, "detached" DNS (binary), see issue #20
elif format == "XML":
mtype = 'application/xml'
else:
output = "Unsupported format \"%s\"\n" % format
send_response(start_response, '400 Bad request', output, plaintype)
return [output]
ip_client = netaddr.IPAddress(client)
if ip_client.version == 4:
ip_prefix = netaddr.IPNetwork(client + "/28")
@ -310,8 +332,6 @@ Disallow: /
resolver = None
resolver = queries.get("server", [''])[0]
format = queries.get("format", [''])[0].upper()
if format == "":
format = "HTML"
dodnssec = queries.get("dodnssec", '')
do_dnssec = not(len(dodnssec) == 0 or dodnssec[0] == "0" or \
dodnssec[0].lower() == "false" or dodnssec[0] == "")
@ -362,8 +382,7 @@ Disallow: /
# directive, 'Alias /robots.txt
# /usr/local/www/documents/robots.txt" etc.
pure_path = path[len(self.base_url):]
# TODO: content negotiation, see issue #10
return self.query(start_response, pure_path, client, format, resolver,
return self.query(start_response, Request(environ), pure_path, client, format, resolver,
do_dnssec, tcp, cd, edns_size, reverse)
else:
return self.default(start_response, path)

@ -54,11 +54,19 @@ URLs of this service are
There is a non-standard pseudo-querytype ADDR to request both A and
AAAA, specially for the links in the HTML output.
The default output format is HTML so you can use this program from an
ordinary Web browser. You can add the option format=FORMAT where
FORMAT is XML, HTML, TEXT, ZONE or JSON (see next section). So, for
instance, to get the IPv6 address of www.example.com in XML, it will
be <http://dns.example.net/www.example.com/AAAA?format=XML>
The default output format is determined by HTTP content negotiation,
so it depends on your client. You can use this program from an
ordinary Web browser, which will typically get HTML by default. With a
command-line client like curl, you can add the relevant header to get
the format you want;
curl -v -H 'Accept: application/json' $URLBASE/org/SOA
If content negotiation does not suit you, You can add in the URL the
option format=FORMAT where FORMAT is XML, HTML, TEXT, ZONE or JSON
(see next section). So, for instance, to get the IPv6 address of
www.example.com in XML, it will be
<http://dns.example.net/www.example.com/AAAA?format=XML>
You can add an option to select the name server to query (the default
one is choosen by the server, typically the default resolver(s) of the
@ -113,8 +121,8 @@ separators.
Requirments
***********
Requires Python, then SimpleTAL, dnspython and netaddr
Debian/Ubuntu: packages "python-netaddr python-dnspython python-simpletal"
Requires Python, then SimpleTAL, dnspython, webob and netaddr
Debian/Ubuntu: packages "python-netaddr python-dnspython python-webob python-simpletal"
Installation
************

@ -6,7 +6,7 @@ use_setuptools()
from setuptools import setup
setup(name='DNS-LG',
version='2013012101',
version='2013020201',
description='DNS Looking Glass',
license='BSD',
author='Stephane Bortzmeyer',
@ -15,7 +15,7 @@ setup(name='DNS-LG',
download_url='https://github.com/bortzmeyer/dns-lg/tarball/master',
packages=['DNSLG',],
provides=['DNSLG',],
install_requires=[] # We require netaddr, simpletal and
install_requires=[] # We require netaddr, simpletal, webob and
# dnspython but Python cannot find them,
# even when installed :-( Packaging in
# Python is completely broken, anyway

Loading…
Cancel
Save