Hi, I am using web2 to run a cherrypy server at the root of the site using WSGI. I've got a nearly working set up, the only problem is that when a request comes in for the root of the site, it gets redirected back to itself: % curl http://localhost:8080 This resource resides temporarily at <a href='http://localhost:8080/'> http://localhost:8080/</a> Intriguingly, if I request locations below the root, things work more OK: % curl http://localhost:8080/test/index then it works OK, even though I am registering the cherrypy at the root of the site. I've experimented, and if I register the cherrypy site in a subdir, everything works normally as expected! Here's the code that puts it at the root of the site. I've tested this code with a basic WSGI app, and it works OK. Only cherrypy seems to have this problem. One clue is that the logger shows that the URL being requested is '//' instead of '/': 2007-03-18 19:07:02-0700 [HTTPChannel,6,127.0.0.1] 127.0.0.1 - - [18/Mar/2007:19:07:02] "GET // HTTP/1.1" 302 97 "" "curl/7.15.1 (i686-suse-linux) libcurl/7.15.1 OpenSSL/0.9.8a zlib/1.2.3 libidn/0.6.0" Here's the nearly working test example: from twisted.application import service, strports from twisted.web2 import server, channel from twisted.web2 import log from twisted.web2 import wsgi from twisted.web2.wsgi import WSGIResource from cherrypy._cpwsgi import wsgiApp import cherrypy ## Basic cherrypy index object that dumps the WSGI environment class Root(object): @cherrypy.expose def index(self): s = [] for key in cherrypy.request.wsgi_environ: s.append("%s=%s<br/>" % (key, cherrypy.request.wsgi_environ [key])) return "".join(s) ## Run this site using "twistd -noy" if __name__ == '__builtin__': ## Create an instance of the root object and mount it at / r = Root() cherrypy.tree.mount(r, '/') wsgi = wsgi.WSGIResource(wsgiApp) ## Set up the cherrypy environment cherrypy.config.update({ 'server.environment':'production', 'server.socketHost':'127.0.0.1', }) ## Start the cherrypy server; don't actually run an HTTP server, though cherrypy.server.start(initOnly=True, serverClass=None) ## Setup default common access logging res = log.LogWrapperResource(wsgi) log.DefaultCommonAccessLoggingObserver().start() # Create twisted web2 site site = server.Site(res) application = service.Application("demo") ## Launch the HTTP site at port 8080 s = strports.service('tcp:8080', channel.HTTPFactory(site)) s.setServiceParent(application)
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hi David, On Mar 18, 2007, at 7:08 PM, David Konerding wrote:
Hi,
I am using web2 to run a cherrypy server at the root of the site using WSGI.
Which version of cherrypy are you using? I did an easy_install cherrypy and got 3.0.1 but your code didn't work on it. wsgiApp is somewhere else now or something.
I've got a nearly working set up, the only problem is that when a request comes in for the root of the site, it gets redirected back to itself: % curl http://localhost:8080 This resource resides temporarily at <a href='http://localhost: 8080/'> http://localhost:8080/</a>
There are only 2 places we redirect like this, if we're a subclass of resource.Resource with addSlash=True and the url didn't end in a /, and if we're a static.File attached to a directory and the url didn't end in a /. But WSGIResource does not do either of those things. Which leads me to believe that perhaps cherrypy is causing the redirect? I don't know, let me know what cherrypy version you're using and I'll try to play with it later. - -David http://dreid.org "Usually the protocol is this: I appoint someone for a task, which they are not qualified to do. Then, they have to fight a bear if they don't want to do it." -- Glyph Lefkowitz -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.5 (Darwin) iD8DBQFF//ybrsrO6aeULcgRAkQIAJwJqrAqHskSqeDtIMNy1hHS5Zvy7QCdFsZc ZHDEml2w34fkqn29IDGcGW4= =EpzH -----END PGP SIGNATURE-----
On 3/20/07, David Reid <dreid@dreid.org> wrote:
Which version of cherrypy are you using? I did an easy_install cherrypy and got 3.0.1 but your code didn't work on it. wsgiApp is somewhere else now or something.
I'm using CherryPy 2.2 which I got with TurboGears tgsetup.py. I can try CherryPy 3.0.1.
There are only 2 places we redirect like this, if we're a subclass of resource.Resource with addSlash=True and the url didn't end in a /, and if we're a static.File attached to a directory and the url didn't end in a /.
But WSGIResource does not do either of those things. Which leads me
to believe that perhaps cherrypy is causing the redirect? I don't know, let me know what cherrypy version you're using and I'll try to play with it later.
OK, and I will try to adapt my code for CherryPy 3.0.1 as well. If the problem goes away with newer code, then I'm fine with it. It's almost certainly cherrypy causing the redirect: using the WSGI app from the twisted web2 demo, I don't see the same kind of problem. I still think this is a good clue: 2007-03-20 08:39:48-0700 [HTTPChannel,0,127.0.0.1] 127.0.0.1 - - [20/Mar/2007:08:39:48] "GET // HTTP/1.1" 302 97 "" "curl/7.15.1 (i686-suse-linux) libcurl/7.15.1 OpenSSL/0.9.8a zlib/1.2.3 libidn/0.6.0" 2007-03-20 08:39:48-0700 [-] 127.0.0.1 - - [20/Mar/2007:08:39:48 -0700] "GET / HTTP/1.1" 302 97 "-" "curl/7.15.1 (i686-suse-linux) libcurl/7.15.1 OpenSSL/0.9.8a zlib/1.2.3 libidn/0.6.0" Note the 'GET //': I can't tell if that's the logging line coming from Twisted or from CherryPy. Dave
Which version of cherrypy are you using? I did an easy_install cherrypy and got 3.0.1 but your code didn't work on it. wsgiApp is somewhere else now or something.
OK, I've updated my test example to work with CherryPy 3.0. This works a bit better, in fact, when I visit the root of the site I get my cherrypy application! Since I'm not tied to CherryPy 2.2 (unless TurboGears requires it) this 'fixes' most of my problem. I'm still having a problem if I access some URLs under the root, but I have yet to determine if it's going to be a problem. Here's a CherryPy 3.0.1 application that works with Twisted web2 using the WSGI app support. from twisted.internet import reactor from twisted.application import service, strports from twisted.web2 import server, channel from twisted.web2 import log from twisted.web2 import wsgi from twisted.web2.wsgi import WSGIResource import cherrypy ## Basic cherrypy index object that dumps the WSGI environment class Root(object): @cherrypy.expose def index(self): s = [] for key in cherrypy.request.wsgi_environ: s.append("%s=%s<br/>" % (key, cherrypy.request.wsgi_environ [key])) return "".join(s) ## Create an instance of the root application and mount it at / r = Root() ## Convert the Root application to a hostable WSGI application cpwsgiapp = cherrypy.Application(Root(), '/') ## Convert the CherryPy WSGI app to a Twisted WSGI resource wsgi = wsgi.WSGIResource(cpwsgiapp) ## Set up the cherrypy environment cherrypy.config.update({ 'server.environment':'production', }) ## Start the cherrypy engine without starting a blocking server cherrypy.engine.start(blocking=False) ## Setup default common access logging res = log.LogWrapperResource(wsgi) log.DefaultCommonAccessLoggingObserver().start() # Create twisted web2 site site = server.Site(res) ## Launch the HTTP site at port 8080 ## code path invoked by twistd if __name__ == '__builtin__': application = service.Application("demo") s = strports.service('tcp:8080', channel.HTTPFactory(site)) s.setServiceParent(application) ## code path when run directly if __name__ == '__main__': from twisted.python import log as pythonlog import sys pythonlog.startLogging(sys.stdout) reactor.listenTCP(8080, channel.HTTPFactory(site)) reactor.run()
Here is a fix. It looks like a bug in twisted.web2.twcgi to me. Cherrypy is confused by the "//". -josh > svn diff Index: twcgi.py =================================================================== --- twcgi.py (revision 19890) +++ twcgi.py (working copy) @@ -51,7 +51,7 @@ if request.postpath: # Should we raise an exception if this contains "/" chars? - env["PATH_INFO"] = '/' + '/'.join(request.postpath) + env["PATH_INFO"] = '/'.join(request.postpath) # MUST always be present, even if no query env["QUERY_STRING"] = request.querystring On Mar 20, 2007, at 8:55 AM, David Konerding wrote: > > > > Which version of cherrypy are you using? I did an easy_install > cherrypy and got 3.0.1 but your code didn't work on it. wsgiApp is > somewhere else now or something. > > > OK, I've updated my test example to work with CherryPy 3.0. This > works a bit better, > in fact, when I visit the root of the site I get my cherrypy > application! Since > I'm not tied to CherryPy 2.2 (unless TurboGears requires it) this > 'fixes' most of my problem. > I'm still having a problem if I access some URLs under the root, > but I have yet to determine if it's going > to be a problem. > > Here's a CherryPy 3.0.1 application that works with Twisted web2 > using the WSGI app support. > > from twisted.internet import reactor > from twisted.application import service, strports > from twisted.web2 import server, channel > from twisted.web2 import log > from twisted.web2 import wsgi > from twisted.web2.wsgi import WSGIResource > import cherrypy > > ## Basic cherrypy index object that dumps the WSGI environment > class Root(object): > @cherrypy.expose > def index(self): > s = [] > for key in cherrypy.request.wsgi_environ: > s.append("%s=%s<br/>" % (key, > cherrypy.request.wsgi_environ [key])) > > return "".join(s) > > ## Create an instance of the root application and mount it at / > r = Root() > > ## Convert the Root application to a hostable WSGI application > cpwsgiapp = cherrypy.Application(Root(), '/') > > ## Convert the CherryPy WSGI app to a Twisted WSGI resource > wsgi = wsgi.WSGIResource(cpwsgiapp) > > ## Set up the cherrypy environment > cherrypy.config.update({ > 'server.environment':'production', > }) > > ## Start the cherrypy engine without starting a blocking server > cherrypy.engine.start(blocking=False) > > ## Setup default common access logging > res = log.LogWrapperResource(wsgi) > log.DefaultCommonAccessLoggingObserver().start() > > # Create twisted web2 site > site = server.Site(res) > > ## Launch the HTTP site at port 8080 > > ## code path invoked by twistd > if __name__ == '__builtin__': > application = service.Application("demo") > s = strports.service('tcp:8080', channel.HTTPFactory(site)) > s.setServiceParent(application) > > ## code path when run directly > if __name__ == '__main__': > from twisted.python import log as pythonlog > import sys > pythonlog.startLogging(sys.stdout) > reactor.listenTCP(8080, channel.HTTPFactory (site)) > reactor.run() > > > > _______________________________________________ > Twisted-web mailing list > Twisted-web@twistedmatrix.com > http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-web
participants (3)
-
David Konerding
-
David Reid
-
Joshua Boverhof