msg72917 - (view) |
Author: (romkyns) |
Date: 2008-09-09 21:21 |
See example code attached. A very basic http server responds with an XML
document to any GET request. I think what happens is that the connection
remains open at the end of the request, leading the browser to believe
there's more data to come (and hence not displaying anything).
What's curious is that commenting out the single line "self.dummy =
self" fixes the problem. Also, the problem occurs in 3.0b2 but not in 2.5.2.
To reproduce:
1. Run the example code on 3.0b2
2. Navigate to http://localhost:8123/
The browser shows "Transferring data" or something similar, until it
times out.
3. Comment out the line "self.dummy = self"
4. Navigate to http://localhost:8123/
This time it loads instantly.
Repeat with 2.5.2 - both variants work.
I don't know much at all about python internals, but it seems that 1) a
circular reference prevents the request handler from being GC'd and 2)
http.server relies on the request being GC'd to finalise the connection.
|
msg72980 - (view) |
Author: (romkyns) |
Date: 2008-09-10 18:11 |
My initial description doesn't state the actual observable problem very
clearly: the problem is that the browser gets stuck instead of
displaying the page, writing something along the lines of "Transferring
data from localhost". After many seconds it times out. Aborting the
request in Firefox causes the page to be displayed.
Also forgot to mention that it's possible to work around this by
explicitly removing all circular references after the base class'
__init__ method - so for the attached example a work-around is
"self.dummy = None" as the last line of the __init__ method.
|
msg73248 - (view) |
Author: (romkyns) |
Date: 2008-09-15 07:00 |
Someone suggested I test this in 2.6rc1. The problem does not exist in
2.6rc1, only in 3.0b2.
|
msg73481 - (view) |
Author: Gabriel Genellina (ggenellina) |
Date: 2008-09-21 04:14 |
3.0rc1 still fails.
The diagnostic is correct, the connection should be closed after
sending the response, but isn't.
The attached unittest reproduces the error without requiring a browser.
|
msg73774 - (view) |
Author: (romkyns) |
Date: 2008-09-25 09:39 |
So the GC behaviour in this case is such that Python 3.0 can't collect
the object whereas Python 2.6 can. Is this known / expected or should
this be recorded in a separate issue?
|
msg73777 - (view) |
Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) * |
Date: 2008-09-25 11:51 |
The garbage collector does collect unreachable objects.
What happens is that with python 2, the socket is explicitly closed by
the HTTPServer, whereas with python 3, the explicit close() does not
work, and the socket is ultimately closed when the request has finished
and all objects are disposed.
The cause is in the socket.makefile() function: since python3, the
underlying socket uses a reference count, so that:
s = <a connected socket>
f = s.makefile()
s.close()
does not close the socket! adding f.close() is not enough. A "del f" is
necessary to really close the underlying socket.
|
msg73834 - (view) |
Author: Gregory P. Smith (gregory.p.smith) * |
Date: 2008-09-26 05:57 |
The whole socket._io_refs thing looks like a real design flaw. What is
its actual intended purpose?
When close is called on the socket object itself, the socket MSUT be
closed. Why is our API otherwise?
Its up to the programming to ensure that no other references to that
socket wrapped in whatever layers will be used after that, if they are
they'll eventually get errors when an IO occurs.
I think this behavior started with this change:
------------------------------------------------------------------------
r56714 | jeremy.hylton | 2007-08-03 13:40:09 -0700 (Fri, 03 Aug 2007) |
21 lines
Make sure socket.close() doesn't interfere with socket.makefile().
If a makefile()-generated object is open and its parent socket is
closed, the parent socket should remain open until the child is
closed, too. The code to support this is moderately complex and
requires one extra slots in the socket object.
This change fixes httplib so that several urllib2net test cases pass
again.
Add SocketCloser class to socket.py, which encapsulates the
refcounting logic for sockets after makefile() has been called.
Move SocketIO class from io module to socket module. It's only use is
to implement the raw I/O methods on top of a socket to support
makefile().
Add unittests to test_socket to cover various patterns of close and
makefile.
...............
later modified by this (still the same effect):
...............
------------------------------------------------------------------------
r58970 | guido.van.rossum | 2007-11-14 14:32:02 -0800 (Wed, 14 Nov 2007)
| 6 lines
Patch 1439 by Bill Janssen. I think this will work.
Tested on Windows by Christian Heimes.
I changed the code slightly, renaming decref_socketios() to
_decref_socketios(), and moving it closer to the close() method
that it calls. Hopefully Bill can now submit his SSL port to 3.0.
|
msg73849 - (view) |
Author: Guido van Rossum (gvanrossum) * |
Date: 2008-09-26 14:18 |
On Thu, Sep 25, 2008 at 10:57 PM, Gregory P. Smith
<report@bugs.python.org> wrote:
> The whole socket._io_refs thing looks like a real design flaw. What is
> its actual intended purpose?
The original purpose was to support the original semantics of the
.makefile() method on Windows which doesn't have dup() (or at least
didn't have it when this hack was first invented, many years ago). We
almost got rid of it for Py3k, but then we realized that the same
issue (sort of) exists for ssl, and that's why it's still there and
used everywhere, not just on Windows.
> When close is called on the socket object itself, the socket MSUT be
> closed. Why is our API otherwise?
See above -- the underlying connection must remain open until the
stream created with .makefile() is also closed. (These are the
original dup-based semantics.)
Why do you say MUST? Is there an Internet standard that requires this?
> Its up to the programming to ensure that no other references to that
> socket wrapped in whatever layers will be used after that, if they are
> they'll eventually get errors when an IO occurs.
No, the .makefile() API always promised that the connection remained
open until you closed (or lost) the stream.
> I think this behavior started with this change:
>
> ------------------------------------------------------------------------
> r56714 | jeremy.hylton | 2007-08-03 13:40:09 -0700 (Fri, 03 Aug 2007) |
> 21 lines
>
> Make sure socket.close() doesn't interfere with socket.makefile().
No, it's much, much older than that. That change was probably just a
refactoring -- it's been refactored a number of times.
|
msg76567 - (view) |
Author: Gregory P. Smith (gregory.p.smith) * |
Date: 2008-11-28 23:32 |
Alright I've taken another fresh look at this. I understand the dup
semantics issue and don't want to break that.
Attached are two patches, either one of these will fix the problem and
breakage.py test code attached to this bug.
Personally I prefer the socket.py patch as I think it will solve this
problem in other places it could potentially pop up. It calls
self._sock._decref_socketios() from within the SocketIO.close() method
so that after a SocketIO returned by socket.makefile() is closed, it
will no longer prevent the underlying socket from closing.
The socketserver.py patch also works but seems like more of a hack as it
is still relies on immediate reference counted destruction.
Please review.
I'm guessing its too late in the release candidate process for 3.0 to
get this in, but we should do it for 3.0.1.
|
msg76568 - (view) |
Author: Gregory P. Smith (gregory.p.smith) * |
Date: 2008-11-28 23:34 |
P.S. Gabriel Genellina (gagenellina) - Your comment sounded like you
had a unit test for this but it never got attached. Still have it?
|
msg76569 - (view) |
Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) * |
Date: 2008-11-28 23:58 |
I agree that the patch on socket.py is the correct fix: the raw socket
should be detached when the close() method is called.
I have one remark on the patch:
io.IOBase.__del__ already calls close(): could SocketIO.__del__ be
removed completely? And no need for "_need_to_decref_sock": the closed
property should be enough.
|
msg76570 - (view) |
Author: Gregory P. Smith (gregory.p.smith) * |
Date: 2008-11-29 00:04 |
Indeed IOBase does call close() from its __del__. Excellent. That
makes this simpler. -gps03 attached.
|
msg76572 - (view) |
Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) * |
Date: 2008-11-29 00:58 |
Patch issue3826_socket-gps03.diff is OK for me.
Here is a unit test for this new behavior.
Someone should review both patches.
|
msg76592 - (view) |
Author: Martin v. Löwis (loewis) * |
Date: 2008-11-29 13:25 |
I don't think this is quite right yet. If I run
import socket
s=socket.socket()
s.connect(('www.python.org',80))
x=s.makefile()
del x
del s
and put a print statement into real_close, I don't see that real_close
is invoked.
|
msg76595 - (view) |
Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) * |
Date: 2008-11-29 14:38 |
But real_close() is not called either in the trivial socket use:
import socket
s=socket.socket()
s.connect(('www.python.org',80))
del s
OTOH, I added some printf statements in socketmodule.c, near all usages
of SOCKETCLOSE(). They show that the raw socket is closed as expected -
except in the following case:
import socket
s=socket.socket()
s.connect(('www.python.org',80))
x=s.makefile()
x.close()
del s
|
msg76625 - (view) |
Author: Gregory P. Smith (gregory.p.smith) * |
Date: 2008-11-29 21:52 |
Martin: socket.socket has no destructor so a call to
socket.socket._real_close() is not guaranteed. Thats fine as its parent
class from socketmodule.c _socket.socket does the right thing in its
destructor.
Amaury: The case you show doesn't call SOCKETCLOSE() because x still
exists and holds a reference to the socket object.
In order to fix that, SocketIO needs to drop its reference on close.
Take a look at the attached -gps04 patch. It fixes that.
|
msg76631 - (view) |
Author: Gregory P. Smith (gregory.p.smith) * |
Date: 2008-11-29 23:06 |
gps05.diff includes the fix and unittests.
|
msg76633 - (view) |
Author: Gabriel Genellina (ggenellina) |
Date: 2008-11-30 07:37 |
--- El vie 28-nov-08, Gregory P. Smith <report@bugs.python.org> escribió:
> P.S. Gabriel Genellina (gagenellina) - Your comment
> sounded like you
> had a unit test for this but it never got attached. Still
> have it?
I've found it; it uses BaseHTTPRequestHandler as in the original bug report. I'm not sure it is still relevant, but I'm attaching it here anyway.
|
msg79209 - (view) |
Author: STINNER Victor (vstinner) * |
Date: 2009-01-05 23:12 |
Issue #4791 is exaclty the same problem (io reference in SocketIO): I
proposed another patch (decrement the io reference but keep the
self._sock object unchanged).
|
msg79211 - (view) |
Author: STINNER Victor (vstinner) * |
Date: 2009-01-05 23:25 |
Comment about issue3826_gps05.diff:
- I don't like "magical" attributes (sometimes it does exist,
sometimes not) even if it's a protected attribute (_sock) => use
self._sock=None?
- fileno() returns a fixed value whereas the socket.fileno()
returns -1 when the socket is closed => returns -1 or raise an error
if the socket is closed?
- I'm not sure that your test is really working: read a closed socket
may raise an error because of the test on self._closed, not because
the low level socket is closed => use fileno() to check if the socket
is closed or not
|
msg79213 - (view) |
Author: Gregory P. Smith (gregory.p.smith) * |
Date: 2009-01-05 23:29 |
from #python-dev discussion.
agreed, magic attributes are annoying. also, my gps05 patch continues
to return the old fileno even after the underlying socket has been
closed. that is a problem.
I like your patch in #4791 but lets keep both sets of our unit tests.
Also, I think the SocketIO.fileno mathod should change to:
def fileno(self):
no = self._sock.fileno()
if no == -1:
raise IOError("no file descriptor, socket is closed.")
io.IOBase.fileno already raises IOError when no file descriptor is
associated with a file so this behavior seems reasonable and more
pythonic than returning a magic -1.
thoughts?
|
msg79214 - (view) |
Author: STINNER Victor (vstinner) * |
Date: 2009-01-05 23:34 |
> Also, I think the SocketIO.fileno mathod should change to: (...)
Since SocketIO.fileno() just calls self._sock.fileno(), it would be
easier (and better) to fix socket.socket(). But since socket.fileno()
calls socket._fileno() we can just fix it correctly once in
socketmodule.c ;-) And instead IOError, I would prefer socket.error.
|
msg79220 - (view) |
Author: STINNER Victor (vstinner) * |
Date: 2009-01-06 01:09 |
I spent two hours on this issue and here are some notes...
(1) SocketIO.close() have to call self._sock._decref_socketios() to
allow the socket to call _real_close()
s = socket...
f = s.makefile()
f.close() # only close the "file view"
s.close() <= close the socket here
(2) SocketIO.close() have to break its reference to allow the socket
to be closed
s = socket...
f = s.makefile()
del s # there is still one reference (f._sock)
f.close() <= the garbage collector will close the socket here
(3) operations on a closed SocketIO should be blocked
s = socket...
f = s.makefile()
f.close()
f.fileno() => error!
So issue3826_gps05.diff have two bugs:
- point (1)
- point (3): can be fixed by adding self._check_closed() (and so we
don't need the local copy of fileno)
|
msg79221 - (view) |
Author: STINNER Victor (vstinner) * |
Date: 2009-01-06 01:13 |
socket_real_close-5.patch: my own patch developed for the issue #4791
(which is exactly the same problem) to fix SocketIO:
- set self._sock=None on close
- update the io reference count directly in close() (but also in
destructor)
- add a regression test
You may merge my patch with gps's patch (which has different tests).
See also issue #4853 to block all operations on closed socket in the
low level API (socketmodule.c).
|
msg79645 - (view) |
Author: Gregory P. Smith (gregory.p.smith) * |
Date: 2009-01-12 04:51 |
Committed all of our tests and the actual code to fix the problem from
socket_real_close-5.patch in py3k r68539.
This still needs back porting to release30-maint assuming no other
issues are found with it.
|
msg79993 - (view) |
Author: STINNER Victor (vstinner) * |
Date: 2009-01-17 02:02 |
> This still needs back porting to release30-maint
> assuming no other issues are found with it
How can we check if they are new issues with the changes?
|
msg79994 - (view) |
Author: Gregory P. Smith (gregory.p.smith) * |
Date: 2009-01-17 02:08 |
That mostly meant let the buildbots run it and/or see if anyone
complains on a list. Go ahead and backport. :)
|
msg80233 - (view) |
Author: Gregory P. Smith (gregory.p.smith) * |
Date: 2009-01-20 04:03 |
backported to release30-maint in r68796.
|
|
Date |
User |
Action |
Args |
2022-04-11 14:56:38 | admin | set | github: 48076 |
2009-01-20 04:03:01 | gregory.p.smith | set | status: open -> closed resolution: fixed messages:
+ msg80233 |
2009-01-17 02:08:13 | gregory.p.smith | set | messages:
+ msg79994 |
2009-01-17 02:02:19 | vstinner | set | messages:
+ msg79993 |
2009-01-12 04:51:36 | gregory.p.smith | set | keywords:
- needs review messages:
+ msg79645 |
2009-01-06 13:38:21 | vstinner | set | priority: critical -> release blocker title: BaseHTTPRequestHandler depends on GC to close connections -> Problem with SocketIO for closing the socket |
2009-01-06 01:15:40 | vstinner | set | files:
- socket_real_close-5.patch |
2009-01-06 01:13:31 | vstinner | set | files:
+ socket_real_close-5.patch messages:
+ msg79221 |
2009-01-06 01:09:23 | vstinner | set | files:
+ socket_real_close-5.patch messages:
+ msg79220 |
2009-01-05 23:48:31 | gvanrossum | set | nosy:
- gvanrossum |
2009-01-05 23:34:20 | vstinner | set | messages:
+ msg79214 |
2009-01-05 23:29:47 | gregory.p.smith | set | messages:
+ msg79213 |
2009-01-05 23:25:14 | vstinner | set | messages:
+ msg79211 |
2009-01-05 23:12:37 | vstinner | set | nosy:
+ vstinner messages:
+ msg79209 |
2008-11-30 07:37:52 | ggenellina | set | files:
+ test_httpclose_py3k.py messages:
+ msg76633 |
2008-11-29 23:07:22 | gregory.p.smith | set | files:
- issue3826_socket-gps04.diff |
2008-11-29 23:07:17 | gregory.p.smith | set | files:
- test_makefileclose.patch |
2008-11-29 23:06:54 | gregory.p.smith | set | files:
- issue3826_socket-gps03.diff |
2008-11-29 23:06:46 | gregory.p.smith | set | files:
+ issue3826_gps05.diff messages:
+ msg76631 |
2008-11-29 21:52:16 | gregory.p.smith | set | files:
+ issue3826_socket-gps04.diff messages:
+ msg76625 |
2008-11-29 14:38:45 | amaury.forgeotdarc | set | messages:
+ msg76595 |
2008-11-29 13:25:13 | loewis | set | nosy:
+ loewis messages:
+ msg76592 |
2008-11-29 12:49:59 | loewis | set | files:
- issue3826_socket-gps02.diff |
2008-11-29 12:49:53 | loewis | set | files:
- issue3826_socketserver-gps01.diff |
2008-11-29 00:58:03 | amaury.forgeotdarc | set | keywords:
+ needs review files:
+ test_makefileclose.patch messages:
+ msg76572 |
2008-11-29 00:04:58 | gregory.p.smith | set | files:
- issue3826_socket-gps01.diff |
2008-11-29 00:04:48 | gregory.p.smith | set | files:
+ issue3826_socket-gps03.diff messages:
+ msg76570 |
2008-11-28 23:58:13 | amaury.forgeotdarc | set | messages:
+ msg76569 |
2008-11-28 23:41:17 | gregory.p.smith | set | files:
+ issue3826_socket-gps02.diff |
2008-11-28 23:34:41 | gregory.p.smith | set | messages:
+ msg76568 stage: patch review |
2008-11-28 23:32:04 | gregory.p.smith | set | messages:
+ msg76567 |
2008-11-28 23:27:31 | gregory.p.smith | set | files:
+ issue3826_socket-gps01.diff |
2008-11-28 23:27:02 | gregory.p.smith | set | files:
+ issue3826_socketserver-gps01.diff keywords:
+ patch |
2008-09-26 14:18:18 | gvanrossum | set | messages:
+ msg73849 |
2008-09-26 05:57:45 | gregory.p.smith | set | nosy:
+ gvanrossum, jhylton messages:
+ msg73834 |
2008-09-25 11:51:40 | amaury.forgeotdarc | set | nosy:
+ amaury.forgeotdarc messages:
+ msg73777 |
2008-09-25 09:39:50 | romkyns | set | messages:
+ msg73774 |
2008-09-25 01:37:14 | zanella | set | nosy:
+ zanella |
2008-09-22 01:05:28 | gregory.p.smith | set | priority: critical assignee: gregory.p.smith nosy:
+ gregory.p.smith title: Self-reference in BaseHTTPRequestHandler descendants causes stuck connections -> BaseHTTPRequestHandler depends on GC to close connections |
2008-09-21 04:14:03 | ggenellina | set | nosy:
+ ggenellina messages:
+ msg73481 |
2008-09-15 07:00:58 | romkyns | set | messages:
+ msg73248 |
2008-09-10 18:11:59 | romkyns | set | messages:
+ msg72980 |
2008-09-09 21:21:11 | romkyns | create | |