Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

[1.6.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...
commit 56201fe5a85ead96f00d8ad2eda5cfd2bc4cb4b0 1 parent b2876c0
Florian Apolloner authored September 22, 2013
15  django/core/management/commands/runserver.py
... ...
@@ -1,12 +1,13 @@
1 1
 from optparse import make_option
2 2
 from datetime import datetime
  3
+import errno
3 4
 import os
4 5
 import re
5 6
 import sys
6 7
 import socket
7 8
 
8 9
 from django.core.management.base import BaseCommand, CommandError
9  
-from django.core.servers.basehttp import run, WSGIServerException, get_internal_wsgi_application
  10
+from django.core.servers.basehttp import run, get_internal_wsgi_application
10 11
 from django.utils import autoreload
11 12
 
12 13
 naiveip_re = re.compile(r"""^(?:
@@ -117,16 +118,16 @@ def inner_run(self, *args, **options):
117 118
             handler = self.get_handler(*args, **options)
118 119
             run(self.addr, int(self.port), handler,
119 120
                 ipv6=self.use_ipv6, threading=threading)
120  
-        except WSGIServerException as e:
  121
+        except socket.error as e:
121 122
             # Use helpful error messages instead of ugly tracebacks.
122 123
             ERRORS = {
123  
-                13: "You don't have permission to access that port.",
124  
-                98: "That port is already in use.",
125  
-                99: "That IP address can't be assigned-to.",
  124
+                errno.EACCES: "You don't have permission to access that port.",
  125
+                errno.EADDRINUSE: "That port is already in use.",
  126
+                errno.EADDRNOTAVAIL: "That IP address can't be assigned-to.",
126 127
             }
127 128
             try:
128  
-                error_text = ERRORS[e.args[0].args[0]]
129  
-            except (AttributeError, KeyError):
  129
+                error_text = ERRORS[e.errno]
  130
+            except KeyError:
130 131
                 error_text = str(e)
131 132
             self.stderr.write("Error: %s" % error_text)
132 133
             # Need to use an OS exit because sys.exit doesn't work in a thread
9  django/core/servers/basehttp.py
@@ -58,10 +58,6 @@ def get_internal_wsgi_application():
58 58
     )
59 59
 
60 60
 
61  
-class WSGIServerException(Exception):
62  
-    pass
63  
-
64  
-
65 61
 class ServerHandler(simple_server.ServerHandler, object):
66 62
     error_status = str("500 INTERNAL SERVER ERROR")
67 63
 
@@ -114,10 +110,7 @@ def __init__(self, *args, **kwargs):
114 110
 
115 111
     def server_bind(self):
116 112
         """Override server_bind to store the server name."""
117  
-        try:
118  
-            super(WSGIServer, self).server_bind()
119  
-        except Exception as e:
120  
-            six.reraise(WSGIServerException, WSGIServerException(e), sys.exc_info()[2])
  113
+        super(WSGIServer, self).server_bind()
121 114
         self.setup_environ()
122 115
 
123 116
 
9  django/test/testcases.py
@@ -7,6 +7,7 @@
7 7
 import json
8 8
 import os
9 9
 import re
  10
+import socket
10 11
 import sys
11 12
 import select
12 13
 import socket
@@ -21,8 +22,7 @@
21 22
 from django.core.management import call_command
22 23
 from django.core.management.color import no_style
23 24
 from django.core.management.commands import flush
24  
-from django.core.servers.basehttp import (WSGIRequestHandler, WSGIServer,
25  
-    WSGIServerException)
  25
+from django.core.servers.basehttp import WSGIRequestHandler, WSGIServer
26 26
 from django.core.urlresolvers import clear_url_caches, set_urlconf
27 27
 from django.db import connection, connections, DEFAULT_DB_ALIAS, transaction
28 28
 from django.db.models.loading import cache
@@ -1089,10 +1089,9 @@ def run(self):
1089 1089
                 try:
1090 1090
                     self.httpd = StoppableWSGIServer(
1091 1091
                         (self.host, port), QuietWSGIRequestHandler)
1092  
-                except WSGIServerException as e:
  1092
+                except socket.error as e:
1093 1093
                     if (index + 1 < len(self.possible_ports) and
1094  
-                        hasattr(e.args[0], 'errno') and
1095  
-                        e.args[0].errno == errno.EADDRINUSE):
  1094
+                        e.errno == errno.EADDRINUSE):
1096 1095
                         # This port is already in use, so we go on and try with
1097 1096
                         # the next one in the list.
1098 1097
                         continue
4  tests/servers/tests.py
@@ -5,10 +5,10 @@
5 5
 from __future__ import unicode_literals
6 6
 
7 7
 import os
  8
+import socket
8 9
 
9 10
 from django.core.exceptions import ImproperlyConfigured
10 11
 from django.test import LiveServerTestCase
11  
-from django.core.servers.basehttp import WSGIServerException
12 12
 from django.test.utils import override_settings
13 13
 from django.utils.http import urlencode
14 14
 from django.utils.six.moves.urllib.error import HTTPError
@@ -71,7 +71,7 @@ def setUpClass(cls):
71 71
         cls.raises_exception('localhost', ImproperlyConfigured)
72 72
 
73 73
         # The host must be valid
74  
-        cls.raises_exception('blahblahblah:8081', WSGIServerException)
  74
+        cls.raises_exception('blahblahblah:8081', socket.error)
75 75
 
76 76
         # The list of ports must be in a valid format
77 77
         cls.raises_exception('localhost:8081,', ImproperlyConfigured)

0 notes on commit 56201fe

Please sign in to comment.
Something went wrong with that request. Please try again.