Bug 14997 - Support for server-sent DOM events
: Support for server-sent DOM events
Status: RESOLVED FIXED
: WebKit
WebCore Misc.
: 523.x (Safari 3)
: All All
: P2 Enhancement
Assigned To:
: http://www.whatwg.org/specs/web-apps/...
:
: 14994 14995 14996
:
  Show dependency treegraph
 
Reported: 2007-08-16 20:03 PST by
Modified: 2009-08-15 14:25 PST (History)


Attachments
Patch which implements server-sent DOM events (101.02 KB, patch)
2007-08-16 21:34 PST, Henry Mason
aroben: review-
Review Patch | Details | Formatted Diff | Diff
Updated Patch (102.47 KB, patch)
2007-08-20 12:58 PST, Henry Mason
aroben: review-
Review Patch | Details | Formatted Diff | Diff
patch (42.24 KB, patch)
2009-04-27 14:20 PST, Adam Bergkvist
no flags Review Patch | Details | Formatted Diff | Diff
proposed patch (42.25 KB, patch)
2009-05-06 08:38 PST, Adam Bergkvist
mjs: review-
Review Patch | Details | Formatted Diff | Diff
updated patch (67.53 KB, patch)
2009-05-29 10:16 PST, Adam Bergkvist
no flags Review Patch | Details | Formatted Diff | Diff
updated patch (67.69 KB, patch)
2009-06-11 05:45 PST, Adam Bergkvist
abarth: review-
Review Patch | Details | Formatted Diff | Diff
updated patch (72.63 KB, patch)
2009-08-05 09:17 PST, Adam Bergkvist
sam: review-
Review Patch | Details | Formatted Diff | Diff
updated patch (87.68 KB, patch)
2009-08-12 09:07 PST, Adam Bergkvist
sam: review+
eric: commit‑queue-
Review Patch | Details | Formatted Diff | Diff
updated patch (91.13 KB, patch)
2009-08-13 04:49 PST, Adam Bergkvist
no flags Review Patch | Details | Formatted Diff | Diff


Note

You need to log in before you can comment on or make changes to this bug.


Description From 2007-08-16 20:03:50 PST
As currently specified in HTML 5's section 6.2, WebKit should support the mechanism for "Server-sent DOM events". This includes:

* A parser for the "application/x-dom-event-stream" stream format
* A mechanism for creating and dispatching Events after parsing is completed
* Possibly a set of test cases for this functionality?
------- Comment #1 From 2007-08-16 21:34:46 PST -------
Created an attachment (id=16003) [details]
Patch which implements server-sent DOM events

My proposed implementation for this feature.
------- Comment #2 From 2007-08-16 21:38:03 PST -------
Is this something that should go on feature-branch?
------- Comment #3 From 2007-08-17 23:13:07 PST -------
First of all, awesome patch! I am only going to comment on one part of the patch for now.

Regarding the changes to:

    WebCore/bindings/scripts/CodeGeneratorJS.pm
    WebCore/bindings/js/JSDocumentCustom.h - (new file)
    WebCore/bindings/js/JSDocumentCustom.cpp

    +Document* toDocument(KJS::JSValue* val)

A custom implementation of this function is not necessary.  You can add the [GenerateNativeConverter] extended attribute to Document.idl for the same code.
------- Comment #4 From 2007-08-17 23:52:01 PST -------
Some other bindings related issues.

In WebCore/html/HTMLEventSourceElement.idl

+module html {
+    interface [GenerateConstructor] HTMLEventSourceElement : HTMLElement {
+        attribute DOMString src;
+    };
+}

Please put spaces before and after the interface.  Also, if you are going to use the [GenerateConstructor] extended attribute (and therefore generate a JS constructor) please also add the constructor to DOMWindow.idl.  The same goes for the [GenerateConstructor] in WebCore/dom/MessageEvent.idl
------- Comment #5 From 2007-08-18 01:04:34 PST -------
(From update of attachment 16003 [details])
It's exciting to see an implementation of this part of HTML5!

Thanks for adding the new files to all 3 build systems!

Your patch has a mixture of LGPL and BSD licenses for the new files. Would you be willing to make them all BSD?

-                EnablePREfast="$(EnablePREfast)"

Please remove this change from your patch in the 3 places it occurs.

+static HashSet<String> *NonBubblingEventTypes()
+static HashSet<String> *NonCancelableEventTypes()

These functions should return a const HashSet<String>&. Their names should have a lowercase first letter. Any *s in this patch should be next to the type name, not the variable name.

+DOMEventStreamLoader::DOMEventStreamLoader(EventTargetNode *target, KURL& url)

The second parameter should be a const KURL&.

+void DOMEventStreamLoader::open()
+{
+    if (!m_isOpen) {

Please reverse the condition of this if and make it an early return. This avoids needless indentation.

+        RefPtr<SubresourceLoader> loader = SubresourceLoader::create(m_target->ownerDocument()->frame(), this, request, true, true);
+        m_loader = loader.release();

There's no need for the local loader variable. You can assign straight into m_loader.

+void DOMEventStreamLoader::close()
+{
+    if (m_isOpen) {

Please make this an early return.

+void DOMEventStreamLoader::handleEvent(Event* event, bool isWindowEvent)

Please remove the unused parameter name (release builds will break otherwise). You also don't need braces around the body of the if.

+RefPtr<EventTargetNode> DOMEventStreamLoader::getNodeFromFieldValue(String& fieldValue)

The return type should be a PassRefPtr (see <http://webkit.org/coding/RefPtr.html> for an explanation of the uses of RefPtr vs. PassRefPtr). The parameter should be a const String&.

+    if (fieldValue.isEmpty())
+        return 0;
+    else if (fieldValue[0] == '#')
+        return m_target->ownerDocument()->getElementById(fieldValue.substring(1, fieldValue.length()-1));
+    else if (fieldValue == "Document")
+        return m_target->ownerDocument();
+    else
+        return 0;

You can remove all instances of the else keyword from these lines, since they all follow return statements. You also don't need to pass a second argument to String::substring (the default argument will do the same thing for you).

+Event* DOMEventStreamLoader::createEventFromFields(HashMap<String, String>& fields)

The return type should be a PassRefPtr<Event>. The parameter should be a const HashMap<String, String>&.

+    String eventType = fields.contains("Event") ? fields.get("Event") : "message";

+    bool bubbles, cancelable;

Please declare these on separate lines (preferably right above the if-else where each is initialized).

+    Event *event;
+    PassRefPtr<WebCore::Event> eventRefPtr;

There's no need for two variables here. You should just use a single RefPtr<Event> event. (If event is not a RefPtr, you will crash!)

+        else if (eventType == messageEvent)
+            event = new MessageEvent;

There's no need for this branch (the else below will accomplish the same thing).

+    String data = fields.contains("data") ? fields.get("data") : "";
+    int detail = fields.contains("detail") ? fields.get("detail").toInt() : 0;
+    bool ctrlKey = fields.contains("ctrlKey") ? (fields.get("ctrlKey") != "false") : false;

You should make helper functions like getStringFieldValue, getIntFieldValue, getBooleanFieldValue instead of repeating these ternary operators over and over.

+    EventTargetNode* relatedTarget;
+    if (fields.contains("relatedTarget")) {
+        String relatedTargetStr = fields.get("relatedTarget");
+        RefPtr<EventTargetNode> relatedTargetRef = getNodeFromFieldValue(relatedTargetStr);
+        relatedTarget = relatedTargetRef ? relatedTargetRef.get() : 0;
+    } else 
+        relatedTarget = 0;

relatedTarget should be a RefPtr. Once you change that you won't need the relatedTargetRef local variable. You also don't need the relatedTargetStr local variable. If you initialize relatedTarget to 0 you won't need the else at all. These comments also apply to the relatedNode block below it.

+    // TODO: These fields should be used in cross-domain messaging when it is implemented

Should be a FIXME (we don't use TODO generally).

+    Document* source(0);

We would normally use = 0 instead of the constructor syntax here.

+        (static_cast<UIEvent*>(event))->initUIEvent(eventType, bubbles, cancelable, view, detail);

Don't need the parentheses around the static_cast.

+        (static_cast<SVGZoomEvent*>(event))->setNewScale(newScale);
+        (static_cast<SVGZoomEvent*>(event))->setPreviousScale(previousScale);

I think a local variable is preferable to casting twice.

+void DOMEventStreamLoader::willSendRequest(SubresourceLoader* loader, ResourceRequest& request, const ResourceResponse& redirectResponse)

Please remove the unused request parameter name.

+    if (loader != m_loader) return;

Put the return on the next line. (This happens elsewhere as well)

+        /* FIXME:
+           There is a rare unhandled case here. If we get the first byte of a CRLF ("\r\n")
+           new line in one data chunk, when we get the second chunk with an '\n' byte at the
+           start, we will wrongly parse an empty event. 
+        */

Please use C++ style comments.

+        int newLinePos, nextParseStartPos;

+        } else {
+            // No newline chars, need more data!
+            break;
+        }

I think it would be good to do:

if (lfPos < 0 && crPos < 0)
   break;

right after the calls to find(). Then this else won't be needed.

+            RefPtr<EventTargetNode> eventTarget;
+            
+            if (fields.contains("Target")) {
+                String target = fields.get("Target");
+                RefPtr<EventTargetNode> otherTarget = getNodeFromFieldValue(target);
+                eventTarget = otherTarget ? otherTarget : m_target;
+            } else
+                eventTarget = m_target;

Would be clearer/simpler as:

RefPtr<EventTargetNode> eventTarget = 0;

if (fields.contains("Target"))
    eventTarget = getNodeFromFieldValue(fields.get("Target"));

if (!eventTarget)
    eventTarget = m_target;

+            Event* event = createEventFromFields(fields);

event needs to be a RefPtr.

+            // Dispatch completed (or not), clear the fields and start parsing the next event

I don't think this comment adds any information the code doesn't already say.

+        } else if ((m_unparsedData[parseStartPos] != ';') && (m_unparsedData[parseStartPos] != ':')) {

You can reverse this and turn it into an early continue.

+            String fieldName, fieldContent;

Please declare these on separate lines.

+                fields.set(fieldName, (fields.get(fieldName) + String("\n") + fieldContent));

It seems a shame to keep appending all these strings as we go along. There must be a more efficient way to do this.

+    m_reloadTimer.startOneShot(12.0);

The 12.0 constant should go in a static const double at the top of the file.

+#include "EventListener.h"
+#include "EventTargetNode.h"
+#include "KURL.h"
+#include "SubresourceLoaderClient.h"
+#include "TextResourceDecoder.h"
+#include "Timer.h"
+
+#ifndef DOMEventStreamLoader_h
+#define DOMEventStreamLoader_h

The header guards should go above the #includes. You don't need to #include  EventTargetNode.h, you can just forward declare EventTargetNode.

+    class DOMEventStreamLoader : public EventListener, private SubresourceLoaderClient {

"private" is not needed.

+        DOMEventStreamLoader(EventTargetNode *target, KURL& url);

Please remove the parameter names as they don't add any information beyond the types.

+        void setTarget(PassRefPtr<EventTargetNode> target) { m_target = target; }

The parameter type should be an EventTargetNode*.

+        KURL *URL() { return &m_url; }

This should be:

const KURL& url() { return m_url; }

+} // namespace

Please name the namespace here.

+void EventTargetNode::addEventSource(String& src)
+{    
+    
+    if (m_eventSources.contains(src)) {

You've got an extra newline above the if. The parameter should be a const String& (ditto for removeEventSource).

+    if (m_eventSources.contains(src)) {

Please reverse this and make it an early return.

 #include "EventTarget.h"
+#include "RemoteEventTarget.h"
 #include "Node.h"
+#include "DOMEventStreamLoader.h"

Please keep the #includes lexically sorted. You should also be able to forward-declare DOMEventStreamLoader instead of #including the header.

+ * This file is part of the DOM implementation for KDE.

Please remove this line from any new files.

+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2007 Henry Mason (hmason@mac.com)
+ * Copyright (C) 2003, 2005, 2006 Apple Computer, Inc.

I don't think all these old copyrights apply to your new MessageEvent.cpp file.

+    protected:
+        
+
+    private:    

The protected: is not needed since there's nothing in it.

+        virtual void addEventSource(String& src);
+        virtual void removeEventSource(String& src);

Perhaps these should be pure virtual functions?

+    DOMEventStreamLoader *m_loader;

Please make this an OwnPtr<DOMEventStreamLoader>.

+    m_loader = new DOMEventStreamLoader((EventTargetNode*)this, kurl);

Use static_cast instead of a C-style case.

+
+#include "EventTargetNode.h"
+

I don't see why this is needed in HTTPParsers.h.

Index: LayoutTests/http/tests/domeventsource/event-source.html

It would be great to add tests of invalid values for the various fields defined in HTML5.

Index: LayoutTests/http/tests/domeventsource/remote-event-target-expected.txt

This should go inside a "resources" directory. Then run-webkit-tests will know that it's not a test itself and won't generate results for it.

\ No newline at end of file

Please add a newline.

r- so that the style can be cleaned up and the RefPtr problems can be addressed. I'm sure other people will have more comments on this patch as well.
------- Comment #6 From 2007-08-20 12:58:20 PST -------
Created an attachment (id=16038) [details]
Updated Patch

This patch addresses most of the issues brought up so far, along with some others:

- More sane use of RefPtr stuff
- Now supports adding an event source directly to a Document without crashing
- EventTargetNode now only stores a pointer to its internal URL->Stream Loader hash map, thus making nodes which don't need event sources require much less memory
- Refactored the field parsing code
- Proper handling of split CR+LF packets
- Switched to BSD license for all new code

Is there a fast way to concat strings? The + operator is what's used in KJS's array join() method...
------- Comment #8 From 2007-09-30 00:00:57 PST -------
(From update of attachment 16038 [details])
Sorry it's taken so long for me to get back to this patch. This is looking a lot nicer!

A couple more stylistic comments:

+static HashSet<String>& nonBubblingEventTypes()
+static HashSet<String>& nonCancelableEventTypes()

The return types should be const.

+DOMEventStreamLoader::DOMEventStreamLoader(EventTargetNode *target, const KURL& url)

The * should be next to EventTargetNode, not target.

+PassRefPtr<EventTargetNode> DOMEventStreamLoader::getNodeFromFieldValue(const String& fieldValue)

I was wrong before in saying that this should return a PassRefPtr. Since we're not transferring ownership, the correct return type is EventTargetNode* (as you had it originally).

+        /* Not supported in WebCore yet....
+        else if (eventType == DOMElementNamedChangedEvent || eventType == DOMAttributeNameChangeEvent)
+            event = new MutationNameEvent; */

We don't like to have commented-out code checked in to our tree. I think it would be more appropriate to have a FIXME comment here linking to a bug about supporting these event types.

+    return event;

(at the end of createEventFromFields) To be slightly more efficient, you can do:

return event.releaseRef();

+    if (loader != m_loader) return;
+    if (len < 1) return;

Please put the return on its own line, here and elsewhere.

+        const KURL& URL() { return m_url; }

In my previous comment I forgot to say that this should be a const method.

+    private:
+    
+        String getStringFieldValue(const HashMap<String, String>&, const String&, const String& defaultValue = "");
+        int getIntFieldValue(const HashMap<String, String>&, const String&, const int defaultValue = 0);
+        unsigned getUnsignedFieldValue(const HashMap<String, String>&, const String&, const unsigned defaultValue = 0);
+        unsigned short getUnsignedShortFieldValue(const HashMap<String, String>&, const String&, const unsigned short defaultValue = 0);
+        bool getBoolFieldValue(const HashMap<String, String>&, const String&, const bool defaultValue = false);
+        float getFloatFieldValue(const HashMap<String, String>&, const String&, const float defaultValue = 0.0);
+        EventTargetNode* getEventTargetNodeFieldValue(const HashMap<String, String>&, const String&, EventTargetNode* defaultValue = 0);
+        
+        PassRefPtr<EventTargetNode> getNodeFromFieldValue(const String& fieldValue);
+        PassRefPtr<Event> createEventFromFields(const HashMap<String, String>& fields);

I think these can all be static helper functions in the .cpp file, rather than being private instance methods.

+    HashMap<String, EventSourceEntry>* m_eventSources;

You could put this in an OwnPtr if you want so that you can avoid having to remember to delete it.

+#include <wtf/Forward.h>

(in RemoteEventTarget.h) I don't think this include is necessary.

I don't think this is quite ready to go in yet, but we're making nice progress!
------- Comment #9 From 2007-09-30 00:02:20 PST -------
(In reply to comment #6)
> Is there a fast way to concat strings? The + operator is what's used in KJS's
> array join() method...

One method we sometimes use is to create a Vector<UChar> and do all of the appending work on that. Then, once we're done appending, we create a String from Vector<UChar>::data().
------- Comment #10 From 2007-09-30 00:09:41 PST -------
(In reply to comment #8)
> +    return event;
> 
> (at the end of createEventFromFields) To be slightly more efficient, you can
> do:
> 
> return event.releaseRef();

Sorry, that should have been:

return event.release();
------- Comment #11 From 2007-09-30 00:14:00 PST -------
(In reply to comment #9)
> Then, once we're done appending, we create a String from Vector<UChar>::data().

What I really meant was that we pass the Vector into String::adopt().
------- Comment #12 From 2009-03-04 20:21:51 PST -------
URL should be updated to http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#server-sent-events

Note that descript ion for this issue is stale in that MIME type is now text/event-stream -
http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#parsing-an-event-stream
------- Comment #13 From 2009-04-27 14:20:31 PST -------
Created an attachment (id=29828) [details]
patch

Here's an implementation that is up to date with the current spec.
------- Comment #14 From 2009-05-06 08:38:03 PST -------
Created an attachment (id=30050) [details]
proposed patch

Updated patch since the previous one no longer applies.
------- Comment #15 From 2009-05-07 00:21:38 PST -------
Is there is a consensus about server-sent DOM events between browser vendors and other parties? I remember it raised concerns about potentially breaking NATs by using more connections per client machine on average, but I do not know how serious this concern is.
------- Comment #16 From 2009-05-07 04:42:29 PST -------
(In reply to comment #15)

I'm aware of these concerns. This initial implementation is meant to promote further discussions in the WHATWG, W3C, and IETF.
------- Comment #17 From 2009-05-07 06:07:01 PST -------
(In reply to comment #16)
> This initial implementation is meant to promote
> further discussions in the WHATWG, W3C, and IETF.

Adam, (if you don't know this already) as far as promoting it for further discussion in the W3C, the place to do that would probably best be the public-webapps@w3.org mailing list. http://lists.w3.org/Archives/Public/public-webapps/
------- Comment #18 From 2009-05-22 07:32:00 PST -------
(From update of attachment 30050 [details])
We need to add test cases for this.  They can also be disabled/skipped by default of course.  The http tests should make this possible.
------- Comment #19 From 2009-05-22 07:34:42 PST -------
(In reply to comment #18)
> (From update of attachment 30050 [details] [review])
> We need to add test cases for this.  They can also be disabled/skipped by
> default of course.  The http tests should make this possible.

Sorry, my comment may not apply.  It was mostly drive-by.  Reading more of the history this appears to be more of a speculative, framework implementation.  It will still of course need testing, but maybe you already have that planned...  Still could you some explanation about testing in the ChangeLogs.  In fact, the ChangeLog in general needs some lovin... like a link to the spec and this bug at least.
------- Comment #20 From 2009-05-24 04:35:24 PST -------
(From update of attachment 30050 [details])
Thanks for the patch! It will be good to finally have this feature. A few things need to be addressed first:

1) I think it would be ok to enable this by default for testing, unless there is some critical problem with it.

2) It would be nice if constructors (real ones like this, not fake ones like Element) could be autogenerated. I guess that is not a new issue with your patch, so you don't have to fix this right away, just noticing.

3) might be good to file a follow-up bug on this: // FIXME: should support cross-origin requests

4) EventSource::parseEventStream looks a little large for a single function. Is there a way to break it up into smaller functions for understandability?

5) A couple of times the code removes UChars from the beginning of the m_receiveBuf vector:  m_receiveBuf.remove(0, removeLen);

Removing from the start of a Vector is very inefficient. It copies almost all the contents of the vector every time. I would consider using a different data structure here. One possibility is to keep each incoming chunk of text as a separate Vector or String, and just track where you are in the current segment, and drop it once the whole thing has been processed. Another possibility is to use a Deque, which allows for relatively efficient prepend or remove from start.

6) This patch needs regression tests. I think it would be good to add http tests including both normal Window versions and Worker versions. Tests should ideally cover both normal event delivery, and handling of malformed EventSource streams, with particular attention to edge cases.

The tests are the most critical piece of feedback here. We definitely need regression tests to cover this new feature.

r- for test cases and other feedback. Please resubmit once these issues have been addressed.
------- Comment #21 From 2009-05-29 10:16:44 PST -------
Created an attachment (id=30778) [details]
updated patch

(In reply to comment #20)

Thanks for your feedback.

> 1) I think it would be ok to enable this by default for testing, unless there
> is some critical problem with it.
Done. Note that I have only updated the GTK build system since it is the platform I am testing on.

> 2) It would be nice if constructors (real ones like this, not fake ones like
> Element) could be autogenerated. I guess that is not a new issue with your
> patch, so you don't have to fix this right away, just noticing.
I am not sure how to automatically generate constructors that take arguments. This could perhaps be fixed later.

> 3) might be good to file a follow-up bug on this: // FIXME: should support
> cross-origin requests
Sure, will do that as soon as this patch is landed.

> 4) EventSource::parseEventStream looks a little large for a single function. Is
> there a way to break it up into smaller functions for understandability?
Line parsing in EventSource::parseEventStream has been extracted to a separate function (EventSource::parseEventStreamLine).

> 5) A couple of times the code removes UChars from the beginning of the
> m_receiveBuf vector:  m_receiveBuf.remove(0, removeLen);
> 
> Removing from the start of a Vector is very inefficient. It copies almost all
> the contents of the vector every time. I would consider using a different data
> structure here. One possibility is to keep each incoming chunk of text as a
> separate Vector or String, and just track where you are in the current segment,
> and drop it once the whole thing has been processed. Another possibility is to
> use a Deque, which allows for relatively efficient prepend or remove from
> start.
Removing from the beginning of the Vector is now reduced to being done when all lines in one chunk has been parsed.

> 6) This patch needs regression tests. I think it would be good to add http
> tests including both normal Window versions and Worker versions. Tests should
> ideally cover both normal event delivery, and handling of malformed EventSource
> streams, with particular attention to edge cases.
Added various tests.
------- Comment #22 From 2009-05-29 18:08:53 PST -------
This is a nice feature :) Some drive-by-comments.

About the implementation, I was under the impression that the intent was to be able to reuse the same http connection to a given event source for multiple pages. With the goal being fewer distinct hanging GETs lingering around. It looks like this patch makes a distinct request for each instance of an EventSource in all cases. Is that right? If so, maybe a FIXME (and maybe not turn it on by default quite yet?)
------- Comment #23 From 2009-06-01 00:32:33 PST -------
(In reply to comment #22)
> This is a nice feature :) Some drive-by-comments.
> 
> About the implementation, I was under the impression that the intent was to be
> able to reuse the same http connection to a given event source for multiple
> pages. With the goal being fewer distinct hanging GETs lingering around. It
> looks like this patch makes a distinct request for each instance of an
> EventSource in all cases. Is that right? If so, maybe a FIXME (and maybe not
> turn it on by default quite yet?)
> 

I don't see anything like that in the spec: <http://www.w3.org/TR/eventsource/>. The event-stream format has no support for multiplexing or suggestion that it's possible, as far as I can tell.
------- Comment #24 From 2009-06-01 12:19:45 PST -------
You're right. I'm not sure why I was under that impression? Although, now I have a greater appreciation of the concerns alluded to earlier about exceeding connection limits :)

I very much like that this feature formalizes support for the commonly performed 'hanging get', and alleviates some of the webapp busy work involved to do so.

> This initial implementation is meant to promote
> further discussions in the WHATWG, W3C, and IETF.

Maybe when that discussion continues, ways to reduce the cost of long lived connections in some use cases can be a part of it.
------- Comment #25 From 2009-06-11 05:45:58 PST -------
Created an attachment (id=31160) [details]
updated patch

Updated patch to reflect recent changes to ThreadableLoader.

Also replaced remove() with clear() when removing all elements from the m_receiveBuf vector.
------- Comment #26 From 2009-07-15 21:28:07 PST -------
(From update of attachment 31160 [details])

> +static JSObject* constructEventSource(ExecState* exec, JSObject* constructor, const ArgList& args)
> +{
> +    if (args.size() == 0)
> +        return throwError(exec, SyntaxError, "Not enough arguments");

Out approach is ussually to just all the the toString conversion go to work on the undefined value instead of checking the number of args here. Is this called out for specifically in the spec?

One thing we should definitely look into doing is writing a fuzzer for this new parser.  Otherwise, this looks great, thanks for keeping it up to date and hanging in there for this ridiculous long time. r=me.
------- Comment #27 From 2009-07-24 01:26:04 PST -------
Will land.
------- Comment #28 From 2009-07-24 01:28:44 PST -------
(From update of attachment 31160 [details])
I tried to land this, but the patch did not apply cleanly to a top-of-tree checkout:

1 out of 3 hunks FAILED -- saving rejects to file configure.ac.rej

I haven't looked whether the merge is trivial.  Can you post an updated patch that applies cleanly?  Thanks.
------- Comment #29 From 2009-07-24 07:35:34 PST -------
I think EventSource code should call nonCacheRequestInFlight(), similarly to how XMLHttpRequest does it. If it does not, other connections may stall indefinitely with some network back-ends.
------- Comment #30 From 2009-07-24 15:35:32 PST -------
+        void disconnect();

I believe this doesn't match the current spec - disconnect has been renamed to close. I do not know if there were more spec changes in the meanwhile.
------- Comment #31 From 2009-08-05 09:17:17 PST -------
Created an attachment (id=34139) [details]
updated patch

Updated patch to reflect recent changes in the spec as well as in WebKit.

Fixes:
* Renamed disconnect to close according to spec changes (and updated tests)
* Added connection limit counting fix (nonCacheRequestInFlight/Complete)
* Updated calls to set/unsetPendingActivity according to new garbage collection rules in the spec
* Added EventSource to the Qt build system

Since r45558 events are delayed until 512 bytes have been received with the Soup backend due to content sniffing always being enabled (see https://bugs.webkit.org/show_bug.cgi?id=27981).
------- Comment #32 From 2009-08-07 13:50:27 PST -------
(From update of attachment 34139 [details])
> Index: ChangeLog
> ===================================================================
> --- ChangeLog	(revision 46804)
> +++ ChangeLog	(working copy)
> @@ -1,3 +1,12 @@
> +2009-08-05  Adam Bergkvist  <adam.bergkvist@ericsson.com>
> +
> +        Reviewed by NOBODY (OOPS!).
> +
> +        [GTK] Added EventSource to the build (default on).
> +        https://bugs.webkit.org/show_bug.cgi?id=14997
> +
> +        * configure.ac:
> +
>  2009-08-05  Jan Michael Alonzo  <jmalonzo@webkit.org>
>  
>          Reviewed by Xan Lopez.
> Index: configure.ac
> ===================================================================
> --- configure.ac	(revision 46804)
> +++ configure.ac	(working copy)
> @@ -348,6 +348,14 @@ AC_ARG_ENABLE(database,
>                [],[enable_database="yes"])
>  AC_MSG_RESULT([$enable_database])
>  
> +# check whether to build with server-sent events support
> +AC_MSG_CHECKING([whether to enable HTML5 server-sent events support])
> +AC_ARG_ENABLE(eventsource,
> +              AC_HELP_STRING([--enable-eventsource],
> +                             [enable HTML5 server-sent events support [default=yes]]),
> +              [],[enable_eventsource="yes"])
> +AC_MSG_RESULT([$enable_eventsource])
> +
>  # check whether to build with icon database support
>  AC_MSG_CHECKING([whether to enable icon database support])
>  AC_ARG_ENABLE(icon_database,
> @@ -702,6 +710,7 @@ AM_CONDITIONAL([ENABLE_JAVASCRIPT_DEBUGG
>  AM_CONDITIONAL([ENABLE_OFFLINE_WEB_APPLICATIONS],[test "$enable_offline_web_applications" = "yes"])
>  AM_CONDITIONAL([ENABLE_DOM_STORAGE],[test "$enable_dom_storage" = "yes"])
>  AM_CONDITIONAL([ENABLE_DATABASE],[test "$enable_database" = "yes"])
> +AM_CONDITIONAL([ENABLE_EVENTSOURCE],[test "$enable_eventsource" = "yes"])
>  AM_CONDITIONAL([ENABLE_ICONDATABASE],[test "$enable_icon_database" = "yes"])
>  AM_CONDITIONAL([ENABLE_XPATH],[test "$enable_xpath" = "yes"])
>  AM_CONDITIONAL([ENABLE_XSLT],[test "$enable_xslt" = "yes"])
> @@ -758,6 +767,7 @@ Features:
>   HTML5 client-side session and persistent storage support : $enable_dom_storage
>   HTML5 client-side database storage support               : $enable_database
>   HTML5 ruby support                                       : $enable_ruby
> + HTML5 server-sent events support                         : $enable_eventsource
>   HTML5 video element support                              : $enable_video
>   Icon database support                                    : $enable_icon_database
>   SharedWorkers support                                    : $enable_shared_workers
> Index: WebCore/ChangeLog
> ===================================================================
> --- WebCore/ChangeLog	(revision 46804)
> +++ WebCore/ChangeLog	(working copy)
> @@ -1,3 +1,87 @@
> +2009-08-05  Adam Bergkvist  <adam.bergkvist@ericsson.com>
> +
> +        Reviewed by NOBODY (OOPS!).
> +
> +        Added implementation of the EventSource object that enables
> +        server-sent events from HTML5.
> +        http://dev.w3.org/html5/eventsource/
> +        https://bugs.webkit.org/show_bug.cgi?id=14997
> +
> +        Tests: fast/eventsource/eventsource-attribute-listeners.html
> +               fast/eventsource/eventsource-constructor.html
> +               http/tests/eventsource/eventsource-bad-mime-type.html
> +               http/tests/eventsource/eventsource-parse-event-stream.html
> +               http/tests/eventsource/eventsource-reconnect.html
> +               http/tests/eventsource/eventsource-status-code-states.html
> +               http/tests/eventsource/workers/eventsource-simple.html
> +
> +        * GNUmakefile.am:
> +        * WebCore.pro:
> +        * bindings/js/JSDOMWindowCustom.cpp:
> +        (WebCore::JSDOMWindow::eventSource):
> +        * bindings/js/JSEventSourceConstructor.cpp: Added.
> +        (WebCore::):
> +        (WebCore::JSEventSourceConstructor::JSEventSourceConstructor):
> +        (WebCore::JSEventSourceConstructor::scriptExecutionContext):
> +        (WebCore::constructEventSource):
> +        (WebCore::JSEventSourceConstructor::getConstructData):
> +        (WebCore::JSEventSourceConstructor::mark):
> +        * bindings/js/JSEventSourceConstructor.h: Added.
> +        (WebCore::JSEventSourceConstructor::classInfo):
> +        * bindings/js/JSEventSourceCustom.cpp: Added.
> +        (WebCore::JSEventSource::mark):
> +        (WebCore::JSEventSource::addEventListener):
> +        (WebCore::JSEventSource::removeEventListener):
> +        * bindings/js/JSEventTarget.cpp:
> +        (WebCore::toJS):
> +        (WebCore::toEventTarget):
> +        * bindings/js/JSWorkerContextCustom.cpp:
> +        (WebCore::JSWorkerContext::eventSource):
> +        * dom/EventNames.h:
> +        * dom/EventTarget.cpp:
> +        (WebCore::EventTarget::toEventSource):
> +        * dom/EventTarget.h:
> +        * page/DOMWindow.idl:
> +        * page/EventSource.cpp: Added.
> +        (WebCore::EventSource::EventSource):
> +        (WebCore::EventSource::~EventSource):
> +        (WebCore::EventSource::connect):
> +        (WebCore::EventSource::endRequest):
> +        (WebCore::EventSource::scheduleReconnect):
> +        (WebCore::EventSource::reconnectTimerFired):
> +        (WebCore::EventSource::url):
> +        (WebCore::EventSource::readyState):
> +        (WebCore::EventSource::close):
> +        (WebCore::EventSource::scriptExecutionContext):
> +        (WebCore::EventSource::addEventListener):
> +        (WebCore::EventSource::removeEventListener):
> +        (WebCore::EventSource::dispatchEvent):
> +        (WebCore::EventSource::didReceiveResponse):
> +        (WebCore::EventSource::didReceiveData):
> +        (WebCore::EventSource::didFinishLoading):
> +        (WebCore::EventSource::didFail):
> +        (WebCore::EventSource::didFailRedirectCheck):
> +        (WebCore::EventSource::parseEventStream):
> +        (WebCore::EventSource::parseEventStreamLine):
> +        (WebCore::EventSource::dispatchGenericEvent):
> +        (WebCore::EventSource::dispatchMessageEvent):
> +        (WebCore::EventSource::stop):
> +        * page/EventSource.h: Added.
> +        (WebCore::EventSource::create):
> +        (WebCore::EventSource::):
> +        (WebCore::EventSource::setOnopen):
> +        (WebCore::EventSource::onopen):
> +        (WebCore::EventSource::setOnmessage):
> +        (WebCore::EventSource::onmessage):
> +        (WebCore::EventSource::setOnerror):
> +        (WebCore::EventSource::onerror):
> +        (WebCore::EventSource::toEventSource):
> +        (WebCore::EventSource::eventListeners):
> +        (WebCore::EventSource::refEventTarget):
> +        (WebCore::EventSource::derefEventTarget):
> +        * page/EventSource.idl: Added.
> +        * workers/WorkerContext.idl:
> +
>  2009-08-05  Andras Becsi  <becsi.andras@stud.u-szeged.hu>
>  
>          Reviewed by Simon Hausmann.
> Index: WebCore/GNUmakefile.am
> ===================================================================
> --- WebCore/GNUmakefile.am	(revision 46804)
> +++ WebCore/GNUmakefile.am	(working copy)
> @@ -237,6 +237,7 @@ IDL_BINDINGS += \
>  	WebCore/page/Coordinates.idl \
>  	WebCore/page/DOMSelection.idl \
>  	WebCore/page/DOMWindow.idl \
> +	WebCore/page/EventSource.idl \
>  	WebCore/page/Geolocation.idl \
>  	WebCore/page/Geoposition.idl \
>  	WebCore/page/History.idl \
> @@ -339,6 +340,9 @@ webcore_sources += \
>  	WebCore/bindings/js/JSEventCustom.cpp \
>  	WebCore/bindings/js/JSEventListener.cpp \
>  	WebCore/bindings/js/JSEventListener.h \
> +	WebCore/bindings/js/JSEventSourceConstructor.cpp \
> +	WebCore/bindings/js/JSEventSourceConstructor.h \
> +	WebCore/bindings/js/JSEventSourceCustom.cpp \
>  	WebCore/bindings/js/JSEventTarget.cpp \
>  	WebCore/bindings/js/JSEventTarget.h \
>  	WebCore/bindings/js/JSGeolocationCustom.cpp \
> @@ -1263,6 +1267,8 @@ webcore_sources += \
>  	WebCore/page/EditorClient.h \
>  	WebCore/page/EventHandler.cpp \
>  	WebCore/page/EventHandler.h \
> +	WebCore/page/EventSource.cpp \
> +	WebCore/page/EventSource.h \
>  	WebCore/page/FocusController.cpp \
>  	WebCore/page/FocusController.h \
>  	WebCore/page/FocusDirection.h \
> @@ -2114,6 +2120,20 @@ webcore_cppflags += -DENABLE_DATABASE=0
>  endif # END ENABLE_DATABASE
>  
>  # ----
> +# HTML5 server-sent events
> +# ----
> +if !ENABLE_EVENTSOURCE
> +global_cppflags += -DENABLE_EVENTSOURCE=0
> +endif
> +
> +if ENABLE_EVENTSOURCE
> +FEATURE_DEFINES_JAVASCRIPT += ENABLE_EVENTSOURCE=1
> +
> +webcore_cppflags += \
> +	-DENABLE_EVENTSOURCE=1
> +endif # ENABLE_EVENTSOURCE
> +
> +# ----
>  # HTML5 client-side session and persistent storage
>  # ----
>  if ENABLE_DOM_STORAGE
> Index: WebCore/WebCore.pro
> ===================================================================
> --- WebCore/WebCore.pro	(revision 46804)
> +++ WebCore/WebCore.pro	(working copy)
> @@ -106,6 +106,7 @@ contains(DEFINES, ENABLE_SINGLE_THREADED
>  
>  !contains(DEFINES, ENABLE_JAVASCRIPT_DEBUGGER=.): DEFINES += ENABLE_JAVASCRIPT_DEBUGGER=1
>  !contains(DEFINES, ENABLE_DATABASE=.): DEFINES += ENABLE_DATABASE=1
> +!contains(DEFINES, ENABLE_EVENTSOURCE=.): DEFINES += ENABLE_EVENTSOURCE=1
>  !contains(DEFINES, ENABLE_OFFLINE_WEB_APPLICATIONS=.): DEFINES += ENABLE_OFFLINE_WEB_APPLICATIONS=1
>  !contains(DEFINES, ENABLE_DOM_STORAGE=.): DEFINES += ENABLE_DOM_STORAGE=1
>  !contains(DEFINES, ENABLE_ICONDATABASE=.): DEFINES += ENABLE_ICONDATABASE=1
> @@ -425,6 +426,7 @@ IDL_BINDINGS += \
>      page/Coordinates.idl \
>      page/DOMSelection.idl \
>      page/DOMWindow.idl \
> +    page/EventSource.idl \
>      page/Geolocation.idl \
>      page/Geoposition.idl \
>      page/History.idl \
> @@ -486,6 +488,8 @@ SOURCES += \
>      bindings/js/JSDOMWindowShell.cpp \
>      bindings/js/JSElementCustom.cpp \
>      bindings/js/JSEventCustom.cpp \
> +    bindings/js/JSEventSourceConstructor.cpp \
> +    bindings/js/JSEventSourceCustom.cpp \
>      bindings/js/JSEventTarget.cpp \
>      bindings/js/JSGeolocationCustom.cpp \
>      bindings/js/JSHTMLAllCollection.cpp \
> @@ -916,6 +920,7 @@ SOURCES += \
>      page/NavigatorBase.cpp \
>      page/DragController.cpp \
>      page/EventHandler.cpp \
> +    page/EventSource.cpp \
>      page/FocusController.cpp \
>      page/Frame.cpp \
>      page/FrameTree.cpp \
> @@ -1162,6 +1167,7 @@ HEADERS += \
>      bindings/js/JSDOMWindowCustom.h \
>      bindings/js/JSDOMWindowShell.h \
>      bindings/js/JSEventListener.h \
> +    bindings/js/JSEventSourceConstructor.h \
>      bindings/js/JSEventTarget.h \
>      bindings/js/JSHistoryCustom.h \
>      bindings/js/JSHTMLAllCollection.h \
> @@ -1586,6 +1592,7 @@ HEADERS += \
>      page/DOMWindow.h \
>      page/DragController.h \
>      page/EventHandler.h \
> +    page/EventSource.h \
>      page/FocusController.h \
>      page/Frame.h \
>      page/FrameTree.h \
> @@ -2264,6 +2271,10 @@ contains(DEFINES, ENABLE_DATAGRID=1) {
>      FEATURE_DEFINES_JAVASCRIPT += ENABLE_DATAGRID=1
>  }
>  
> +contains(DEFINES, ENABLE_EVENTSOURCE=1) {
> +    FEATURE_DEFINES_JAVASCRIPT += ENABLE_EVENTSOURCE=1
> +}
> +
>  contains(DEFINES, ENABLE_SQLITE=1) {
>      !system-sqlite:exists( $${SQLITE3SRCDIR}/sqlite3.c ) {
>              # Build sqlite3 into WebCore from source
> Index: WebCore/bindings/js/JSDOMWindowCustom.cpp
> ===================================================================
> --- WebCore/bindings/js/JSDOMWindowCustom.cpp	(revision 46804)
> +++ WebCore/bindings/js/JSDOMWindowCustom.cpp	(working copy)
> @@ -38,6 +38,7 @@
>  #include "JSDOMWindowShell.h"
>  #include "JSEvent.h"
>  #include "JSEventListener.h"
> +#include "JSEventSourceConstructor.h"
>  #include "JSHTMLCollection.h"
>  #include "JSHistory.h"
>  #include "JSImageConstructor.h"
> @@ -424,6 +425,13 @@ JSValue JSDOMWindow::event(ExecState* ex
>      return toJS(exec, event);
>  }
>  
> +#if ENABLE(EVENTSOURCE)
> +JSValue JSDOMWindow::eventSource(ExecState* exec) const
> +{
> +    return getDOMConstructor<JSEventSourceConstructor>(exec, this);
> +}
> +#endif
> +
>  JSValue JSDOMWindow::image(ExecState* exec) const
>  {
>      return getDOMConstructor<JSImageConstructor>(exec, this);
> Index: WebCore/bindings/js/JSEventSourceConstructor.cpp
> ===================================================================
> --- WebCore/bindings/js/JSEventSourceConstructor.cpp	(revision 0)
> +++ WebCore/bindings/js/JSEventSourceConstructor.cpp	(revision 0)
> @@ -0,0 +1,99 @@
> +/*
> + * Copyright (C) 2009 Ericsson AB
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + *
> + * 1. Redistributions of source code must retain the above copyright
> + *    notice, this list of conditions and the following disclaimer.
> + * 2. Redistributions in binary form must reproduce the above copyright
> + *    notice, this list of conditions and the following disclaimer
> + *    in the documentation and/or other materials provided with the
> + *    distribution.
> + * 3. Neither the name of Ericsson nor the names of its contributors
> + *    may be used to endorse or promote products derived from this
> + *    software without specific prior written permission.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + */
> +
> +#include "config.h"
> +
> +#if ENABLE(EVENTSOURCE)
> +
> +#include "JSEventSourceConstructor.h"
> +
> +#include "EventSource.h"
> +#include "ExceptionCode.h"
> +#include "JSEventSource.h"
> +#include "ScriptExecutionContext.h"
> +
> +using namespace JSC;
> +
> +namespace WebCore {
> +
> +ASSERT_CLASS_FITS_IN_CELL(JSEventSourceConstructor);
> +
> +const ClassInfo JSEventSourceConstructor::s_info = { "EventSourceContructor", 0, 0, 0 };
> +
> +JSEventSourceConstructor::JSEventSourceConstructor(ExecState* exec, JSDOMGlobalObject* globalObject)
> +    : DOMObject(JSEventSourceConstructor::createStructure(exec->lexicalGlobalObject()->objectPrototype()))

This should inherit from DOMConstructorObject

> +    , m_globalObject(globalObject)
> +{
> +    putDirect(exec->propertyNames().prototype, JSEventSourcePrototype::self(exec, exec->lexicalGlobalObject()), None);

This should use the passed in global object instead of the lexical global object.

> +    putDirect(exec->propertyNames().length, jsNumber(exec, 1), ReadOnly|DontDelete|DontEnum);
> +}
> +
> +ScriptExecutionContext* JSEventSourceConstructor::scriptExecutionContext() const
> +{
> +    return m_globalObject->scriptExecutionContext();
> +}
> +
> +static JSObject* constructEventSource(ExecState* exec, JSObject* constructor, const ArgList& args)
> +{
> +    if (args.size() == 0)
> +        return throwError(exec, SyntaxError, "Not enough arguments");
> +
> +    UString url = args.at(0).toString(exec);
> +    if (exec->hadException())
> +        return 0;
> +
> +    ScriptExecutionContext* context = static_cast<JSEventSourceConstructor*>(constructor)->scriptExecutionContext();
> +    if (!context)
> +        return throwError(exec, ReferenceError, "EventSource constructor associated document is unavailable");
> +
> +    ExceptionCode ec = 0;
> +    RefPtr<EventSource> eventSource = EventSource::create(url, context, ec);
> +    setDOMException(exec, ec);
> +
> +    return asObject(toJS(exec, eventSource.release()));
> +}
> +
> +ConstructType JSEventSourceConstructor::getConstructData(ConstructData& constructData)
> +{
> +    constructData.native.function = constructEventSource;
> +    return ConstructTypeHost;
> +}
> +
> +void JSEventSourceConstructor::mark()
> +{
> +    DOMObject::mark();
> +    if (!m_globalObject->marked())
> +        m_globalObject->mark();
> +}

This method will not be necessary if you inherit from DOMConstructorObject.


> +#if ENABLE(EVENTSOURCE)
> +    if (EventSource* eventSource = target->toEventSource())
> +        return getCachedDOMObjectWrapper(exec->globalData(), eventSource);

This should use toJS(exec, globalObject, eventSource);


In addition, the new files need to be added to all the project files (xcode, vcproj, etc.) and DerivedSources.make needs to be updated.

r-
------- Comment #33 From 2009-08-12 09:07:03 PST -------
Created an attachment (id=34665) [details]
updated patch

Thank you for the quick review and sorry for not noticing the recent addition of the DOMConstructorObject class.
Here is an updated patch that also adds EventSource to the mac and win builds (untested).
------- Comment #34 From 2009-08-12 15:29:41 PST -------
(From update of attachment 34665 [details])
Testing 11056 test cases.
fast/dom/prototype-inheritance-2.html -> failed
fast/dom/prototype-inheritance.html -> failed
fast/dom/Window/window-properties.html -> failed

This needs more tests updated.  Either the patch needs to be updated, or someone needs to do that when landing.
------- Comment #35 From 2009-08-13 04:49:08 PST -------
Created an attachment (id=34732) [details]
updated patch

Updated expected results of the affected tests.

Index: LayoutTests/fast/dom/prototype-inheritance-2-expected.txt
===================================================================
--- LayoutTests/fast/dom/prototype-inheritance-2-expected.txt    (revision 47105)
+++ LayoutTests/fast/dom/prototype-inheritance-2-expected.txt    (working copy)
@@ -77,6 +77,7 @@ PASS DataGridColumnListConstructor from 
 PASS DataGridColumnListPrototype from inner.document.activeElement.childNodes.14.columns.__proto__
 PASS DocumentPrototype from inner.document.__proto__.__proto__
 PASS ElementPrototype from inner.document.activeElement.lastElementChild.__proto__.__proto__
+PASS EventSourceContructor from inner.EventSource
 FAIL Function from inner.document.location.pathname.constructor
 PASS HTMLAnchorElement from inner.document.activeElement.firstElementChild
 PASS HTMLAnchorElementConstructor from inner.document.activeElement.firstElementChild.constructor
Index: LayoutTests/fast/dom/prototype-inheritance-expected.txt
===================================================================
--- LayoutTests/fast/dom/prototype-inheritance-expected.txt    (revision 47105)
+++ LayoutTests/fast/dom/prototype-inheritance-expected.txt    (working copy)
@@ -77,6 +77,8 @@ PASS inner.Event.isInner is true
 PASS inner.Event.constructor.isInner is true
 PASS inner.EventException.isInner is true
 PASS inner.EventException.constructor.isInner is true
+PASS inner.EventSource.isInner is true
+PASS inner.EventSource.constructor.isInner is true
 PASS inner.File.isInner is true
 PASS inner.File.constructor.isInner is true
 PASS inner.FileList.isInner is true
Index: LayoutTests/fast/dom/Window/window-properties-expected.txt
===================================================================
--- LayoutTests/fast/dom/Window/window-properties-expected.txt    (revision 47105)
+++ LayoutTests/fast/dom/Window/window-properties-expected.txt    (working copy)
@@ -857,6 +857,15 @@ window.EventException [object EventExcep
 window.EventException.UNSPECIFIED_EVENT_TYPE_ERR [number]
 window.EventException.prototype [object EventExceptionPrototype]
 window.EventException.prototype.UNSPECIFIED_EVENT_TYPE_ERR [number]
+window.EventSource [object EventSourceContructor]
+window.EventSource.prototype [object EventSourcePrototype]
+window.EventSource.prototype.CLOSED [number]
+window.EventSource.prototype.CONNECTING [number]
+window.EventSource.prototype.OPEN [number]
+window.EventSource.prototype.addEventListener [function]
+window.EventSource.prototype.close [function]
+window.EventSource.prototype.dispatchEvent [function]
+window.EventSource.prototype.removeEventListener [function]
 window.File [object FileConstructor]
 window.File.prototype [object FilePrototype]
 window.FileList [object FileListConstructor]
------- Comment #36 From 2009-08-13 10:02:53 PST -------
I will land this.
------- Comment #37 From 2009-08-15 14:05:05 PST -------
Fix landed in r47323.
------- Comment #38 From 2009-08-15 14:25:46 PST -------
Landed missing GTK piece in r47324.