New loader class to allow workers to do xhr
BackgroundRight now, XHR uses SubresourceLoader directly, but this doesn't work well if the XHR is running on another thread (which happens for workers). As described before ( http://docs.google.com/View?docID=dg7mj9sd_6dvthmdqj&revision=_latest), I'm working on making the actual request underneath the XHR happen on the main thread for workers. Proposal To make this happen transparently, I would like to have a new loader class that is used by XHR. It is a thin wrapper over SubresourceLoader when the XHR is done for a Document, but when done on a worker, it sends messages to the main thread to do the work. I was thinking about calling the class ScriptResourceLoader. It is stripped down from SubresourceLoader / ResourceLoader to have only the items that are needed by XHR (to reduce the amount of work to be done for the Worker implementation of it). Here's what it looks like: class ScriptResourceLoader { public: static PassRefPtr<ScriptResourceLoader> create(ScriptExecutionContext*, ScriptResourceLoaderClient*, const ResourceRequest&, bool skipCanLoadCheck, bool sendResourceLoadCallbacks, bool shouldContentSniff); virtual ~ScriptResourceLoader() {} virtual void cancel() = 0; virtual void ref() = 0; virtual void deref() = 0; }; class ScriptResourceLoaderClient { public: virtual ~ScriptResourceLoaderClient() {} virtual void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent) { } virtual void didReceiveResponse(const ResourceResponse&) { } virtual void didReceiveData(const char*, int) { } virtual void didFinishLoading(int resourceIdentifer) { } virtual void didFail(bool isCancellation) { } virtual void securityOriginDenyRequest() { } virtual void receivedCancellation(const ResourceResponse&) { } }; Question Do you have any feedback about the naming of the class or its functionality? Thanks, Dave
I have a few thoughts on this. The general approach seems OK. On Dec 30, 2008, at 11:11 AM, David Levin wrote:
class ScriptResourceLoader {
I'm not sure "Script" is the right word here, but I don't have a better one. Up until now Script has meant "interface to the JavaScript interpreter" rather than objects outside that that are intended for use by script. But prefixes like "Programmatic" are uglier, so maybe we should stick with Script. Lets see if we can think of a better prefix. How were you planning on handling synchronous loads? Maybe the function for that should be here too as a static member function?
public: static PassRefPtr<ScriptResourceLoader> create(ScriptExecutionContext*, ScriptResourceLoaderClient*, const ResourceRequest&, bool skipCanLoadCheck, bool sendResourceLoadCallbacks, bool shouldContentSniff);
Despite their use in existing code I think booleans are a lousy way to handle options like these. I think we can omit skipCanLoadCheck, since it's always false for XMLHttpRequest. For the other two I would prefer something easier to read at the call site, either named enums or a flags word. The best example I could find of the named enum approach is EChildrenOnly in markup.h, although the use of an "E" prefix isn't desirable. I couldn't find a good example of a flags word. But this may be in appropriate, since we already use booleans for this purpose and you're just refactoring.
virtual ~ScriptResourceLoader() {}
ScriptResourceLoader should have a protected destructor instead of a public one. There's no legitimate reason for someone who created an object using create to call the destructor. Instead only the deref function should do that, and since it's virtual it will be a deref function specific to a particular derived class.
virtual void ref() = 0; virtual void deref() = 0;
I'll need to see more of a design to be sure that the virtual ref/ deref design is the best one for this. I understand it can be helpful to use ThreadSafeShared rather than RefCounted (or whatever those classes are named), but there are other approaches too; it's basically an implementation detail, though, not really part of the interface. I'll wait to see work that's further along.
virtual ~ScriptResourceLoaderClient() {}
This destructor should be protected rather than public. Nobody should ever delete a ScriptResourceLoaderClient given a pointer of that class. I believe the lifetime rule for these objects is that they are responsible for deleting themselves. That's a little hard to program with, but if we're sticking with it then the protected destructor helps make it clear. But the rules about when it's safe/needed for a client to delete itself should be defined as clearly as possible. I believe that certain client functions are guaranteed to be the last one received, and also if you call cancel() you're guaranteed to not get any more client function calls, but I'm not sure. This kind of lifetime rule is one of the most important things about an interface like this. I presume you'll just keep the current design.
virtual void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent) { }
It's a little strange that each didSendData call repeatedly passes the total bytes to be sent; not terrible, but strange. Like other aspects of this class it's no doubt just echoing the existing resource loader design.
virtual void didReceiveData(const char*, int) { }
I think the "int" here needs an argument name to make clear it's the size of the data.
virtual void didFinishLoading(int resourceIdentifer) { }
Does XMLHttpRequest need to know about the resource identifier? If so, how could it possibly know which identifiers to expect? Should we just omit that from this interface? Or is this part of the inspector interface? It's pretty confusing with the current name, I think.
virtual void didFail(bool isCancellation) { }
I think that the cancellation and non-cancellation functions should be separate rather than having a single call with a boolean. Like other aspects of this class it's no doubt just echoing the existing resource loader design.
virtual void securityOriginDenyRequest() { }
You're adding a new call here to indicate that the request was denied due to the security origin. It's important to use the past tense, so it's clear you're not telling the client to deny the request, but rather notifying the client that the request was already denied. A name like "didFailDueToSecurityOrigin" might be appropriate to fit in with the other client calls. Also, the name needs to express what's different about this failure that matters to the client. The practical difference in XMLHttpRequest seems to be only the call to internalAbort(), so the fact that this failure is due to a security origin check may not be the salient difference. It's possible that the important difference is the timing of the failure and the name should reflect that. Or maybe all failures could call internalAbort(), in which case this can just be didFail() and not require a separate function.
virtual void receivedCancellation(const ResourceResponse&) { }
This needs "authentication" in its name; the original function arguably doesn't need that in its name because its AuthenticationChallenge argument makes it clear what kind of cancellation we are hearing about. I don't understand our mix of "did" in some calls and "received" in others. We should be more consistent in our naming. If "did" is our way to emphasize this is a client function then it should be "didReceiveAuthenticationCancellation" or "didCancelAuthentication". We could dump the "did" prefix if we have a better naming scheme for client functions as a group. -- Darin
On Dec 30, 2008, at 12:07 PM, Darin Adler wrote:
I have a few thoughts on this. The general approach seems OK.
On Dec 30, 2008, at 11:11 AM, David Levin wrote:
class ScriptResourceLoader {
I'm not sure "Script" is the right word here, but I don't have a better one. Up until now Script has meant "interface to the JavaScript interpreter" rather than objects outside that that are intended for use by script. But prefixes like "Programmatic" are uglier, so maybe we should stick with Script. Lets see if we can think of a better prefix.
ScriptResourceLoader sounds like the name for a ResourceLoader that loads Scripts. However, this is neither a ResourceLoader (in the subclass sense), nor does it load scripts. It is just a helper class to do the loading for XMLHttpRequest. Thus I would suggest the name XHRLoader or XMLHttpRequestLoader.
How were you planning on handling synchronous loads? Maybe the function for that should be here too as a static member function?
public: static PassRefPtr<ScriptResourceLoader> create(ScriptExecutionContext*, ScriptResourceLoaderClient*, const ResourceRequest&, bool skipCanLoadCheck, bool sendResourceLoadCallbacks, bool shouldContentSniff);
Despite their use in existing code I think booleans are a lousy way to handle options like these.
I think we can omit skipCanLoadCheck, since it's always false for XMLHttpRequest. For the other two I would prefer something easier to read at the call site, either named enums or a flags word. The best example I could find of the named enum approach is EChildrenOnly in markup.h, although the use of an "E" prefix isn't desirable. I couldn't find a good example of a flags word.
But this may be in appropriate, since we already use booleans for this purpose and you're just refactoring.
I believe XHR also never does content sniffing, so sendResourceLoadCallbacks would be the only flag that could have an effect. Does it actually differ for different XHR invocations? Regards, Maciej
As part of bug https://bugs.webkit.org/show_bug.cgi?id=22720, I just added this interface (https://bugs.webkit.org/attachment.cgi?id=26855&action=diff) with the comments given in this thread largely addressed. One issue came up. Given that the "loader" will be used by both XHR and importScripts in workers. The name XMLHttpRequestLoader seemed too specific. How does ScriptExecutionContextLoader sound? (There will be Document and Worker subclasses of it: DocumentContextLoader and WorkerContextLoader.) Thanks, Dave On Wed, Dec 31, 2008 at 9:04 AM, Maciej Stachowiak <mjs@apple.com> wrote:
On Dec 30, 2008, at 12:07 PM, Darin Adler wrote:
I have a few thoughts on this. The general approach seems OK.
On Dec 30, 2008, at 11:11 AM, David Levin wrote:
class ScriptResourceLoader {
I'm not sure "Script" is the right word here, but I don't have a better one. Up until now Script has meant "interface to the JavaScript interpreter" rather than objects outside that that are intended for use by script. But prefixes like "Programmatic" are uglier, so maybe we should stick with Script. Lets see if we can think of a better prefix.
ScriptResourceLoader sounds like the name for a ResourceLoader that loads Scripts. However, this is neither a ResourceLoader (in the subclass sense), nor does it load scripts. It is just a helper class to do the loading for XMLHttpRequest. Thus I would suggest the name XHRLoader or XMLHttpRequestLoader.
How were you planning on handling synchronous loads? Maybe the function for that should be here too as a static member function?
public:
static PassRefPtr<ScriptResourceLoader> create(ScriptExecutionContext*, ScriptResourceLoaderClient*, const ResourceRequest&, bool skipCanLoadCheck, bool sendResourceLoadCallbacks, bool shouldContentSniff);
Despite their use in existing code I think booleans are a lousy way to handle options like these.
I think we can omit skipCanLoadCheck, since it's always false for XMLHttpRequest. For the other two I would prefer something easier to read at the call site, either named enums or a flags word. The best example I could find of the named enum approach is EChildrenOnly in markup.h, although the use of an "E" prefix isn't desirable. I couldn't find a good example of a flags word.
But this may be in appropriate, since we already use booleans for this purpose and you're just refactoring.
I believe XHR also never does content sniffing, so sendResourceLoadCallbacks would be the only flag that could have an effect. Does it actually differ for different XHR invocations?
Regards, Maciej
On Jan 20, 2009, at 12:55 AM, David Levin wrote:
As part of bug https://bugs.webkit.org/show_bug.cgi?id=22720, I just added this interface (https://bugs.webkit.org/attachment.cgi?id=26855&action=diff ) with the comments given in this thread largely addressed.
One issue came up. Given that the "loader" will be used by both XHR and importScripts in workers. The name XMLHttpRequestLoader seemed too specific.
How does ScriptExecutionContextLoader sound? (There will be Document and Worker subclasses of it: DocumentContextLoader and WorkerContextLoader.)
That name doesn't really clarify to me how it differs from and relates to other kinds of loaders. The name itself sounds like the class loads a script execution context, which is clearly not the case from your explanation. Or perhaps you mean that it loads on behalf of a script execution context, but is that more the case for this loader than for any other kind? Regards, Maciej
Thanks, Dave
On Wed, Dec 31, 2008 at 9:04 AM, Maciej Stachowiak <mjs@apple.com> wrote:
On Dec 30, 2008, at 12:07 PM, Darin Adler wrote:
I have a few thoughts on this. The general approach seems OK.
On Dec 30, 2008, at 11:11 AM, David Levin wrote:
class ScriptResourceLoader {
I'm not sure "Script" is the right word here, but I don't have a better one. Up until now Script has meant "interface to the JavaScript interpreter" rather than objects outside that that are intended for use by script. But prefixes like "Programmatic" are uglier, so maybe we should stick with Script. Lets see if we can think of a better prefix.
ScriptResourceLoader sounds like the name for a ResourceLoader that loads Scripts. However, this is neither a ResourceLoader (in the subclass sense), nor does it load scripts. It is just a helper class to do the loading for XMLHttpRequest. Thus I would suggest the name XHRLoader or XMLHttpRequestLoader.
How were you planning on handling synchronous loads? Maybe the function for that should be here too as a static member function?
public: static PassRefPtr<ScriptResourceLoader> create(ScriptExecutionContext*, ScriptResourceLoaderClient*, const ResourceRequest&, bool skipCanLoadCheck, bool sendResourceLoadCallbacks, bool shouldContentSniff);
Despite their use in existing code I think booleans are a lousy way to handle options like these.
I think we can omit skipCanLoadCheck, since it's always false for XMLHttpRequest. For the other two I would prefer something easier to read at the call site, either named enums or a flags word. The best example I could find of the named enum approach is EChildrenOnly in markup.h, although the use of an "E" prefix isn't desirable. I couldn't find a good example of a flags word.
But this may be in appropriate, since we already use booleans for this purpose and you're just refactoring.
I believe XHR also never does content sniffing, so sendResourceLoadCallbacks would be the only flag that could have an effect. Does it actually differ for different XHR invocations?
Regards, Maciej
On Tue, Jan 20, 2009 at 4:40 AM, Maciej Stachowiak <mjs@apple.com> wrote:
Or perhaps you mean that it loads on behalf of a script execution
context, but is that more the case for this loader than for any other kind? Yes. None of the other loaders works for a ScriptExecutionContext. Some may be suitable if you have a Document, but none simply use a ScriptExecutionContext to do the loading. My intent with this class is to allow anything that wants to work generically with a ScriptExecutionContext to be able to use this to load whatever it wants. Currently I'm starting with XHR and fitting its needs. (No need to be overly generic.) importScripts will be able to use it as well. Is ScriptContextResourceLoader a suitable name? (Resource because it loads multiple things, ScriptContext because that's what uses it and ScriptExecutionContext is too long..) Thanks again, Dave
participants (4)
-
Darin Adler
-
David Levin
-
David Levin
-
Maciej Stachowiak