[Web-SIG] Web Container Interface

Phillip J. Eby pje at telecommunity.com
Sat Jan 24 23:03:10 EST 2004


At 01:05 PM 1/24/04 -0600, Ian Bicking wrote:
>>>Or, the application may want to know something about the URL layout. 
>>>Mmm... which makes me think that PATH_INFO and SCRIPT_NAME need to be 
>>>well defined for runCGI, or alternate variables need to be considered. 
>>>Does SCRIPT_NAME (and several associated CGI variables, PATH_INFO 
>>>included) point to the application, or the container, or what?
>>
>>An excellent point.  That *should* be added to the spec.  I simply 
>>assumed they point to the object that is receiving the runCGI() call.
>>It should be made explicit, though.  Thanks!
>
>Hmm... that might not be backward compatible.  In both Webware and I 
>believe Zope (and probably several others) these point to the container 
>root, not the resource root.

Um, that's a container issue, not an app issue.  AFAIK, all existing apps 
expect SCRIPT_NAME to point to the *app* root.  Also AFAIK, no generic WCI 
containers exist yet except the ones in PEAK, and they all just pass 
SCRIPT_NAME as pointing to the app they're running.  This works just fine 
with Zope 2 and 3, as well as any properly written CGI.

However, if you were to create a container that routed requests, then it 
would need to remove any parts from PATH_INFO that it consumes, and add 
them to SCRIPT_NAME, so that the application being run can use 
HTTP_HOST+SCRIPT_NAME to form a URL to the application.

I am, however, beginning to see the awkwardness of "container" and 
"app".  I'm wondering if maybe "gateway" and "service" would be better 
terms, and rename the whole thing the Python Web Service Gateway 
Interface.  That is, the WSGI, perhaps to be pronounced "whisky".  :)

Anyway, it would then make sense that the values supplied by a gateway to a 
service should be such that SCRIPT_NAME is the path of the service, 
relative to HTTP_HOST, with PATH_INFO being the remainder of the 
URL.  Since a service can also act as a gateway to nested WSGI services, it 
should of course deliver different values to them, so that they know their 
correct base URLs as well.


>Again, I'm not proposing we set out a standard that covers these, but that 
>we leave room for implementations to extend the standard to cover these cases.

Well, for Twisted, Zope, and PEAK at least, each framework has ways of 
specifying interface metadata about an object, including adapters.  So, 
gateways provided by those frameworks would be free to try to introspect a 
service for a fancier interface.

For example, PEAK has a 'suggestParentComponent()' API that can be used to 
sniff an object for PEAK component-ness (using PyProtocols), and then tell 
it what context it's being used in.  Zope 3 has getAdapter(), and Twisted 
has ISomething(ob).

None of these mechanisms require anything special in the WSGI spec to 
support them.  And even if you don't have those, there's still good old 
fashioned 'hasattr'.  You'll notice that I keep emphasizing the gateway 
inspecting and invoking the service, *not* the other way around.  There 
should not *be* anything different from one gateway to the next, if at all 
possible, since that runs counter to the whole point of the exercise, which 
is allowing the same service to run in different gateways, *especially* 
ones it wasn't written for.  That's why I want the spec to be 
mind-numbingly precise about what is and isn't required, and don't want to 
throw a vague parameter into it that has no meaning at all, existing solely 
to introduce *differences*, which are the mortal enemy of the goal of 
sameness.  :)


>I remain skeptical.  I can't really see how you'll run a Zope application 
>under plain CGI, or how both a Zope application and a Twisted application 
>could successfully run with the same interface.

They can't.  But a Twisted-specific application can run in the same process 
as a Twisted gateway that runs non-Twisted web services.  And Zope 2 and 
Zope 3 services should be runnable by any WSGI gateway: certainly I've been 
successful with them in my own gateways.  (I have an ancient Zope 2 
ZPublisher-based app that runs via a runCGI call right now as we speak, 
serving millions of dynamic hits per month.)

And, if somebody wrote a WSGI gateway for Twisted, we could finally marry 
Zope 3 and Twisted, as people have been flirting with doing for quite some 
time now.  It would have to use the Twisted threadpool, and a pool of 
service instances (Zope 3 "Publication" objects, presumably), but it 
certainly could be done.

Again, this presumes that you could configure the Twisted gateway in a way 
that would let it manage an app pool properly.  But let's say that it 
couldn't, and you had to give Twisted a single service instance that had to 
be shared for the entire web server.  Well, you'd write a WSGI service that 
simply pulled a Zope top-level instance from a pool, and invoked it as a 
subservice (leaving the 'environ' alone).  And now, your "pooling" WSGI 
service could be used with a pool of *any* WSGI service objects.

The cool thing about having a spec is, it enables this sort of bridging and 
connecting just by its very existence.  Somebody has a specific problem to 
solve, like reversing the gender of a cable, or creating a splitter or 
splicer...  instead of trying to invent wire, plugs, and sockets.  :)


>I still can see that this is a step in the right direction -- not a big 
>step, but it's still the right direction.

I think it's a bigger step, but we won't know until we try, do we?  If it 
turns out we need more, there's nothing stopping us from doing a WSGI 1.1 
after a few months.


>>Actually, I think it's more likely that a WCI 2.0 would grow another 
>>method, similar to the Java servlet 'init()' method, to tell the app that 
>>it's being "used by" a particular container.  However, at that point 
>>we'll also want to know something about what people actually want to get 
>>from a container, if anything.
>
>I think WCI 1.0 needs an init(), or something equivalent (like simply 
>passing the container in to runCGI()).  I think it is useful to provide 
>that hook, even if we give implementors no specification beyond that.
>
>A portable application might even go as far as doing:
>
>if container.__class__.__name__ == 'AppServer':
>     # Probably Webware, we'll do X
>elif container.__class__.__name__ == 'ZPublisher':
>     # Zope, we do Y
>..

Hm.  ZPublisher isn't a gateway in this spec.  It's a service.  A gateway 
would call runCGI to *get to* ZPublisher.  If you want a ZPublisher app, 
you just write a ZPublisher app.  Then, to run it, you configure a service 
wrapper around ZPublisher, and pass it to a gateway.  But if you wrote a 
ZPublisher app, you're *way* below the level of this interface.

The idea of the WCI/WSGI is to provide an HTTP gateway interface, to let 
apps built with any framework run via any sort of HTTP gateway.  That's why 
I keep saying that access to other services is an app-framework job.



>Portable applications in Python typically require some special cases as 
>issues arise -- it's better to enable developers than to enforce agnosticism.

Even so, I think it's better to have that glue controlled by the 
application's integrator, rather than buried inside.  If the service has 
options X and Y, let the integrator choose what behavior is appropriate for 
the gateway they're installing it in.  Otherwise, you're forcing the app 
developer to know about all possible gateways, which again runs counter to 
the point.

I think I see now why we seem slightly at odds in this discussion.  Your 
example suggests that you are thinking of "app" as "what I write to do 
useful work", and that you will write apps that directly export a service 
for use by a gateway.  While it's definitely possible to do this, you will 
more likely use a service wrapper that's pre-defined by your app framework 
such as Zope or Webware.  This is a way to take a Zope or Webware 
application and run it in a different server environment, not to make the 
application itself portable between Zope and Webware.

However, once the interface exists, it becomes possible to make a "router" 
service that would let you run both say, Zope and Webware applications 
within the same server environment.

But at that point, if you want to actually integrate the apps themselves 
(as opposed to simply running them side by side), again I think the 
mechanism of choice would be to write a short startup script that passes 
references to each app's internal services to the other.  At least, that's 
my take on "practicality beats purity".  Why create an abstract spec for 
passing things around, when the integrator "on the spot" can just connect 
what they need?




More information about the Web-SIG mailing list