Fixed #7735 -- Added support for IPv6 adresses to runserver and testserver management command. Thanks to Jason Alonso and Łukasz Rekucki for the report and initial patches.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@14711 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Jannis Leidel 2010-11-26 13:33:53 +00:00
parent 132afbf8ee
commit 6a32e253f6
5 changed files with 82 additions and 27 deletions

View File

@ -1,14 +1,21 @@
from optparse import make_option
import os
import re
import sys
import socket
from django.core.management.base import BaseCommand, CommandError
from django.core.handlers.wsgi import WSGIHandler
from django.core.servers.basehttp import AdminMediaHandler, run, WSGIServerException
from django.utils import autoreload
naiveip_re = r'^(?:(?P<addr>\d{1,3}(?:\.\d{1,3}){3}|\[[a-fA-F0-9:]+\]):)?(?P<port>\d+)$'
DEFAULT_PORT = "8000"
class BaseRunserverCommand(BaseCommand):
option_list = BaseCommand.option_list + (
make_option('--ipv6', '-6', action='store_true', dest='use_ipv6', default=False,
help='Tells Django to use a IPv6 address.'),
make_option('--noreload', action='store_false', dest='use_reloader', default=True,
help='Tells Django to NOT use the auto-reloader.'),
)
@ -25,22 +32,31 @@ class BaseRunserverCommand(BaseCommand):
return WSGIHandler()
def handle(self, addrport='', *args, **options):
self.use_ipv6 = options.get('use_ipv6')
if self.use_ipv6 and not hasattr(socket, 'AF_INET6'):
raise CommandError('Your Python does not support IPv6.')
if args:
raise CommandError('Usage is runserver %s' % self.args)
if not addrport:
self.addr = ''
self.port = '8000'
self.port = DEFAULT_PORT
else:
try:
self.addr, self.port = addrport.split(':')
except ValueError:
self.addr, self.port = '', addrport
m = re.match(naiveip_re, addrport)
if m is None:
raise CommandError('%r is not a valid port number'
'or address:port pair.' % addrport)
self.addr, self.port = m.groups()
if not self.port.isdigit():
raise CommandError("%r is not a valid port number." % self.port)
if self.addr:
if self.addr.startswith('[') and self.addr.endswith(']'):
self.addr = self.addr[1:-1]
self.use_ipv6 = True
elif self.use_ipv6:
raise CommandError('IPv6 addresses must be surrounded '
'with brackets, e.g. [::1].')
if not self.addr:
self.addr = '127.0.0.1'
if not self.port.isdigit():
raise CommandError("%r is not a valid port number." % self.port)
self.addr = self.use_ipv6 and '::1' or '127.0.0.1'
self.run(*args, **options)
def run(self, *args, **options):
@ -70,7 +86,7 @@ class BaseRunserverCommand(BaseCommand):
) % {
"version": self.get_version(),
"settings": settings.SETTINGS_MODULE,
"addr": self.addr,
"addr": self.use_ipv6 and '[%s]' % self.addr or self.addr,
"port": self.port,
"quit_command": quit_command,
})
@ -81,7 +97,7 @@ class BaseRunserverCommand(BaseCommand):
try:
handler = self.get_handler(*args, **options)
run(self.addr, int(self.port), handler)
run(self.addr, int(self.port), handler, ipv6=self.use_ipv6)
except WSGIServerException, e:
# Use helpful error messages instead of ugly tracebacks.
ERRORS = {

View File

@ -9,6 +9,8 @@ class Command(BaseCommand):
make_option('--addrport', action='store', dest='addrport',
type='string', default='',
help='port number or ipaddr:port to run the server on'),
make_option('--ipv6', '-6', action='store_true', dest='use_ipv6', default=False,
help='Tells Django to use a IPv6 address.'),
)
help = 'Runs a development server with data from the given fixture(s).'
args = '[fixture ...]'
@ -33,4 +35,4 @@ class Command(BaseCommand):
# a strange error -- it causes this handle() method to be called
# multiple times.
shutdown_message = '\nServer stopped.\nNote that the test database, %r, has not been deleted. You can explore it on your own.' % db_name
call_command('runserver', addrport=addrport, shutdown_message=shutdown_message, use_reloader=False)
call_command('runserver', addrport=addrport, shutdown_message=shutdown_message, use_reloader=False, use_ipv6=options['use_ipv6'])

View File

@ -10,6 +10,7 @@ been reviewed for security issues. Don't use it for production use.
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import os
import re
import socket
import sys
import urllib
import warnings
@ -526,6 +527,11 @@ class WSGIServer(HTTPServer):
"""BaseHTTPServer that implements the Python WSGI protocol"""
application = None
def __init__(self, *args, **kwargs):
if kwargs.pop('ipv6', False):
self.address_family = socket.AF_INET6
HTTPServer.__init__(self, *args, **kwargs)
def server_bind(self):
"""Override server_bind to store the server name."""
try:
@ -683,9 +689,8 @@ class AdminMediaHandler(handlers.StaticFilesHandler):
"""
return path.startswith(self.base_url[2]) and not self.base_url[1]
def run(addr, port, wsgi_handler):
def run(addr, port, wsgi_handler, ipv6=False):
server_address = (addr, port)
httpd = WSGIServer(server_address, WSGIRequestHandler)
httpd = WSGIServer(server_address, WSGIRequestHandler, ipv6=ipv6)
httpd.set_app(wsgi_handler)
httpd.serve_forever()

View File

@ -75,7 +75,7 @@ Runs this project as a FastCGI application. Requires flup. Use
.B runfcgi help
for help on the KEY=val pairs.
.TP
.BI "runserver [" "\-\-noreload" "] [" "\-\-nostatic" "] [" "\-\-insecure" "] [" "\-\-adminmedia=ADMIN_MEDIA_PATH" "] [" "port|ipaddr:port" "]"
.BI "runserver [" "\-\-noreload" "] [" "\-\-nostatic" "] [" "\-\-insecure" "] [" "\-\-ipv6" "] [" "\-\-adminmedia=ADMIN_MEDIA_PATH" "] [" "port|ipaddr:port" "]"
Starts a lightweight Web server for development.
.TP
.BI "shell [" "\-\-plain" "]"
@ -170,6 +170,9 @@ Disable automatic serving of static files from STATIC_URL.
.I \-\-insecure
Enables serving of static files even if DEBUG is False.
.TP
.I \-\-ipv6
Enables IPv6 addresses.
.TP
.I \-\-verbosity=VERBOSITY
Verbosity level: 0=minimal output, 1=normal output, 2=all output.
.TP

View File

@ -630,7 +630,7 @@ runserver [port or ipaddr:port]
.. django-admin:: runserver
Starts a lightweight development Web server on the local machine. By default,
the server runs on port 8000 on the IP address 127.0.0.1. You can pass in an
the server runs on port 8000 on the IP address ``127.0.0.1``. You can pass in an
IP address and port number explicitly.
If you run this script as a user with normal privileges (recommended), you
@ -654,10 +654,15 @@ them to standard output, but it won't stop the server.
You can run as many servers as you want, as long as they're on separate ports.
Just execute ``django-admin.py runserver`` more than once.
Note that the default IP address, 127.0.0.1, is not accessible from other
Note that the default IP address, ``127.0.0.1``, is not accessible from other
machines on your network. To make your development server viewable to other
machines on the network, use its own IP address (e.g. ``192.168.2.1``) or
``0.0.0.0``.
``0.0.0.0`` or ``::`` (with IPv6 enabled).
.. versionchanged:: 1.3
You can also provide an IPv6 address surrounded by brackets
(eg. ``[200a::1]:8000``). This will automaticaly enable IPv6 support.
.. django-admin-option:: --adminmedia
@ -681,25 +686,49 @@ Example usage::
django-admin.py runserver --noreload
.. django-admin-option:: --ipv6, -6
.. versionadded:: 1.3
Use the ``--ipv6`` (or shorter ``-6``) option to tell Django to use IPv6 for
the development server. This changes the default IP address from
``127.0.0.1`` to ``::1``.
Example usage::
django-admin.py runserver --ipv6
Examples of using different ports and addresses
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Port 8000 on IP address 127.0.0.1::
Port 8000 on IP address ``127.0.0.1``::
django-admin.py runserver
django-admin.py runserver
Port 8000 on IP address 1.2.3.4::
Port 8000 on IP address ``1.2.3.4``::
django-admin.py runserver 1.2.3.4:8000
django-admin.py runserver 1.2.3.4:8000
Port 7000 on IP address 127.0.0.1::
Port 7000 on IP address ``127.0.0.1``::
django-admin.py runserver 7000
Port 7000 on IP address 1.2.3.4::
Port 7000 on IP address ``1.2.3.4``::
django-admin.py runserver 1.2.3.4:7000
Port 8000 on IPv6 address ``::1``::
django-admin.py runserver -6
Port 7000 on IPv6 address ``::1``::
django-admin.py runserver -6 7000
Port 7000 on IPv6 address ``2001:0db8:1234:5678::9``::
django-admin.py runserver [2001:0db8:1234:5678::9]:7000
Serving static files with the development server
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -963,7 +992,7 @@ templates.
.. django-admin-option:: --addrport [port number or ipaddr:port]
Use ``--addrport`` to specify a different port, or IP address and port, from
the default of 127.0.0.1:8000. This value follows exactly the same format and
the default of ``127.0.0.1:8000``. This value follows exactly the same format and
serves exactly the same function as the argument to the ``runserver`` command.
Examples: