UCWA - Messing with SignalR and NodeJS

I have been thinking about other transport mechanisms (other than iframe) that would be interesting to see working with UCWA and two immediately came to mind: SignalR and NodeJS. Each can be used to work around the issue of cross-domain requests and provide additional pathways to access UCWA in the event that iframe communication is not feasible.

SignalR

I choose to go the self-hosted route and found great use out of Tutorial: SignalR Self-Host and ASP.NET SignalR Hubs API Guide - JavaScript Client (C#). I felt that by self-hosting it would allow me to run it via a Console application (short-term) and delay the decisions about where it would make the most sense to have it hosted.

I was able to reuse a subset of the helper libraries I made in my previous .NET efforts, specifically Transport and some helper functions. The only modifications that seemed necessary were changes to the Response object as this would be directly used by the other sample libraries. I also wanted to avoid making modifications to the sample libraries beyond choosing between using iframe or SignalR.

The samples libraries' Transport.js needed modifications to support using SignalR over iframe. Modifications were made to allow Transport to take a hub Url (location of the hub proxy) upon construction. Presence of a hub Url is used to determine if Transport should create/connect to the hub proxy (injectFrame(...)) and how to send the request (clientRequest(...)). Similar to how event handlers for onmessage/message were attached/removed a function for handling the response callback was added to attach/remove handler per clientRequest(...) call.

The SignalR hub consists of one method, Request(...), that takes a request object (generated by Transport.js) and execute the request using the .NET Transport library notifying the caller by a response callback. The response object relatively close to the object return by the sample libraries. Running with the UCWA samples was as simple as starting the console application hosting the SignalR hub and loading up the modified samples code (inspecting the JavaScript console to see if the hub connected correctly).

One issue I did run into was that requesting images became a bit of difficulty as the POST on applications returns an HttpOnly cookie that is rather impossible to set from JavaScript. With much deliberation I was able to reason out that image requests could go through clientRequest(...) (the request uses the Authorization header in place of the cookie) and take the raw (I call it base64 below, but it is really just a C# byte[]) response data and stick that into a data Uri for the src property of the image (data:image/png;base64,base64_encoded_string).

One downside of using this SignalR proxy (at least for WebSockets transport) is that network traffic reachable via Fiddler/Network tab becomes nothing more than the initial negotiate/connect calls to the hub proxy. I have not played around to check out other transport types it might use to see what may/may not show up in Fiddler/Network tab.

NodeJS

NodeJS took a bit of time to wrap my head around what exactly I was intending to accomplish. The end desire boiled down to issuing a request containing data similar to what Transport.js would be sending along via postMessage. I created an Http server listening on port 8889 that would take Http request data, filter it, and issue an Https request to UCWA. When the response comes back for the Https request, write out the status code, headers, body, and respond as if it was the intended Http request. Initially it worked very well for GET requests as there wasn't any complicated body data. For POST (and PUT) requests recalculate the content-length headers based on the inner data (data actually being sent in the request and not the data containing url, type, etc).

Debugging NodeJS was actually a bit interesting from Fiddler/Network tab point of view as the request originates from http://localhost:8889 and the end result is determined by the Url provided in the request body. The request headers are relatively close to the end result with a bit of fixing depending on the request type.

Samples containing GET/POST requests: NodeJS.saz

The many faces of Transport

Currently Transport in the sample libraries makes exclusive use of a cross-domain iframe for communication and it works for most situations. If new transport mechanism were to be added, I could see them being added as part of the Lync Server and started as services (of some sort). Perhaps information would be offered similar to how the iframe is currently offered during AutoDiscovery and based on the option chosen by user/code it could load use the appropriate transport. It would be interesting to take this idea further and see how many supported browsers UCWA could reach by utilizing more transport mechanisms like Socket.IO, etc.