<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<META NAME="Generator" CONTENT="MS Exchange Server version 6.5.7638.1">
<TITLE>web.client blowing up on non-fully qualified 301s</TITLE>
</HEAD>
<BODY>
<!-- Converted from text/plain format -->

<P><FONT SIZE=2>Hello,<BR>
<BR>
I have run into an odd problem.&nbsp; I am not sure if it is my issue or Twisted: any help would be appreciated.&nbsp; Under at least some circumstances, twisted.web.client seems to 1) not be able to follow a 301, and 2) throw an unhandled exception, when trying to follow a 301.&nbsp; A specific example and resulting error is given below:<BR>
<BR>
<BR>
from twisted.internet import defer<BR>
from twisted.web import client<BR>
from twisted.internet import reactor<BR>
<BR>
class HTTPGetter(client.HTTPClientFactory):<BR>
&nbsp;&nbsp;&nbsp; protocol = client.HTTPPageGetter<BR>
<BR>
class Fetcher:<BR>
<BR>
&nbsp;&nbsp;&nbsp; def __init__(self,client_factory = HTTPGetter):<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.factory = client_factory<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>
&nbsp;&nbsp;&nbsp; def download(self,host,port,url):<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f = self.factory(url)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.deferred.addCallback(self.downloadFinished).addErrback(self.downloadFailed)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; k = reactor.connectTCP(host, port, f, timeout=10)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return f.deferred<BR>
&nbsp;&nbsp;&nbsp;<BR>
&nbsp;&nbsp;&nbsp; def downloadFinished(self,v):<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print&nbsp; &quot;good&quot;<BR>
<BR>
&nbsp;&nbsp;&nbsp; def downloadFailed(self, v):<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print &quot;bad&quot;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print v<BR>
&nbsp;&nbsp;&nbsp;<BR>
r = Fetcher()<BR>
w = r.download(&quot;www.shopzilla.com&quot;,80,&quot;/aaaa&quot;)<BR>
reactor.callLater(10,reactor.stop)<BR>
reactor.run()<BR>
<BR>
This results in:<BR>
<BR>
Unhandled error in Deferred:<BR>
Traceback (most recent call last):<BR>
&nbsp; File &quot;/usr/local/lib/python2.4/site-packages/twisted/internet/posixbase.py&quot;, line 226, in mainLoop<BR>
&nbsp;&nbsp;&nbsp; self.runUntilCurrent()<BR>
&nbsp; File &quot;/usr/local/lib/python2.4/site-packages/twisted/internet/base.py&quot;, line 541, in runUntilCurrent<BR>
&nbsp;&nbsp;&nbsp; call.func(*call.args, **call.kw)<BR>
&nbsp; File &quot;/usr/local/lib/python2.4/site-packages/twisted/internet/tcp.py&quot;, line 494, in resolveAddress<BR>
&nbsp;&nbsp;&nbsp; d.addCallbacks(self._setRealAddress, self.failIfNotConnected)<BR>
&nbsp; File &quot;/usr/local/lib/python2.4/site-packages/twisted/internet/defer.py&quot;, line 182, in addCallbacks<BR>
&nbsp;&nbsp;&nbsp; self._runCallbacks()<BR>
--- &lt;exception caught here&gt; ---<BR>
&nbsp; File &quot;/usr/local/lib/python2.4/site-packages/twisted/internet/defer.py&quot;, line 307, in _runCallbacks<BR>
&nbsp;&nbsp;&nbsp; self.result = callback(self.result, *args, **kw)<BR>
&nbsp; File &quot;/usr/local/lib/python2.4/site-packages/twisted/internet/tcp.py&quot;, line 498, in _setRealAddress<BR>
&nbsp;&nbsp;&nbsp; self.doConnect()<BR>
&nbsp; File &quot;/usr/local/lib/python2.4/site-packages/twisted/internet/tcp.py&quot;, line 520, in doConnect<BR>
&nbsp;&nbsp;&nbsp; connectResult = self.socket.connect_ex(self.realAddress)<BR>
&nbsp; File &quot;&lt;string&gt;&quot;, line 1, in connect_ex<BR>
&nbsp;&nbsp;&nbsp;<BR>
exceptions.TypeError: an integer is required<BR>
<BR>
Which is apparently due to the fact that doConnect assumes a good address and so does not trap for TypeError.<BR>
<BR>
The bad address that doConnect blows up on ('',None) for (host,port) slips in due to twisted.web.client.handleStatus_301.&nbsp;&nbsp; The example site (Shopzilla.com) posts a URL for the 301 Location that is not fully qualified.&nbsp; handleStatus_301, in the face of such a URL, appears to fail because it relies on getting the host/port from the location URL, but these are not present in it.&nbsp; Thus it passes in the ('',None) to its reactor.connectTCP attempt to follow the redirect, leading to the error above.&nbsp; My kludge fix to handleStatus_301 is given below, where if the host or port are missing I steal them from the transport, which should be correct since it was just used to get the page.&nbsp; I am running with this now, with no errors.<BR>
<BR>
Is this a Twisted issue?&nbsp; If so, is my fix reasonable?&nbsp; If it is not a Twisted issue, what am I doing wrong?&nbsp;<BR>
<BR>
Thanks,<BR>
<BR>
Keith<BR>
<BR>
&nbsp;&nbsp;&nbsp; def handleStatus_301(self):<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l = self.headers.get('location')<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if not l:<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.handleStatusDefault()<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; url = l[0]<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if self.followRedirect:<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; scheme, host, port, path = \<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _parse(url, defaultPort=self.transport.getPeer().port)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.factory.setURL(url)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #following 4 lines added kad to fix apparent issue with 301 to a url that is not fully qualified<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if self.factory.host == '':<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.factory.host = self.transport.addr[0]<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if self.factory.port == None:<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.factory.port = self.transport.addr[1]<BR>
<BR>
<BR>
</FONT>
</P>

</BODY>
</HTML>