two fixes for redirects:
    - don't close the fp, since that appears to also close the socket
    - join the original url with the redirect reponse to deal with
      relative redirect URL

wrap two socket ops in try/except to turn them into URLErrors, so that
client code need only catch one exception.

in HTTPError.__del__ only close fp if fp is not None

style changes:
    - use f(*args) instead of apply(f, args)
    - use __super_init instead of super.__init__(self, ...)
diff --git a/Lib/urllib2.py b/Lib/urllib2.py
index 86fdc20..3e1e588 100644
--- a/Lib/urllib2.py
+++ b/Lib/urllib2.py
@@ -155,9 +155,10 @@
 
 class HTTPError(URLError, addinfourl):
     """Raised when HTTP error occurs, but also acts like non-error return"""
+    __super_init = addinfourl.__init__
 
     def __init__(self, url, code, msg, hdrs, fp):
-        addinfourl.__init__(self, fp, hdrs, url)
+        self.__super_init(fp, hdrs, url)
         self.code = code
         self.msg = msg
         self.hdrs = hdrs
@@ -171,7 +172,8 @@
     def __del__(self):
         # XXX is this safe? what if user catches exception, then
         # extracts fp and discards exception?
-        self.fp.close()
+        if self.fp:
+            self.fp.close()
 
 class GopherError(URLError):
     pass
@@ -215,6 +217,7 @@
     def get_type(self):
         if self.type is None:
             self.type, self.__r_type = splittype(self.__original)
+            assert self.type is not None, self.__original
         return self.type
 
     def get_host(self):
@@ -297,7 +300,8 @@
         handlers = chain.get(kind, ())
         for handler in handlers:
             func = getattr(handler, meth_name)
-            result = apply(func, args)
+
+            result = func(*args)
             if result is not None:
                 return result
 
@@ -318,7 +322,7 @@
 
         type_ = req.get_type()
         result = self._call_chain(self.handle_open, type_, type_ + \
-                                  '_open', req) 
+                                  '_open', req)
         if result:
             return result
 
@@ -338,13 +342,13 @@
             meth_name = proto + '_error'
             http_err = 0
         args = (dict, proto, meth_name) + args
-        result = apply(self._call_chain, args)
+        result = self._call_chain(*args)
         if result:
             return result
 
         if http_err:
             args = (dict, 'default', 'http_error_default') + orig_args
-            return apply(self._call_chain, args)
+            return self._call_chain(*args)
 
 def is_callable(obj):
     # not quite like builtin callable (which I didn't know existed),
@@ -440,6 +444,8 @@
         nil = fp.read()
         fp.close()
 
+        newurl = urlparse.urljoin(req.get_full_url(), newurl)
+
         # XXX Probably want to forget about the state of the current
         # request, although that might interact poorly with other
         # handlers that also use handler-specific request attributes
@@ -727,19 +733,23 @@
         if not host:
             raise URLError('no host given')
 
-        h = httplib.HTTP(host) # will parse host:port
-##      h.set_debuglevel(1)
-        if req.has_data():
-            data = req.get_data()
-            h.putrequest('POST', req.get_selector())
-            h.putheader('Content-type', 'application/x-www-form-urlencoded')
-            h.putheader('Content-length', '%d' % len(data))
-        else:
-            h.putrequest('GET', req.get_selector())
+        try:
+            h = httplib.HTTP(host) # will parse host:port
+            if req.has_data():
+                data = req.get_data()
+                h.putrequest('POST', req.get_selector())
+                h.putheader('Content-type',
+                            'application/x-www-form-urlencoded')
+                h.putheader('Content-length', '%d' % len(data))
+            else:
+                h.putrequest('GET', req.get_selector())
+        except socket.error, err:
+            raise URLError(err)
+            
         # XXX proxies would have different host here
         h.putheader('Host', host)
         for args in self.parent.addheaders:
-            apply(h.putheader, args)
+            h.putheader(*args)
         for k, v in req.headers.items():
             h.putheader(k, v)
         h.endheaders()
@@ -751,12 +761,6 @@
         if code == 200:
             return addinfourl(fp, hdrs, req.get_full_url())
         else:
-            # want to make sure the socket is closed, even if error
-            # handling doesn't return immediately.  the socket won't
-            # actually be closed until fp is also closed.
-            if h.sock:
-                h.sock.close()
-                h.sock = None
             return self.parent.error('http', req, fp, code, msg, hdrs)
 
 class UnknownHandler(BaseHandler):
@@ -859,7 +863,10 @@
         if not host:
             raise IOError, ('ftp error', 'no host given')
         # XXX handle custom username & password
-        host = socket.gethostbyname(host)
+        try:
+            host = socket.gethostbyname(host)
+        except socket.error, msg:
+            raise URLError(msg)
         host, port = splitport(host)
         if port is None:
             port = ftplib.FTP_PORT
@@ -988,7 +995,7 @@
     # right authentication configuration for test purposes.
     if socket.gethostname() == 'bitdiddle':
         localhost = 'bitdiddle.cnri.reston.va.us'
-    elif socket.gethostname() == 'walden':
+    elif socket.gethostname() == 'bitdiddle.concentric.net':
         localhost = 'localhost'
     else:
         localhost = None