Browse files

[1.5.x] Fixed "Address already in use" from liveserver.

Our WSGIServer rewrapped the socket errors from server_bind into
WSGIServerExceptions, which is used later on to provide nicer
error messages in runserver and used by the liveserver to see if
the port is already in use. But wrapping server_bind isn't enough since
it only binds to the socket, socket.listen (which is called from
server_activate) could also raise "Address already in use".

Instead of overriding server_activate too I chose to just catch socket
errors, which seems to make more sense anyways and should be more robust
against changes in wsgiref.

Backport of 2ca00fa from master
  • Loading branch information...
apollo13 committed Sep 22, 2013
1 parent b5eddde commit 18fe77e4ed01a7761a24de7ec7b1c3a1314fc197
@@ -1,12 +1,13 @@
from optparse import make_option
from datetime import datetime
+import errno
import os
import re
import sys
import socket
from import BaseCommand, CommandError
-from django.core.servers.basehttp import run, WSGIServerException, get_internal_wsgi_application
+from django.core.servers.basehttp import run, get_internal_wsgi_application
from django.utils import autoreload
naiveip_re = re.compile(r"""^(?:
@@ -112,16 +113,16 @@ def inner_run(self, *args, **options):
handler = self.get_handler(*args, **options)
run(self.addr, int(self.port), handler,
ipv6=self.use_ipv6, threading=threading)
- except WSGIServerException as e:
+ except socket.error as e:
# Use helpful error messages instead of ugly tracebacks.
- 13: "You don't have permission to access that port.",
- 98: "That port is already in use.",
- 99: "That IP address can't be assigned-to.",
+ errno.EACCES: "You don't have permission to access that port.",
+ errno.EADDRINUSE: "That port is already in use.",
+ errno.EADDRNOTAVAIL: "That IP address can't be assigned-to.",
- error_text = ERRORS[e.args[0].args[0]]
- except (AttributeError, KeyError):
+ error_text = ERRORS[e.errno]
+ except KeyError:
error_text = str(e)
self.stderr.write("Error: %s" % error_text)
# Need to use an OS exit because sys.exit doesn't work in a thread
@@ -67,10 +67,6 @@ def get_internal_wsgi_application():
return app
-class WSGIServerException(Exception):
- pass
class ServerHandler(simple_server.ServerHandler, object):
error_status = str("500 INTERNAL SERVER ERROR")
@@ -131,10 +127,7 @@ def __init__(self, *args, **kwargs):
def server_bind(self):
"""Override server_bind to store the server name."""
- try:
- super(WSGIServer, self).server_bind()
- except Exception as e:
- raise WSGIServerException(e)
+ super(WSGIServer, self).server_bind()
@@ -4,6 +4,7 @@
import json
import os
import re
+import socket
import sys
from copy import copy
from functools import wraps
@@ -24,8 +25,7 @@
from import call_command
from import no_style
from django.core.signals import request_started
-from django.core.servers.basehttp import (WSGIRequestHandler, WSGIServer,
- WSGIServerException)
+from django.core.servers.basehttp import WSGIRequestHandler, WSGIServer
from django.core.urlresolvers import clear_url_caches
from django.core.validators import EMPTY_VALUES
from django.db import (transaction, connection, connections, DEFAULT_DB_ALIAS,
@@ -1064,10 +1064,9 @@ def run(self):
self.httpd = StoppableWSGIServer(
(, port), QuietWSGIRequestHandler)
- except WSGIServerException as e:
+ except socket.error as e:
if (index + 1 < len(self.possible_ports) and
- hasattr(e.args[0], 'errno') and
- e.args[0].errno == errno.EADDRINUSE):
+ e.errno == errno.EADDRINUSE):
# This port is already in use, so we go on and try with
# the next one in the list.
@@ -5,14 +5,14 @@
from __future__ import unicode_literals
import os
+import socket
from urllib.request import urlopen, HTTPError
except ImportError: # Python 2
from urllib2 import urlopen, HTTPError
from django.core.exceptions import ImproperlyConfigured
from django.test import LiveServerTestCase
-from django.core.servers.basehttp import WSGIServerException
from django.test.utils import override_settings
from django.utils.http import urlencode
from django.utils._os import upath
@@ -66,7 +66,7 @@ def setUpClass(cls):
cls.raises_exception('localhost', ImproperlyConfigured)
# The host must be valid
- cls.raises_exception('blahblahblah:8081', WSGIServerException)
+ cls.raises_exception('blahblahblah:8081', socket.error)
# The list of ports must be in a valid format
cls.raises_exception('localhost:8081,', ImproperlyConfigured)

0 comments on commit 18fe77e

Please sign in to comment.