As the title says, how do I get around a browser's 6 connections per domain limit?
I have a web app that needs to download data from the server as quickly as possible. Currently, I have up to about a dozen connections being opened at once, but in the network tab I see that several of the connections are stalled (Chrome) or blocked (Firefox) shown in gray:
After some digging around I believe this is due to Chrome's 6 connections per domain limit. How do I get around this?
After some searching, I have some reason to believe that one of these options may work, but I would like to know which option is the best (not a hack):
Use several subdomains (a.mysite.com, b.mysite.com etc...) and point them to the main server so that Chrome believes that they are different sites. This sounds like the most "hacky" option in my opinion and I don't know how long this will actually work for.
Some answers suggest that HTTP2 isn't restricted by the 6 connection limit, but when I look into using HTTP2 it seems like if the browser supports it then it will use it. So I guess this doesn't actually work since I'm still getting the stalled message in Chrome's most recent version.
I'm currently using fetch to get a stream of data from the server, would using Web Sockets or WebRTC instead not be limited by the 6 connection limit?
What other options are there?
I don't think webRTC is limited to 6 connections per domain, since it is often used for P2P mesh connections where that restriction would make no sense.
But I'd be surprised if you got better performance out of 20 datachannels than one HTTP2 connection since the webRTC datachannel is really not optimized for throughput.
You might also want to look at using Service Workers to work around the problem in a different way.
Related
The RTCDataChannel API does not provide any kind of flow/control or back-pressure, does this mean, that a sender could, theoretically, crash the browser of the receiver ? In my opinion the browser, (Chrome, Firefox, etc. all use SCTP under the hood), reads from the SCTP connection and schedules to run the js-callback consuming the packet. If the event queue cannot not keep up with the sender, the browser basically reads continuously packets while storing the packets in a buffer, which grows indefinitely. So when you connect two browsers, the sender can actually always overwhelm the other one, because there is no barrier like TCP receive windows or something similar.
This applies to the websocket api as well.
Do I just miss something or are these API just broken ? If I'm right, this would be a severe security issue when talking to unauthenticated browsers (in a torrent scenario for instance).
The webrtc data channel used to be based on UDP. During that time there was artificial throttling imposed by the browser in order to prevent network flooding. This was the case until chrome v32, I believe.
Nowadays the data channel is based on SCTP which has build-in flow control (FC) and there is no browser throttling any more (thank God). The parameters that control FC are not exposed through the API but that doesn't mean there is no FC.
I am not familiar with the implementation of webrtc in Chrome/FF but I don't think you can crash the browser with a simple flood attack. The "producer is faster than the consumer" is a pretty old problem.
That said, I have been working with the data channel, for more than an year now and have seen my browser crash almost on a daily basis, so there are probably many bugs in the webrtc implementation. Hopefully they won't pose any threat to security.
Sending big chunks of data useing webrtc data channel is not a particularly pleasant experience. The API doesn't offer a "channel is ready for write" callback or anything of the sort, so, yes!, you have to poll the bufferedamount value and try to keep it inside an optimal window. To add insult to injury bufferedamount used to be broken under Windows versions of Chrome, it was always 0. But I think they fixed this in chrome v37 or around that time.
IMHO the webrtc API is not very well thought through but it does the job and honestly I cannot think of any js API that is well thought through.
In the web world a web browser makes a new request for every static file it has to retrieve, so; a stylesheet, javascript file, inline image - all initiate a new server request. Whilst my knowledge of the web is pretty good, the underlying technologies like websockets are somewhat new to me in how they work and what they are capable of.
My question is rather theoretical, but I am wondering if it's possible now or would ever be possible to serve static files via a websocket? Considering websockets are a persistent connection from the client (web browser) to the server, it makes sense that websockets could be used for serving some if not all static content as it would just be one connection as opposed to many.
To clarify a little bit.
I realise my wording about connections was incorrect as pointed out by Greg below. But from what I understand the reason CDN's were created and are still used today is to address the issue with browsers and or servers having a hard limit on the number of concurrent downloads, once you hit that limit your requests are then queued thus adding to the page load time. I am aware they were also created to provide cookie-less requests as well. So really my question should be: "Can websockets be used in place of a CDN?"
BrowserScope has some useful metrics, it appears as though the request limit is about 6 per hostname for most modern browsers and even IE8. But as I said sometimes people have more than 6 resources, does this mean they're being queued and slowing the page load time where websockets could potentially reduce this to one?
It's definitely possible but there are a few reasons why you probably don't want to use this for static resources:
You need at least one resource that is statically delivered over the standard HTTP mechanism which means you need something capable of serving static resources anyways. Generally you want to keep Javascript separate from your HTML which would mean another static load. Or you can be messy and put the WebSocket code embedded on the main page, but you still are really any better off yet.
You can't open WebSocket connections until a script on the page starts running. Establishing the WebSocket connection adds some initial latency.
Most browsers will load non-conflicting static resources in parallel (some older browsers have a severe limit on the number of parallel connections, but they still have some parallelization). You could open multiple WebSocket connections for different static resources, but doing this reliably and efficiently is going to take a lot of effort. Browsers have already solved most of these issues for static resources.
Each WebSocket connection is a guaranteed order message based transport. Combined with the serialized nature of Javascript execution this effectively means you get to process one WebSocket message at a time. You could use Web Workers to be able to process more than one WebSocket connection in parallel, but the main render script will still be serialized across those connections. You could certainly make this efficient, but once again, this isn't a trivial problem and browsers have already solved a lot of these static resource loading problems.
Many web servers support gziping resources before delivering them. WebSocket does not yet have compression support (it's being discussed as an extension in the working group). This means if you want to compress your resources over WebSocket you will have to do this in Javascript which will add more latency.
If you have parts of your page that are dynamically updated using static resources (e.g. loading in new images into a HTML5 canvas game), then WebSockets may be your best option because an already established WebSocket connection will have low latency and overhead for getting pushed updates from the server then getting these delivered over HTTP. But I wouldn't recommend using WebSockets for the initial static resources when you page first loads.
This answer does not really address your web sockets question, but it may make it obsolete:
The next generation technology that is supposed to solve the problem of transferring several assets over a single connection is SPDY, which is was a candidate for HTTP 2.0. It has working implementations in Chrome and Firefox and already some experimental server-side support by the likes of Google and Twitter.
Edit: SPDY protocol is now deprecated. You can however look into it for research purposes.
I understand that websocket is still being worked on. Now, I don't know if what I'm considering is even technically possible but I'm just bouncing off ideas.
What I'm thinking of is a client less SSL VPN using websockets. Is it possible to create a websocket & redirect all the traffic from the browser (on that particular site/domain) through this socket. So lets us say you go to a site http://example.com & this site will set up a websocket back to it's server. Now can we in any way capture all the traffic going from that browser tab & push it through that websocket tunnel (wss://). This way you can have a client less SSL VPN solution.
Now, the biggest problem I can see is how do you actually grab all the traffic going from that browser tab or window. I don't think javascript has or will have enough privileges or even capabilities to do that. Any thoughts?
You could present your own browser UI (URL bar + rendering area), push out HTTP requests over your tunnel and parse & present the returned HTML in the rendering area. But you are correct, you aren't going to be able to capture all browser traffic in javascript without somehow escalating privileges (for example, as a Firefox extension).
A web proxy is really what you are describing: http://en.wikipedia.org/wiki/Proxy_server
All browsers have support for HTTP proxy server settings. If the proxy encapsulated the data with SSL and sent it on to another proxy within the firewall (I assume that's why you mention VPN) then I think you have what you are asking. I don't think WebSockets really has any relevance here. You could use it, but it would just be harder.
I would like to know how Gmail (or anyone else) does comet on Opera.
Here is what I know so far from my experiments.
It doesn't use the event-source tag which is broken in Opera 10.51.
It doesn't use iframe which displays a spinning throbber and a busy mouse cursor.
It doesn't use responseText on xmlhttprequest when readyState = 3 which is known to be broken on Opera.
I tried seeing how it was done in mibbit and etherpad, and I found that they both use long-polling.
Bounty
The bounty goes to whoever can tell me a method better than "event-source" for Opera comet streaming, or how gmail does streaming (or long-polling if it does that).
GMail uses BrowserChannel (Docs | Source), which is included in Google's Closure Library.
#fileoverview Definition of the BrowserChannel class. A BrowserChannel
simulates a bidirectional socket over HTTP. It is the basis of the
Gmail Chat IM connections to the server.
I really don't have any idea on what the answer is. But I know Opera supports server-events : http://my.opera.com/WebApplications/blog/show.dml/438711 . Maybe it's a step towards the anwser?
I'm not really sure either, but I think they use it within Opera Unite.
I think that rather cross-browser (including Opera) approach might be to stream data through an Adobe Flash application. Though it would introduce dependence on the Flash plugin and is not very popular because of that.
I am the author of an in progess C++ HTTP server that is compatible with goog.netBrowserChannel. You can find the docs I've written while studying the protocol here:
http://code.google.com/p/libevent-browserchannel-server/wiki/BrowserChannelProtocol
Long story short, BrowserChannel uses forever frames on IE and XHR streaming on all other browsers. The protocol is divided into several phases, the first of which is network testing:
1) test the network to ensure response "streaming" is supported (in other words no buffering proxy exists)
2) check access to a variety of network prefixes (to make sure the network admin has not blocked access to chat)
Then the actual data transmission can start. Data is divided into two channels (forward and back). The back channel is a series of long lived (about 4 mins each) requests used for the server to "stream" content to the client. To do so HTTP chunked encoding is used. The client does it's best to make sure that one backchannel is always open. The server will close it about every 4 mins after which the client will open a new backchannel. The forward channel is used to send data from the client to the server. This pushing of data is done as necessary.
Ok, this is downright bizarre. I am building a web application that relies on long held HTTP connection using COMET, and using this to stream data from the server to the application.
Now, the problem is that this does not seem to go well with some anti-virus programs. We are now on beta, and some users are facing problems with the application when the anti-virus is enabled. It's not just one specific anti-virus either.. I found this work around for Avast when I looked online: http://avricot.com/blog/index.php?post/2009/05/20/Comet-and-ajax-with-Avast-s-shield-web-:-The-salvation-or-not
However, anyone here has any suggestions on how to handled this? Should I send any specific header to please these security programs?
This is a tough one. The kind of anti-virus feature that causes this tries to prevent malicious code running in the browser from uploading your personal data to a remote server. To do that, the anti-virus tries to buffer all outgoing traffic before it hits the network, and scan it for pre-defined strings.
This works when the application sends a complete HTTP request on the socket, because the anti-virus sees the end of the the HTTP request and knows that it can stop scanning and send the data.
In your case, there's probably just a header without a length field, so until you send enough data to fill the anti-virus's buffer, nothing will be written to the network.
If that's not a good reason to turn that particular feature off, I don't know what is. I ran into this with AVast and McAfee - at this point, the rest of the anti-virus industry is probably doing something like that. Specifically, I ran into this with McAfee's Personal Information Protection feature, which as far as I can tell, is simply too buggy to use.
If you can, just keep sending data on the socket, or send the data in HTTP messages that have a length field. I tried reporting this to a couple of anti-virus vendors - one of them fixed it, the other one didn't, to the best of my knowledge.
Of course, this sort of feature is completely useless. All a malicious application would need to do to get around it is to ROT13 the data before sending it.
Try using https instead of http. There are scanners that intercept https, too, but they're less common and the feature defaulted to off last time I checked. It also broke Firefox SSL connectivity when activated, so I think very few people will activate it and the vendor will hopefully kill the feature.
The problem is that some files can't be scanned in order - later parts are required to determine if the earlier parts are malicious.
So scanners have a problem with channels that are streaming data. I doubt your stream of data is able to be recognised as a clean file type, so the scanner is attempting to scan the data as best it can, and I guess holding up your stream in the process.
The only think I can suggest is to do the data transfer in small transactions, and use the COMET connection for notification only (closing each channel after a single notification).
If you use a non-standard port for your web requests, you may be able to work around this, there are a number of other issues, namely that this will be considered cross-domain by many browsers. Not sure if I have a better suggestion to offer here. It really depends on how the AV program intercepts a given port's traffic.
I think you're going to be forced to break the connection and reconnect. What does your code do if the connection goes down in an outage situation? I had a similar problem with a firewall once. The code had to detect the disconnect, then reconnect. I like the answer about breaking up the data transfer.