xmlHttpRequest connection limit - detecting if a request is in the queue

M

Matt Kruse

According to HTTP/1.1 specs, a client should only have two connections open
to the host at a time (which can be changed by browser users, of course).

When using xmlHttpRequest connections, is there any way to detect that the
request is queued?
I did some tests (see "Queued Requests" at
http://www.ajaxtoolbox.com/request/examples.php ) and it looks like
readyState 1 is fired immediately after the request is made, even though
it's not actually active yet.

Is there anything else I can look at to tell if my request has been queued
and hasn't actually started running yet?
 
T

Thomas 'PointedEars' Lahn

Matt said:
According to HTTP/1.1 specs, a client should only have two connections
open to the host at a time (which can be changed by browser users, of
course).

Not quite.

,-[RFC2616: <URL:http://rfc-editor.org/rfc/rfc2616.txt>]
|
| 8.1.4 Practical Considerations
| [...]
| A single-user client SHOULD NOT maintain more than 2 connections with
| any server or proxy. [...]

And that is only a SHOULD NOT, not a MUST NOT. For HTTP/1.1 clients, not
for HTTP/1.0 clients. Therefore, it may even happen without the user
interfering.
When using xmlHttpRequest connections, is there any way to detect that
the request is queued?
^^^^^^
What do you mean by that? AFAIK, you can only make one request with one
XMLHTTPRequest object at a time (see [1]). A Web server may (and probably
will) fork a child process per connection (e.g. Apache2 prefork MPM), and
those child processes may create threads per connection (e.g. Apache2
worker MPM); but the client cannot know about that.
I did some tests (see "Queued Requests" at
http://www.ajaxtoolbox.com/request/examples.php ) and it looks like
readyState 1 is fired immediately after the request is made, even
though it's not actually active yet.

Of course XMLHTTPRequest::readyState is 1 the first time
XMLHTTPRequest::eek:nreadystatechange is called. What do you mean by
"not actually active"? If you mean that the actual HTTP request was
not made yet, you are looking for readystate == 2 (LOADED) instead.

See also
<URL:http://msdn.microsoft.com/library/en-us/xmlsdk/html/0e6a34e4-f90c-489d-acff-cb44242fafc6.asp>
<URL:http://xulplanet.com/references/objref/XMLHttpRequest.html>

BTW: I get

| Error: this.form has no properties
| Source file: http://www.ajaxtoolbox.com/request/examples.php
| Line: 1

(in Firefox 1.5.0.1/Linux) when I click one of the buttons in the
"Simultaneous Requests" section.

BTW 2: I have had to review important parts of your library now (using the
commented version), and I do think that I am going to write my own XMLHTTP
request library, unless something better comes along. I dislike your
creating a new AjaxRequest object needlessly when calling
AjaxRequest.doRequest(), for example.


HTH

PointedEars
___________
[1] news:[email protected]
 
M

Matt Kruse

Thomas said:
A single-user client SHOULD NOT maintain more than 2 connections with
any server or proxy. [...]
And that is only a SHOULD NOT, not a MUST NOT.

Which is exactly what I said. Should. Not must.
For HTTP/1.1 clients,
not for HTTP/1.0 clients.

I believe 1.0 recommended a max of 4 connections. I don't remember.
^^^^^^
What do you mean by that?

Queued by the client. It has nothing to do with the server.
If a client maintains only two connections with the server at a time, then
trying to open a third connection will cause it to wait until one of the
other two is finished.
Of course XMLHTTPRequest::readyState is 1 the first time
XMLHTTPRequest::eek:nreadystatechange is called. What do you mean by
"not actually active"? If you mean that the actual HTTP request was
not made yet, you are looking for readystate == 2 (LOADED) instead.

readyState 1 means "loading". Which is misleading. Because if the request is
queued, then it hasn't actually started loading yet. I would have expected
these requests to stay in readyState 0 until they actually opened a
connection to the server. ReadyState 2 means loaded, meaning the content has
been delivered. That is certainly not what I want.
BTW: I get
(in Firefox 1.5.0.1/Linux) when I click one of the buttons in the
"Simultaneous Requests" section.

Thanks for letting me know - fixed it. I screwed some things up while
updating the page this morning for the Queued example.
BTW 2: I have had to review important parts of your library now
(using the commented version), and I do think that I am going to
write my own XMLHTTP request library, unless something better comes
along. I dislike your creating a new AjaxRequest object needlessly
when calling AjaxRequest.doRequest(), for example.

I had considered pooling the objects and reusing them. However, my own tests
didn't show much speed improvement, if any. So for now I am not re-using
objects. If that's the only concern, then that's not too bad ;)
 
M

Michael Winter

Matt Kruse wrote:
[snip]
When using xmlHttpRequest connections, is there any way to detect that
the request is queued?
^^^^^^
What do you mean by that? AFAIK, you can only make one request with one
XMLHTTPRequest object at a time [...].

Yes, but I believe that Matt is referring to the creation and
simultaneous use of multiple objects.

[snip]

Mike
 
T

Thomas 'PointedEars' Lahn

Matt Kruse wrote:

[restored quotation level]
Thomas said:
Matt said:
According to HTTP/1.1 specs, a client should only have two connections
open
to the host at a time (which can be changed by browser users, of
course).
| A single-user client SHOULD NOT maintain more than 2 connections with
| any server or proxy. [...]
And that is only a SHOULD NOT, not a MUST NOT.

Which is exactly what I said. Should. Not must.

"should only ..." and "SHOULD NOT ... more than ..." have different meaning,
even if the "should" is capitalized.
I believe 1.0 recommended a max of 4 connections. I don't remember.

There is nothing in RFC1945 to support that. Probably you have confused
this with

| 1.3 Overall Operation
|
| [...] A tunnel acts as a relay point between two connections
| without changing the messages; tunnels are used when the
| communication needs to pass through an intermediary (such as a
| firewall) even when the intermediary cannot understand the contents
| of the messages.
|
| request chain -------------------------------------->
| UA -----v----- A -----v----- B -----v----- C -----v----- O
| <------------------------------------- response chain
|
| The figure above shows three intermediaries (A, B, and C) between the
| user agent and origin server. A request or response message that
| travels the whole chain must pass through four separate connections.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Queued by the client. It has nothing to do with the server.
If a client maintains only two connections with the server at a time, then
trying to open a third connection will cause it to wait until one of the
other two is finished.

That does not have anything with the readyState, though. The additional
HTTP connection is not opened when the XMLHTTPRequest object is created
or its open() method is called. It is opened when send() is called and
a sufficient number of arguments are provided for it. This is not only
theory; I have tested this myself with Firefox 1.5.0.1/Linux and running
`netstat -talpeen' in a tight loop in parallel.
readyState 1 means "loading". Which is misleading.

Complain to Micro$~1. They are also to blame for the fact that you have
to create a closure when using onreadystatechange.
because if the request is queued, then it hasn't actually started loading
yet.

Requests do not load, they are made. "Loading/-ed" refers to the object.
I would have expected these requests to stay in readyState 0 until
they actually opened a connection to the server. ReadyState 2 means
loaded, meaning the content has been delivered.

Not according to the MSDN Library, XULPlanet, my expectations, and
experience. readyState == 4 means the content has been delivered,
3 means that status code and headers have been received, 2 means
that send() was called (and therefore the HTTP request was made,
or "queued"), and 1 means that open() was called.


PointedEars
 
M

Michael Winter

On 20/03/2006 22:03, Matt Kruse wrote:

[snip]
I believe 1.0 recommended a max of 4 connections. I don't remember.

As I said in a previous thread, I don't believe that there are any
recommended limits for non-persistent connections. At least not in RFCs
1945 (HTTP/1.0) and 2616 (HTTP/1.1). What has been mentioned so far only
applies to persistent connections.

[snip]
If a client maintains only two connections with the server at a time,
then trying to open a third connection will cause it to wait until
one of the other two is finished.

Not necessarily. It depends upon the established capabilities of both
the client and server, as well as the form in which both requests and
responses are made.

If persistent connections are not in use (HTTP/1.0 without extensions,
or a HTTP/1.1 agent that has opted out), a third connection will
probably be opened assuming that the client hasn't established a number
of other connections for other purposes (downloading images, for example).

If persistent connections are in use, the client may attempt to pipeline
the new request; to send another request without waiting for the
response from the first. If it doesn't, then a connection will be reused
for the third request.

If the request method is non-idempotent, pipe lining should not be used.
If either a request or response has an entity body and is missing the
Content-Length header, the connection will be closed to mark the end of
that entity, necessitating the establishment of a new connection.


In all likelihood, the request will be queued. As I understand it, pipe
lining isn't utilised that much due to buggy implementations both
client- and server-side, and the vast majority of HTTP agents should use
v1.1 and support persistent connections. Of course, as noted above, how
a request or response is formed can still affect the efficiency of HTTP
connections.

[snip]

As for the issue at hand - discerning the queued state of a connection -
do you really expect consistent behaviour? I've never seen the
readyState values defined particularly well, at least at a protocol
level, and the object isn't an open standard (it's not even a standard)
so implementations are likely to differ on such issues.

Mike
 
T

Thomas 'PointedEars' Lahn

Michael said:
[...] I've never seen the readyState values defined particularly well,

Then it is about time you followed the links in my other followup.
at least at a protocol level,

"Protocol level"? The protocol used is HTTP(S).
and the object isn't an open standard (it's not even a standard)
so implementations are likely to differ on such issues.

But not on this. For example, Gecko's nsIXMLHttpRequest interface
is an implementation of Microsoft's IXMLHTTPRequest interface.


PointedEars
 
M

Matt Kruse

Thomas said:
There is nothing in RFC1945 to support that.

A quick search for http/1.0 "simultaneous connections" shows that it was a
convention more than a rule, but widely followed.
That does not have anything with the readyState, though. The
additional HTTP connection is not opened when the XMLHTTPRequest
object is created
or its open() method is called. It is opened when send() is called
and
a sufficient number of arguments are provided for it.

Not if it's queued behind other connections, it seems.
Not according to the MSDN Library, XULPlanet, my expectations, and
experience. readyState == 4 means the content has been delivered,
3 means that status code and headers have been received, 2 means
that send() was called (and therefore the HTTP request was made,
or "queued"), and 1 means that open() was called.

What reference do you have for these guesses?
What actually happens, according to my experience, is:

readystate 1 (Loading) = the request has been made and content has started
being delivered
readystate 2 (Loaded) = the content has been delivered but not yet parsed
readystate 3 (Interactive) = the content is ready for interaction, ie, it
can be scripted
readystate 4 (Complete) = the content is fully loaded, parsed, etc.

In IE, for example, you can monitor the readyState of many elements, not
just using "ajax" calls. For example,

<html>
<head><title>test</title>
<script type="text/javascript">alert(document.readyState);</script>
</head><body>test</body>
</html>

This will display "interactive" in IE. Meaning, the document object may be
interacted with via script even though it is not yet fully loaded. If you
alert document.readyState onLoad of the body, it will show "complete"
because the content has fully loaded.

In fact, this simple perl script illustrates it well:

#!/usr/local/bin/perl
$|=1;
print "Content-type: text/html\n\n";
print <<"END";
<html><head><title>test</title>
<script type="text/javascript">
alert(document.readyState);
</script>
</head>
<body>
test
END
sleep(5);
print <<"END";
<br>
test2
<script>
alert(document.readyState);
window.onload=function(){alert(document.readyState);}
</script>
</body>
</html>
END

The first alert shows "loading" because the content is not all delivered
(it's waiting on the sleep call). Then it shows "interactive" at the second
alert because the content is fully delivered. Finally it shows "complete"
after the onload event has fired.
 
T

Thomas 'PointedEars' Lahn

Matt said:
A quick search for http/1.0 "simultaneous connections" shows that it was a
convention more than a rule, but widely followed.

Care to share your findings?
Not if it's queued behind other connections, it seems.

You are not making any sense. If the XMLHTTP request is queued behind other
connections on application level, the other connection must of course be
disconnected before the new connection for the XMLHTTP request is opened.
Understand that we are _not_ dealing with another protocol, only a
different interface to it.
What reference do you have for these guesses?

The references I have repeatedly pointed you to now.
The references you are ignoring continuously in the process.
And my test results you have been ignoring as well.
What actually happens, according to my experience, is:

readystate 1 (Loading) = the request has been made and content has started
being delivered
readystate 2 (Loaded) = the content has been delivered but not yet parsed
readystate 3 (Interactive) = the content is ready for interaction, ie, it
can be scripted
readystate 4 (Complete) = the content is fully loaded, parsed, etc.

This is just plain wrong. Watch your netstat(1) or equivalent network
monitor (TCPView is great on Windows) if you do not believe neither me
nor what is specified by the vendors themselves. (Regarding Gecko-based
UAs, you can even have a look in the source code at Mozilla LXR to see
this confirmed.)
In IE, for example, you can monitor the readyState of many elements, not
just using "ajax" calls.

I thought that we are talking about XMLHTTP requests and the IXMLHTTPRequest
interface (and its implementations in other AOMs) here, so that other host
objects have such an event handler, too, in the IE DOM, would be completely
irrelevant.


PointedEars
 
R

Randy Webb

Thomas 'PointedEars' Lahn said the following on 3/21/2006 1:40 AM:
Matt Kruse wrote:


I thought that we are talking about XMLHTTP requests and the IXMLHTTPRequest
interface (and its implementations in other AOMs) here, so that other host
objects have such an event handler, too, in the IE DOM, would be completely
irrelevant.

The different states represented by readyState is very relevant.

You are a real work of art sometimes Thomas. The same tests that he used
to show you what the different states represent can be performed with an
HTTPRequest Object.
 
M

Matt Kruse

Thomas said:
Care to share your findings?

Do the search. See the same findings.
You are not making any sense. If the XMLHTTP request is queued
behind other connections on application level, the other connection
must of course be disconnected before the new connection for the
XMLHTTP request is opened. Understand that we are _not_ dealing with
another protocol, only a different interface to it.

At the JS level, I can open and send as many xmlHttpRequest objects as I
want to in my code.
But at the app/browser level, that doesn't mean they all become active
connections immediately.

Regardless of how it's implemented, the fact is that two "ajax" connections
at a time are opened back to the server and others are queued until one of
the first two finishes. Running my "Queued Requests" example at
http://www.ajaxtoolbox.com/request/examples.php clearly shows this. Clicking
all 10 buttons quickly and then running 'netstat' at the command prompt on
windows shows that only two TCP connections to the server are ever open at a
time, even though 10 send() calls have been made.

I'm not going to even argue about the readystate values, since it's just a
diversion from the original question.
 
J

Jim Ley

readyState 1 means "loading". Which is misleading. Because if the request is
queued, then it hasn't actually started loading yet. I would have expected
these requests to stay in readyState 0 until they actually opened a
connection to the server. ReadyState 2 means loaded, meaning the content has
been delivered. That is certainly not what I want.

I think you should consider the xmlhttp object talking to a local
caching proxy, thinking of it like this makes a lot of things make
sense, and would explain why it's immediately a 1 - I don't believe
there's any way to do what you want though.
I had considered pooling the objects and reusing them. However, my own tests
didn't show much speed improvement, if any. So for now I am not re-using
objects. If that's the only concern, then that's not too bad ;)

There are also quite a few differences in implementations when
re-using, probably not worth it.

Jim.
 
J

Jim Ley

What actually happens, according to my experience, is:

readystate 1 (Loading) = the request has been made and content has started
being delivered
readystate 2 (Loaded) = the content has been delivered but not yet parsed
readystate 3 (Interactive) = the content is ready for interaction, ie, it
can be scripted
readystate 4 (Complete) = the content is fully loaded, parsed, etc.

No, these aren't accurate, you can tell simply by putting a sleep in a
server script, you'll see 2 fires long before the full data is
available.

Jim.
 
T

Thomas 'PointedEars' Lahn

Matt said:
Do the search. See the same findings.

You are evading. You are trying to make the point, you are to prove it.
At the JS level, I can open and send as many xmlHttpRequest objects as I
want to in my code.

And you can. (ns)IXMLHTTPRequest::eek:pen() does _not_ mean that a HTTP
connection is opened, it is just initialization of the (ns)IXMLHTTPRequest
object. Will you please recognize that?
But at the app/browser level, that doesn't mean they all become active
connections immediately.

Regardless of how it's implemented, the fact is that two "ajax"
connections at a time are opened back to the server and others are queued
until one of the first two finishes.

This was not debated at all. (Will you please read more carefully what
was replied?) However, there are exactly _no_ additional HTTP requests
made, and so _no_ requests originating from (ns)IXMLHTTPRequest can be
ever queued, before you call the (ns)IXMLHTTPRequest::send() method.

Since calling send() is described to change IXMLHTTPRequest::readyState
to 2, and the `readyState' property value is described does not change
to 3 (status header, response headers, and maybe leading parts of the
response body received) or greater (4: response body received completely)
before any response is received for the request, 2 is the `readyState'
value you should be looking for when attempting to detect requests that
are still in a possible request queue at the application level. At
least in IE. (Geckos behave differently: with 2 it is described and
implemented that you already got the headers, so the request was made;
digging out from Mozilla LXR when readyState is set to 2 in the process
exactly is left as an exercise to the reader.)
I'm not going to even argue about the readystate values, since it's
just a diversion from the original question.

It is the whole point of your question. You just diverted from the
readyState values of (ns)IXMLHTTPRequest to the readyState values of
(IE) DOM objects, needlessly.

ISTM you have made up your mind already, and there is no argument strong
enough (not even test results of the actual implementation) to convince you
that you have a misconception. Unless you at least recognize what really
happens (and you have said nothing to deny that so far), this is EOD for
me. I have better ways to waste my time.


Score adjusted

PointedEars
 
T

Thomas 'PointedEars' Lahn

Jim said:
I think you should consider the xmlhttp object talking to a local
caching proxy, thinking of it like this makes a lot of things make
sense, and would explain why it's immediately a 1

NO connection is established before send() is called, including a possible
connection to a local caching proxy. That is at least what my tests with
Mozilla/5.0/Linux, Opera 8.52/Linux and Konqueror/3.5 have showed; which
admittedly did not include IE, though.
- I don't believe there's any way to do what you want though.

My tests combined with what MSDN Library has to say about this, indicate
that readyState == 1 is a strong indicator for a queued request. Directly
after send() is called, readyState is still 1, and that does not change
(to 2 or 3) before the connection is established.
There are also quite a few differences in implementations when
re-using, probably not worth it.

-v


PointedEars
 
J

Jim Ley

NO connection is established before send() is called, including a possible
connection to a local caching proxy.

Who said there was? I suggested you think of it as if there was an
internal as in inside the UA caching proxy, no external test is going
to show this, but like I said, it's a mental model to help you
understand the process, and not what actually happens.
My tests combined with what MSDN Library has to say about this, indicate
that readyState == 1 is a strong indicator for a queued request. Directly
after send() is called, readyState is still 1, and that does not change
(to 2 or 3) before the connection is established.

2 doesn't come along until long after a connection is established,
indeed you can not get a 2 until long after even thet status code has
arrived (try a status 100 with IE for example)

Jim.
 
T

Thomas 'PointedEars' Lahn

Jim said:
Who said there was?

Matt and you implied that.
I suggested you think of it as if there was an internal as in inside the ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

UA caching proxy, ^^^^^^^^^^^^^^^^^
Pardon?

no external test is going to show this, but like I said, it's a mental
model to help you understand the process, and not what actually happens.

Why using a proxy as an argument or a mental model if it cannot even be
involved at that stage?
2 doesn't come along until long after a connection is established,
indeed you can not get a 2 until long after even thet status code has ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
arrived (try a status 100 with IE for example)
^^^^^^^
Pardon?


PointedEars
 
J

Jim Ley

Why using a proxy as an argument or a mental model if it cannot even be
involved at that stage?

The proxy is inside the browser, the reason to think of it like that
is because that's how caching makes sense, how requests make sense,
etc. etc.
^^^^^^^
Pardon?

Just do what it says, perform a test using XMLHTTPRequest receiving a
properly formatted HTTP status 100 response, and see the state
changes.

Jim.
 
R

Randy Webb

Thomas 'PointedEars' Lahn said the following on 3/21/2006 9:54 AM:
Jim Ley wrote:


My tests combined with what MSDN Library has to say about this, indicate
that readyState == 1 is a strong indicator for a queued request.

And MSDN is the one that says that the HTTPRequest Object is a native
object in IE7 so just because MSDN says something doesn't make it true -
far from it.

Testing may or may not prove it but "MSDN Says it" doesn't mean a whole lot.
 
M

Matt Kruse

Jim said:
No, these aren't accurate, you can tell simply by putting a sleep in a
server script, you'll see 2 fires long before the full data is
available.

You are correct, I actually had a faulty test case.

Here is my current server-side script being called:
#!/usr/local/bin/perl
$|=1;
sleep(5);
print "Content-type: text/html\n\n";
sleep(5);
print <<"END";
<html>
<head><title>test</title></head>
<body>
test
END
sleep(5);
print <<"END";
<br>
test2
</body>
</html>
END

As you can see, it sleeps before the full headers are returned, then again
after the headers are done, then again when half the content is returned.

In my test, readystate 1 fires immediately. Readystate 2 and 3 seem to fire
at the same time, after the 2nd sleep, meaning some content has been
delivered (not just the headers, which are complete after the first sleep).
Then readystate 4 fires when the whole document is loaded.

I can't seem to create a test case where there is a delay between 2 and 3
firing. Can you create one?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,821
Latest member
AleidaSchi

Latest Threads

Top