tags:

views:

195

answers:

4

Given, when a user requests /foo on my server, I send the following HTTP response (not closing the connection):

Content-Type: multipart/x-mixed-replace; boundary=-----------------------

-----------------------
Content-Type: text/html

<a href="/bar">foo</a>

When the user goes to /bar (which will send 204 No Content so the view doesn't change), I want to send the following data in the initial response.

-----------------------
Content-Type: text/html

bar

How would could I get the second request to trigger this from the initial response? I'm planning on possibly creating a fancy [engines that support multipart/x-mixed-replace (currently only Gecko)]-only email webapp that does server-push and Ajax effects without any JavaScript, just for fun.

+1  A: 

If the problem is to pass some command from /bar application to /foo application and you are using some servlet-like approach (the Python code is loaded once and not for each request as in CGI), you can just change some class property of the /foo application and be ready to react to the change in the /foo instance (by checking the property state).

Obviously the /foo application should not return right after the first request and yield content line by line.

Thought this is just theory, I have not tried that myself.

newtover
Without using a full database (as it'd be pretty much overkill), how could I easily change a shared state object?
Eli Grey
As I said, if the code is loaded only once, then each new request is just a new instance of the application class. You can then use some module level or class (not instance) properties to exchange information.
newtover
A: 

Not sure if this is quite what you're looking for, but there is a fairly old way of doing server push using a mime content of multipart/x-mixed-replace

Basically you compose the response as a mime object with content type multipart/x-mixed-replace, and send the first "version" of a document down. The browser will keep the socket open.

Then as the server decides to push more data, a new "version" of the document gets sent from the server, and the browser will intelligently replace (within whatever frame/iframe contains the content) the content.

This was an early way of doing webcams, where the server would send down (push) image after image, and the browser would just keep replacing the image in the document over and over. This is also a way of doing a "Loading..." message over a single HTTP request.

alecf
What does have to do with answering my question? I know what `multipart/x-mixed-replace` is and how to use it, as shown in the question. I'm asking a Python wsgi question as to how I would handle this scenario.
Eli Grey
+1  A: 

No complete answer, but:

In your question, you're describing a Comet-style architecture. Regarding support of Comet-style techniques in Python/WSGI, there is a StackOverflow question, which talks about various Python servers with support for long-running requests a la Comet.

Also interesting is this mail thread in the Python Web-SIG: "Could WSGI handle Asynchronous response?". In May 2008, there was a broad discussion in the Web-SIG about the topic of asynchronous requests in WSGI.

A recent development is evserver, a lightweight WSGI server, which implements the Asynchronous WSGI extension proposed by Christopher Stawarz in the Web-SIG in May 2008.

Finally, the Tornado web server supports non-blocking asynchronous requests. It has a chat example application using long polling, which has similarities with your requirements.

flight
You may not realize it, but `multipart/x-mixed-replace` __is__ a form of Comet; the only form that doesn't require JavaScript. If I can get it working with Tornado's async requests, I'll accept this answer.
Eli Grey
**I'm** well aware that `multipart/x-mixed-replace` is a form of Comet, but I thought **you were not** ;-), since you didn't mention the buzzword in your question. I did a little bit of rewording.
flight
+1  A: 

Hi, I have created some small example (just for fun, you know :))

import threading

num = 0
cond = threading.Condition()

def app(environ, start_response):
    global num

    cond.acquire()
    num += 1
    cond.notifyAll()
    cond.release()

    start_response("200 OK", [("Content-Type", "multipart/x-mixed-replace; boundary=xxx")])
    while True:
        n = num    
        s = "--xxx\r\nContent-Type: text/html\r\n\r\n%s\n" % n
        yield s
        # wait for num change:
        cond.acquire()
        while num == n:
            cond.wait()
        cond.release()


from cherrypy.wsgiserver import CherryPyWSGIServer
server = CherryPyWSGIServer(("0.0.0.0", 3000), app)

try:
    server.start()
except KeyboardInterrupt:
    server.stop()

# Now whenever you visit http://127.0.0.1:3000/, the number increases.
# It also automatically increases in all previously opened windows/tabs.

The idea of a shared variable and thread synchronization (using condition variable object) is based on the fact that WSGI server provided by CherryPyWSGIServer is threaded.

Messa