mirror of https://github.com/django/django.git
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:
parent
132afbf8ee
commit
6a32e253f6
|
@ -1,14 +1,21 @@
|
||||||
from optparse import make_option
|
from optparse import make_option
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
import socket
|
||||||
|
|
||||||
from django.core.management.base import BaseCommand, CommandError
|
from django.core.management.base import BaseCommand, CommandError
|
||||||
from django.core.handlers.wsgi import WSGIHandler
|
from django.core.handlers.wsgi import WSGIHandler
|
||||||
from django.core.servers.basehttp import AdminMediaHandler, run, WSGIServerException
|
from django.core.servers.basehttp import AdminMediaHandler, run, WSGIServerException
|
||||||
from django.utils import autoreload
|
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):
|
class BaseRunserverCommand(BaseCommand):
|
||||||
option_list = BaseCommand.option_list + (
|
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,
|
make_option('--noreload', action='store_false', dest='use_reloader', default=True,
|
||||||
help='Tells Django to NOT use the auto-reloader.'),
|
help='Tells Django to NOT use the auto-reloader.'),
|
||||||
)
|
)
|
||||||
|
@ -25,22 +32,31 @@ class BaseRunserverCommand(BaseCommand):
|
||||||
return WSGIHandler()
|
return WSGIHandler()
|
||||||
|
|
||||||
def handle(self, addrport='', *args, **options):
|
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:
|
if args:
|
||||||
raise CommandError('Usage is runserver %s' % self.args)
|
raise CommandError('Usage is runserver %s' % self.args)
|
||||||
if not addrport:
|
if not addrport:
|
||||||
self.addr = ''
|
self.addr = ''
|
||||||
self.port = '8000'
|
self.port = DEFAULT_PORT
|
||||||
else:
|
else:
|
||||||
try:
|
m = re.match(naiveip_re, addrport)
|
||||||
self.addr, self.port = addrport.split(':')
|
if m is None:
|
||||||
except ValueError:
|
raise CommandError('%r is not a valid port number'
|
||||||
self.addr, self.port = '', addrport
|
'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:
|
if not self.addr:
|
||||||
self.addr = '127.0.0.1'
|
self.addr = self.use_ipv6 and '::1' or '127.0.0.1'
|
||||||
|
|
||||||
if not self.port.isdigit():
|
|
||||||
raise CommandError("%r is not a valid port number." % self.port)
|
|
||||||
|
|
||||||
self.run(*args, **options)
|
self.run(*args, **options)
|
||||||
|
|
||||||
def run(self, *args, **options):
|
def run(self, *args, **options):
|
||||||
|
@ -70,7 +86,7 @@ class BaseRunserverCommand(BaseCommand):
|
||||||
) % {
|
) % {
|
||||||
"version": self.get_version(),
|
"version": self.get_version(),
|
||||||
"settings": settings.SETTINGS_MODULE,
|
"settings": settings.SETTINGS_MODULE,
|
||||||
"addr": self.addr,
|
"addr": self.use_ipv6 and '[%s]' % self.addr or self.addr,
|
||||||
"port": self.port,
|
"port": self.port,
|
||||||
"quit_command": quit_command,
|
"quit_command": quit_command,
|
||||||
})
|
})
|
||||||
|
@ -81,7 +97,7 @@ class BaseRunserverCommand(BaseCommand):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
handler = self.get_handler(*args, **options)
|
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:
|
except WSGIServerException, e:
|
||||||
# Use helpful error messages instead of ugly tracebacks.
|
# Use helpful error messages instead of ugly tracebacks.
|
||||||
ERRORS = {
|
ERRORS = {
|
||||||
|
|
|
@ -9,6 +9,8 @@ class Command(BaseCommand):
|
||||||
make_option('--addrport', action='store', dest='addrport',
|
make_option('--addrport', action='store', dest='addrport',
|
||||||
type='string', default='',
|
type='string', default='',
|
||||||
help='port number or ipaddr:port to run the server on'),
|
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).'
|
help = 'Runs a development server with data from the given fixture(s).'
|
||||||
args = '[fixture ...]'
|
args = '[fixture ...]'
|
||||||
|
@ -33,4 +35,4 @@ class Command(BaseCommand):
|
||||||
# a strange error -- it causes this handle() method to be called
|
# a strange error -- it causes this handle() method to be called
|
||||||
# multiple times.
|
# 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
|
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'])
|
||||||
|
|
|
@ -10,6 +10,7 @@ been reviewed for security issues. Don't use it for production use.
|
||||||
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
|
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import socket
|
||||||
import sys
|
import sys
|
||||||
import urllib
|
import urllib
|
||||||
import warnings
|
import warnings
|
||||||
|
@ -526,6 +527,11 @@ class WSGIServer(HTTPServer):
|
||||||
"""BaseHTTPServer that implements the Python WSGI protocol"""
|
"""BaseHTTPServer that implements the Python WSGI protocol"""
|
||||||
application = None
|
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):
|
def server_bind(self):
|
||||||
"""Override server_bind to store the server name."""
|
"""Override server_bind to store the server name."""
|
||||||
try:
|
try:
|
||||||
|
@ -683,9 +689,8 @@ class AdminMediaHandler(handlers.StaticFilesHandler):
|
||||||
"""
|
"""
|
||||||
return path.startswith(self.base_url[2]) and not self.base_url[1]
|
return path.startswith(self.base_url[2]) and not self.base_url[1]
|
||||||
|
|
||||||
|
def run(addr, port, wsgi_handler, ipv6=False):
|
||||||
def run(addr, port, wsgi_handler):
|
|
||||||
server_address = (addr, port)
|
server_address = (addr, port)
|
||||||
httpd = WSGIServer(server_address, WSGIRequestHandler)
|
httpd = WSGIServer(server_address, WSGIRequestHandler, ipv6=ipv6)
|
||||||
httpd.set_app(wsgi_handler)
|
httpd.set_app(wsgi_handler)
|
||||||
httpd.serve_forever()
|
httpd.serve_forever()
|
||||||
|
|
|
@ -75,7 +75,7 @@ Runs this project as a FastCGI application. Requires flup. Use
|
||||||
.B runfcgi help
|
.B runfcgi help
|
||||||
for help on the KEY=val pairs.
|
for help on the KEY=val pairs.
|
||||||
.TP
|
.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.
|
Starts a lightweight Web server for development.
|
||||||
.TP
|
.TP
|
||||||
.BI "shell [" "\-\-plain" "]"
|
.BI "shell [" "\-\-plain" "]"
|
||||||
|
@ -170,6 +170,9 @@ Disable automatic serving of static files from STATIC_URL.
|
||||||
.I \-\-insecure
|
.I \-\-insecure
|
||||||
Enables serving of static files even if DEBUG is False.
|
Enables serving of static files even if DEBUG is False.
|
||||||
.TP
|
.TP
|
||||||
|
.I \-\-ipv6
|
||||||
|
Enables IPv6 addresses.
|
||||||
|
.TP
|
||||||
.I \-\-verbosity=VERBOSITY
|
.I \-\-verbosity=VERBOSITY
|
||||||
Verbosity level: 0=minimal output, 1=normal output, 2=all output.
|
Verbosity level: 0=minimal output, 1=normal output, 2=all output.
|
||||||
.TP
|
.TP
|
||||||
|
|
|
@ -630,7 +630,7 @@ runserver [port or ipaddr:port]
|
||||||
.. django-admin:: runserver
|
.. django-admin:: runserver
|
||||||
|
|
||||||
Starts a lightweight development Web server on the local machine. By default,
|
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.
|
IP address and port number explicitly.
|
||||||
|
|
||||||
If you run this script as a user with normal privileges (recommended), you
|
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.
|
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.
|
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 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
|
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
|
.. django-admin-option:: --adminmedia
|
||||||
|
|
||||||
|
@ -681,25 +686,49 @@ Example usage::
|
||||||
|
|
||||||
django-admin.py runserver --noreload
|
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
|
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
|
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
|
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
|
Serving static files with the development server
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -963,7 +992,7 @@ templates.
|
||||||
.. django-admin-option:: --addrport [port number or ipaddr:port]
|
.. django-admin-option:: --addrport [port number or ipaddr:port]
|
||||||
|
|
||||||
Use ``--addrport`` to specify a different port, or IP address and port, from
|
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.
|
serves exactly the same function as the argument to the ``runserver`` command.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
Loading…
Reference in New Issue