Действующие лица

web.sta – web-приложение, целевой браузер Internet Explorer версии 9 и 11
TextSystem – standalone приложение, написанное на Java/Swing
IntermediateLayer – Client-Server приложение, которое представляет собой связующее звено между web.sta и TextSystem.

web.sta может вызвать TextSystem через IntermediateLayer. Для этого IntermediateLayer создаёт http server и web-приложение web.sta отправляет GET или POST запросы на localhost. Там IntermediateLayer обрабатывает параметры запроса и стартует TextSystem. Обратной связи не требуется, поэтому схема взаимодействия проста и достаточно надёжна.

Citrix

В окружении Citrix мы не можем создать несколько слушающих сокетов на одном IP адресе и порте. Тут или надо менять порт, или же менять IP адрес. Но Citrix предоставляет специальный механизм для обхода этого ограничения, без изменения алгоритма работы программы. Этот механизм называется «Virtual IP Loopback». Администратору достаточно указать необходимые приложения в панели конфигурирования Citrix и приложение, которое использует localhost для сокетных соединений, будет получать не 127.0.0.1, а IP адрес вида 127.0.0.<SID+1>, где SID это идентификатор сессии пользователя Windows.

Проблема

Всё это прекрасно работало под IE9 (да и с другими браузерами тоже) на WindowsServer2008 R2. А потом клиентам захотелось чего-то нового и появился WindowsServer2012 R2 c IE11. И вся система перестала работать. Независимо от настроек Citrix IE11 всегда, при указании localhost, пытается установить соединение на 127.0.0.1, а там никто не слушает. После небольшого исследования мы пришли к выводу, что это баг именно в IE11.

RoutingService

Если виртуализация для localhost не работает из коробки Citrix для IE11, то давайте напишем её сами! Для этих целей мы решили написать windows service, который будет простейшим web сервером, слушать на 127.0.0.1 и перенаправлять запросы на нужные инстансы IntermediateLayer, основываясь на номере сессии пользователя. Простого решения получить SID мы не нашли, но в переменных окружения мы сразу обнаружили SESSIONNAME. В IE через ActiveX мы получаем переменную окружения, передаем её в качестве параметра в http запрос, в RoutingService по имени сессии мы через wtsapi32.lib получаем номер сессии. А затем перенаправляем http запрос и соответственно возвращаем ответ.

Что-то пошло не так

Начали тестировать и внедрять наш сервис. Но не всё оказалось так радужно, как хотелось бы. Как оказалось имя сессии может меняться, правда мы так и не поняли в каких условиях это происходит, а разбираться ещё и с этим, как всегда не хватало времени. Но часто случалось, что имя сессии изменилось, а IE11 знает только первоначальное значение переменной окружения. И упорно передаёт это значение на RoutingService.

А что там в реестре?

Надо найти другой способ получать sessionname. Поискали информацию о сессиях в реестре и вот что нашли: в HKEY_CURRENT_USER\Volatile Environment можно получить список сессий текущего пользователя.

Если сессия пользователя одна – то вообще всё прекрасно, прочитали и используем. А если сессий одного пользователя много, то надо как-то определить, в какой же мы сессии находимся. Ничего лучше, чем сопоставить путь к папке временных файлов, мы не придумали.

Вот пример:

В IE получаем текущий путь к TEMP, используя ActiveX Scripting.FileSystemObject. Таким образом нам удалось получить имя нашей сессии. Но это не всё. Значения ключей под Volatile Environment – это, собственно, SID и есть. То есть мы можем сразу в JavaScript получить необходимый IP адрес и оправить запрос на него.

Будем упрощать? 

В итоге мы можем получить SID и устанавливать соединение напрямую, без использования RoutingService. Но решение всё равно не выглядит красивым. Изучение интернета показало, что проблема есть, но решение этой проблемы нигде не описывается. А сам Microsoft молчит.

Так что, возможно, кому-то наш опыт будет полезен в решении этой специфичной проблемы.