/// <summary>
        /// push image(s) updates(s) (region(s) or fullscreen(s)) from the rdp session to the browser
        /// this is done through a long-polling request (also known as reverse ajax or ajax comet) issued by a zero sized iframe
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Page_Load(
            object sender,
            EventArgs e)
        {
            // if cookies are enabled, the http session id is added to the http request headers; otherwise, it's added to the http request url
            // in both cases, the given http session is automatically bound to the current http context

            RemoteSessionManager remoteSessionManager = null;

            try
            {
                // retrieve the remote session manager for the current http session
                remoteSessionManager = (RemoteSessionManager)HttpContext.Current.Session[HttpSessionStateVariables.RemoteSessionManager.ToString()];
            }
            catch (Exception exc)
            {
                System.Diagnostics.Trace.TraceError("Failed to retrieve the remote session manager for the http session {0}, ({1})", HttpContext.Current.Session.SessionID, exc);
                return;
            }

            try
            {
                // retrieve params
                var longPollingDuration = int.Parse(HttpContext.Current.Request.QueryString["longPollingDuration"]);
                var imgIdx = int.Parse(HttpContext.Current.Request.QueryString["imgIdx"]);

                // if a websocket is set at this step, the client had probably changed the rendering mode (html5 -> html4) or configuration while the remote session is active, then reloaded the page (F5)
                // close the websocket (a new one will be set if the client change back to html5 again...)
                if (remoteSessionManager.WebSocket != null)
                {
                    System.Diagnostics.Trace.TraceInformation("Removing no longer used websocket (the client had probably changed the rendering mode from HTML5 to HTML4 then reloaded the page (F5)), remote session {0}", remoteSessionManager.RemoteSession.Id);
                    remoteSessionManager.WebSocket.Close();
                    remoteSessionManager.WebSocket = null;
                }

                // stream image(s) data within the response for the given duration
                // the connection will be automatically reseted by the client when the request ends
                var startTime     = DateTime.Now;
                var remainingTime = longPollingDuration;
                var currentImgIdx = imgIdx;

                while (remainingTime > 0)
                {
                    // ensure the remote session is still connected
                    if (remoteSessionManager.RemoteSession.State == RemoteSessionState.Disconnected)
                    {
                        // the remote session is disconnected, back to home page
                        HttpContext.Current.Response.Write("<script>parent.location.href = parent.getConfig().getHttpServerUrl();</script>");
                        HttpContext.Current.Response.Flush();
                        break;
                    }
                    // the remote clipboard content was requested
                    else if (remoteSessionManager.ClipboardRequested)
                    {
                        HttpContext.Current.Response.Write(string.Format("<script>parent.showDialogPopup('showDialogPopup', 'ShowDialog.aspx', 'Ctrl+C to copy to local clipboard (Cmd-C on Mac)', '{0}', true);</script>", remoteSessionManager.ClipboardText));
                        HttpContext.Current.Response.Flush();
                        remoteSessionManager.ClipboardRequested = false;
                    }

                    // retrieve the next update, if available; otherwise, wait it for the remaining time
                    var image = remoteSessionManager.GetNextUpdate(currentImgIdx, remainingTime);
                    if (image != null)
                    {
                        System.Diagnostics.Trace.TraceInformation("Pushing image {0} ({1}), remote session {2}", image.Idx, (image.Fullscreen ? "screen" : "region"), remoteSessionManager.RemoteSession.Id);

                        var imgData =
                            image.Idx + "," +
                            image.PosX + "," +
                            image.PosY + "," +
                            image.Width + "," +
                            image.Height + "," +
                            "'" + image.Format.ToString().ToLower() + "'," +
                            image.Quality + "," +
                            "'" + image.Base64Data + "'," +
                            image.Fullscreen.ToString().ToLower();

                        imgData = "<script>parent.pushImage(" + imgData + ");</script>";

                        // write the output
                        HttpContext.Current.Response.Write(imgData);
                        HttpContext.Current.Response.Flush();

                        currentImgIdx = image.Idx;
                    }

                    remainingTime = longPollingDuration - Convert.ToInt32((DateTime.Now - startTime).TotalMilliseconds);
                }
            }
            catch (HttpException)
            {
                // this occurs if the user reloads the page while the long-polling request is going on...
            }
            catch (Exception exc)
            {
                System.Diagnostics.Trace.TraceError("Failed to push display update(s), remote session {0} ({1})", remoteSessionManager.RemoteSession.Id, exc);
            }
        }
Esempio n. 2
0
        /// <summary>
        /// send user input(s) (mouse, keyboard) to the rdp session
        /// if long-polling is disabled (xhr only), also returns image data within the response
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Page_Load(
            object sender,
            EventArgs e)
        {
            // if cookies are enabled, the http session id is added to the http request headers; otherwise, it's added to the http request url
            // in both cases, the given http session is automatically bound to the current http context

            RemoteSessionManager remoteSessionManager = null;

            try
            {
                // retrieve the remote session manager for the current http session
                remoteSessionManager = (RemoteSessionManager)HttpContext.Current.Session[HttpSessionStateVariables.RemoteSessionManager.ToString()];
            }
            catch (Exception exc)
            {
                System.Diagnostics.Trace.TraceError("Failed to retrieve the remote session manager for the http session {0}, ({1})", HttpContext.Current.Session.SessionID, exc);
                return;
            }

            try
            {
                // retrieve params
                var data           = HttpContext.Current.Request.QueryString["data"];
                var fsu            = int.Parse(HttpContext.Current.Request.QueryString["fsu"]) == 1;
                var imgIdx         = int.Parse(HttpContext.Current.Request.QueryString["imgIdx"]);
                var imgEncoding    = HttpContext.Current.Request.QueryString["imgEncoding"];
                var imgQuality     = int.Parse(HttpContext.Current.Request.QueryString["imgQuality"]);
                var imgReturn      = int.Parse(HttpContext.Current.Request.QueryString["imgReturn"]) == 1;
                var bandwidthRatio = int.Parse(HttpContext.Current.Request.QueryString["bandwidthRatio"]);

                // image encoding
                var encoding = ImageEncoding.JPEG;
                Enum.TryParse(imgEncoding, true, out encoding);
                remoteSessionManager.ImageEncoding = encoding;

                // throttle the image quality depending on the bandwidth usage ratio
                if (bandwidthRatio >= (int)ImageQualityTweakBandwidthRatio.HigherBound)
                {
                    remoteSessionManager.ImageQuality = imgQuality / 4;
                }
                else if (bandwidthRatio >= (int)ImageQualityTweakBandwidthRatio.LowerBound && bandwidthRatio < (int)ImageQualityTweakBandwidthRatio.HigherBound)
                {
                    remoteSessionManager.ImageQuality = imgQuality / 2;
                }
                else
                {
                    remoteSessionManager.ImageQuality = imgQuality;
                }

                // if defined, send the user input(s) through the rdp session
                // also, a websocket triggers periodical dummy xhr calls, without data, in order to keep the http session alive; such calls musn't close the websocket!
                if (!string.IsNullOrEmpty(data))
                {
                    remoteSessionManager.SendUserEvent(data);

                    // if a websocket is set at this step, the client had probably changed the rendering mode (html5 -> html4) or configuration while the remote session is active, then reloaded the page (F5)
                    // close the websocket (a new one will be set if the client change back to html5 again...)
                    if (remoteSessionManager.WebSocket != null)
                    {
                        System.Diagnostics.Trace.TraceInformation("Removing no longer used websocket (the client had probably changed the rendering mode from HTML5 to HTML4 then reloaded the page (F5)), remote session {0}", remoteSessionManager.RemoteSession.Id);
                        remoteSessionManager.WebSocket.Close();
                        remoteSessionManager.WebSocket = null;
                    }
                }

                // if requested, ask for a fullscreen update
                if (fsu)
                {
                    System.Diagnostics.Trace.TraceInformation("Requesting fullscreen update, remote session {0}", remoteSessionManager.RemoteSession.Id);
                    remoteSessionManager.SendCommand(RemoteSessionCommand.SendFullscreenUpdate);
                }

                // xhr only
                if (imgReturn)
                {
                    var image = remoteSessionManager.GetNextUpdate(imgIdx);
                    if (image != null)
                    {
                        System.Diagnostics.Trace.TraceInformation("Returning image {0} ({1}), remote session {2}", image.Idx, (image.Fullscreen ? "screen" : "region"), remoteSessionManager.RemoteSession.Id);

                        var imgData =
                            image.Idx + "," +
                            image.PosX + "," +
                            image.PosY + "," +
                            image.Width + "," +
                            image.Height + "," +
                            image.Format.ToString().ToLower() + "," +
                            image.Quality + "," +
                            image.Base64Data + "," +
                            image.Fullscreen.ToString().ToLower();

                        // write the output
                        HttpContext.Current.Response.Write(imgData);
                    }
                    // ensure the remote session is still connected
                    else if (remoteSessionManager.RemoteSession.State == RemoteSessionState.Disconnected)
                    {
                        HttpContext.Current.Response.Write("disconnected");
                    }
                    // the remote clipboard content was requested
                    else if (remoteSessionManager.ClipboardRequested)
                    {
                        HttpContext.Current.Response.Write(string.Format("clipboard|{0}", remoteSessionManager.ClipboardText));
                        remoteSessionManager.ClipboardRequested = false;
                    }
                }
            }
            catch (Exception exc)
            {
                System.Diagnostics.Trace.TraceError("Failed to send user input(s), remote session {0} ({1})", remoteSessionManager.RemoteSession.Id, exc);
            }
        }