Accessibility

Flash Communication Server Article

The Trouble with Proxy Servers

Another way to make your organization's network more secure is to use a proxy server as an intermediary between computers inside your network and the Internet. Web proxy servers are often used as caching servers to reduce network utilization. However, proxy servers can often do more than that.

Combined with a network-layer firewall, a proxy server can protect a workstation from having to directly connect to anything outside an organization's network while still allowing access to the web. Instead of requesting a web page directly from a remote server, the browser must request it from the proxy server. The proxy server will look up the page in its cache and return the cached version of the page to the browser. If the page is not in cache, the proxy server will request it from the remote server and return it to the browser. With the proxy server acting as an intermediary, the firewall is often configured to block all direct requests from computers inside the firewall to remote machines—even to port 80. Only the proxy server can connect to the outside world through port 80. See Figure 8.

Before HTTP tunneling, users behind proxy servers who were not allowed to directly connect to the Internet could not connect to a communication server. Now, with tunneling, they often can. From the proxy server's point of view, an attempt to connect using RTMPT will look like a normal HTTP request. The response from the communication server will look like an HTTP response, so the proxy server should both forward the RTMPT request and return the communication server's response. However, HTTP tunneling does not guarantee success. Proxy servers can do more than act as intermediaries that cache web pages. They are an easy way to control access to external resources outside the network. For example, a proxy administrator can create a list of sites that are forbidden, effectively denying access to everyone behind the proxy server to those sites. Some proxy servers are able to examine and filter data in more detail than a simple web proxy. For example, you can configure some to only accept certain content or MIME types such as text/html. When a web server returns a web page to a browser, the HTTP header it returns includes a content type. Here's an example header from a web server returning a web page:

HTTP/1.1 200 OK
Server: Netscape-Enterprise/6.0
Date: Sat, 24 May 2003 01:09:43 GMT
Content-type: text/html
Etag: "c96066c3-1-0-1e8"
Last-modified: Tue, 25 Jun 1996 19:11:18 GMT
Content-length: 488
Accept-ranges: bytes

And, here is the header for an image being returned by a web server:

HTTP/1.1 200 OK
Server: Netscape-Enterprise/6.0
Date: Sat, 24 May 2003 01:51:17 GMT
Content-type: image/gif
Etag: "782311ca-126-0-f1ae"
Last-modified: Mon, 06 May 2002 21:10:38 GMT
Content-length: 61870
Accept-ranges: bytes

The data returned by Macromedia Flash Communication Server is not text, and the headers it uses do not include a Content-type statement. (If no Content-type is provided, it assumes text/html.) So, there are no guarantees that even RTMPT traffic will get through every proxy server. This is no surprise as proxy servers and application-layer firewalls are designed to filter content based on a wide variety of rules that the system administrator sets up. An IT security group that is determined to only allow the entry of valid HTML text and some image file formats (for example image/GIF) can usually deploy tools that are sophisticated enough to succeed. In cases where even RTMPT connections can't get through a proxy server, you may have to ask your client to contact the administrator of the organization's firewall and proxy server to see if he or she can make an exception.

Figure 8. A proxy server and firewall working together

Figure 8. A proxy server and firewall working together

Note: The workstation cannot connect directly to the Internet and must instead request a resource through a proxy server. In turn, the proxy server fetches the resource from the Internet and passes it back to the workstation. The workstation never actually connects to a system outside the firewall.

Trying More than One Port at Once

Macromedia released updated versions of the Macromedia Flash Communication Server components with version 1.5 of the communication server. One notable update was some new code within the Simple Connect component. Macromedia added an extra feature to speed up connections to servers that cannot be reached at the default RTMP port 1935. If the Application Directory parameter for the SimpleConnect component specifies "rtmp" as the protocol and does not supply a port number, the Simple Connect component will do the following:

  1. Create a NetConnection object and use it to attempt to connect to the address in the normal way beginning with port 1935.
  2. Create a second NetConnection object, wait 250 milliseconds, and attempt to connect to the server using RTMPT at port 80.
  3. Accept whatever connection succeeds first and close and delete the other NetConnection object.

Strictly speaking, this should not be necessary. Eventually, the default behavior of Macromedia Flash Player will be to try ports 1935, 443, and 80 with RTMP and then to try port 80 with RTMPT. However, all these attempts take time. Attempting to connect with RTMPT to port 80 after 250 milliseconds will speed up the connection process dramatically if the first RTMP connection attempt fails. Have a look at the actualConnect() method of the FCSimpleConnectClass to see how Macromedia built this component. Of course not everyone uses the Simple Connect component, so the example below is a slightly modified version of the Macromedia code that does pretty much the same thing. I rewrote it to be placed on the main timeline, but you can adapt it to a more object-oriented approach.

// The onConnect function is called when a connection is made.
function onConnect(nc){
   _global.main_nc = nc; // Assign the successful nc to a global variable.
   // For test purposes trace out the uri to see which protocol we are using
   trace("onConnect> " + nc.uri);
   // Create a new onStatus handler for the successful NetConnection object:
   main_nc.onStatus = function(info){
     // your own onStatus handler code goes here
     // to handle errors and other events.
     // For testing this just prints out the contents of the information object.
     trace("----main_nc.onStatus----");
     for (var p in info){
        trace(p + ": " + info[p])
     }
   }
   // Now connect other components and/or initialize your program.
}


// The onConnectFailed function is called if a connection cannot be made.
function onConnectFailed(info){
   // Examine the info object and 
   // report why you can't connect.
   // This code just traces out the information object.
   // Replace it with your own error handling.
   trace("----onConnectFailed----");
   // Loop through all the properties of the information object.
   for (var p in info){
      trace(p + ": " + info[p]);
      // If the application rejects the connection and passes back
      // and application object loop through all its properties too.
      if (p == "application"){
         var appObj = info.application;
         for (var q in appObj){
            trace("   " + q + ": " + appObj[q]);
         }
      }
   }
}

// Create a new NetConnection object that will be used to 
// attempt an RTMP connection.
rtmp_nc = new NetConnection();
// Create an onStatus handler that will dispose of the rtmpt_nc
// NetConnection object if this connection succeeds first.
rtmp_nc.onStatus = function(info) {
  this.pending = false;  
  if (info.code == "NetConnection.Connect.Success") {
    if (rtmpt_nc.pending) {
      rtmpt_nc.onStatus = null;
      rtmpt_nc.close();
      rtmpt_nc = null;
      clearInterval(connectionID);
    }
    onConnect(this);
  } else
    if (! rtmpt_nc.pending){ 
      onConnectFailed(info);
    }
}

// Create a new NetConnection object that will be used to 
// attempt an RTMPT connection.
rtmpt_nc = new NetConnection();
// Create an onStatus handler that will dispose of the rtmp_nc
// NetConnection object if this connection succeeds.
rtmpt_nc.onStatus = function(info) {
  this.pending = false;
  if (info.code == "NetConnection.Connect.Success") {
    if (rtmp_nc.pending) {
      rtmp_nc.onStatus = null;
      rtmp_nc.close();
      rtmp_nc = null;
    }
    onConnect(this);
  } else
    if (! rtmp_nc.pending){ 
      onConnectFailed(info);
    }
}

// Mark both nc objects as pending.
rtmp_nc.pending = true;
rtmpt_nc.pending = true;

// Try to connect with rtmp right away:
rtmp_nc.connect("rtmp://host.domain.com/myApp/myInstance", userName, password);

// Setup an interval to try rtmpt in 400 milliseconds:
connectionID = setInterval(connectRTMPT, 400);

// Clear the interval and try to connect with RTMPT when this function is called.
function connectRTMPT(){
  clearInterval(connectionID);
  rtmpt_nc.connect("rtmpt://host.domain.com/myApp/myInstance", userName, password);
}
You can modify this code to try other ports. For example, if you can't use port 80 and want to try port 8080, use this code:
function connectRTMPT(){
  clearInterval(connectionID);
  rtmpt_nc.connect("rtmpt://myHost.myDomain.com:8080/myApp/myInstance", userName, password);
}

 

Submit feedback on our tutorials, articles, and sample applications.