@@ -17,6 +17,16 @@ internal static class HostConnectionUtil
1717 // The actual time it takes should be significantly less than this.
1818 private static readonly TimeSpan HostStartupTimeout = TimeSpan . FromMilliseconds ( 1500 ) ;
1919
20+ // These were well-known values in V1 instance files. V2 instance files
21+ // allow these to be overridden.
22+ private static readonly IReadOnlyDictionary < string , string > V1DefaultProperties = new Dictionary < string , string > ( )
23+ {
24+ { BrowserLinkConstants . HostNameKey , "localhost" } ,
25+ { BrowserLinkConstants . FetchScriptVerbKey , "browserLink" } ,
26+ { BrowserLinkConstants . InjectScriptVerbKey , "injectScriptLink" } ,
27+ { BrowserLinkConstants . MappingDataVerbKey , "sendMappingData" }
28+ } ;
29+
2030 /// <summary>
2131 /// Find the host connection for an ASP.NET application.
2232 /// </summary>
@@ -29,9 +39,7 @@ internal static bool FindHostConnection(string applicationPhysicalPath, out Host
2939
3040 foreach ( string instanceFileName in GetAllInstanceFileNames ( ) )
3141 {
32- HostConnectionData connectionCandidate ;
33-
34- if ( ReadConnectionData ( instanceFileName , out connectionCandidate ) )
42+ foreach ( HostConnectionData connectionCandidate in ReadConnectionData ( instanceFileName ) )
3543 {
3644 if ( ConnectionContainsApplication ( connectionCandidate , applicationPhysicalPath ) )
3745 {
@@ -164,31 +172,259 @@ private static IEnumerable<string> GetAllInstanceFileNames()
164172 return fileNames ;
165173 }
166174
167- private static bool ReadConnectionData ( string instanceFileName , out HostConnectionData connection )
175+ private static IEnumerable < HostConnectionData > ReadConnectionData ( string instanceFileName )
168176 {
169- List < string > lines = ReadAllLinesFrom ( instanceFileName ) ;
170-
171- if ( lines . Count > 2 )
177+ string version2FileName = instanceFileName + BrowserLinkConstants . Version2Suffix ;
178+ if ( MappedFileExists ( version2FileName ) )
172179 {
173- string connectionString = lines [ 0 ] ;
174- string sslConnectionString = lines [ 1 ] ;
175- string requestSignalName = instanceFileName + BrowserLinkConstants . RequestSignalSuffix ;
176- string readySignalName = instanceFileName + BrowserLinkConstants . ReadySignalSuffix ;
177- List < string > projects = new List < string > ( ) ;
180+ return ReadV2ConnectionData ( version2FileName ) ;
181+ }
182+ else
183+ {
184+ HostConnectionData connectionData ;
178185
179- for ( int i = 2 ; i < lines . Count ; i ++ )
186+ if ( ReadV1ConnectionData ( instanceFileName , out connectionData ) )
187+ {
188+ return new HostConnectionData [ ] { connectionData } ;
189+ }
190+ else
180191 {
181- projects . Add ( PathUtil . NormalizeDirectoryPath ( lines [ i ] ) ) ;
192+ return new HostConnectionData [ 0 ] ;
182193 }
194+ }
195+ }
196+
197+ private static bool ReadV1ConnectionData ( string instanceFileName , out HostConnectionData connection )
198+ {
199+ List < string > lines = ReadAllLinesFrom ( instanceFileName ) ;
200+
201+ return ParseV1ConnectionData ( instanceFileName , lines , out connection ) ;
202+ }
203+
204+ internal static bool ParseV1ConnectionData ( string instanceFileName , List < string > lines , out HostConnectionData connection )
205+ {
206+ if ( lines . Count > 2 )
207+ {
208+ string connectionString ;
209+ string sslConnectionString ;
210+ string requestSignalName ;
211+ string readySignalName ;
212+ string injectScriptVerb ;
213+ string mappingDataVerb ;
214+ string serverDataVerb ;
215+ IEnumerable < string > projectPaths ;
216+
217+ CreateConnectionStringsAndProjectPaths (
218+ lines ,
219+ out connectionString ,
220+ out sslConnectionString ,
221+ out projectPaths ) ;
222+
223+ CreateSignalNames (
224+ instanceFileName ,
225+ out requestSignalName ,
226+ out readySignalName ) ;
227+
228+ CreateVerbUrls (
229+ V1DefaultProperties ,
230+ connectionString ,
231+ out injectScriptVerb ,
232+ out mappingDataVerb ,
233+ out serverDataVerb ) ;
234+
235+ connection = new HostConnectionData (
236+ connectionString ,
237+ sslConnectionString ,
238+ requestSignalName ,
239+ readySignalName ,
240+ injectScriptVerb ,
241+ mappingDataVerb ,
242+ serverDataVerb ,
243+ projectPaths ) ;
183244
184- connection = new HostConnectionData ( connectionString , sslConnectionString , requestSignalName , readySignalName , projects ) ;
185245 return true ;
186246 }
187247
188248 connection = null ;
189249 return false ;
190250 }
191251
252+ private static void CreateConnectionStringsAndProjectPaths ( List < string > lines , out string connectionString , out string sslConnectionString , out IEnumerable < string > projectPaths )
253+ {
254+ connectionString = lines [ 0 ] ;
255+ sslConnectionString = lines [ 1 ] ;
256+
257+ List < string > projectPathsList = new List < string > ( ) ;
258+
259+ for ( int i = 2 ; i < lines . Count ; i ++ )
260+ {
261+ projectPathsList . Add ( PathUtil . NormalizeDirectoryPath ( lines [ i ] ) ) ;
262+ }
263+
264+ projectPaths = projectPathsList ;
265+ }
266+
267+ private static IEnumerable < HostConnectionData > ReadV2ConnectionData ( string instanceFileName )
268+ {
269+ List < string > instanceFileLines = ReadAllLinesFrom ( instanceFileName ) ;
270+
271+ return ParseV2ConnectionData ( instanceFileName , instanceFileLines ) ;
272+ }
273+
274+ internal static IEnumerable < HostConnectionData > ParseV2ConnectionData ( string instanceFileName , List < string > instanceFileLines )
275+ {
276+ string connectionString ;
277+ string sslConnectionString ;
278+ string requestSignalName ;
279+ string readySignalName ;
280+ string injectScriptVerb ;
281+ string mappingDataVerb ;
282+ string serverDataVerb ;
283+ IEnumerable < string > projectPaths ;
284+
285+ string instanceFileNameBase = instanceFileName . Substring ( 0 , instanceFileName . Length - BrowserLinkConstants . Version2Suffix . Length ) ;
286+ CreateSignalNames (
287+ instanceFileNameBase ,
288+ out requestSignalName ,
289+ out readySignalName ) ;
290+
291+ Dictionary < string , string > properties = new Dictionary < string , string > ( ) ;
292+ Dictionary < string , string > projects = new Dictionary < string , string > ( ) ;
293+
294+ ParseValuesFromLines ( instanceFileLines , properties , projects ) ;
295+
296+ List < HostConnectionData > connections = new List < HostConnectionData > ( ) ;
297+
298+ foreach ( KeyValuePair < string , string > project in projects )
299+ {
300+ CreateConnectionStrings (
301+ properties ,
302+ project . Key ,
303+ out connectionString ,
304+ out sslConnectionString ) ;
305+
306+ CreateVerbUrls (
307+ properties ,
308+ connectionString ,
309+ out injectScriptVerb ,
310+ out mappingDataVerb ,
311+ out serverDataVerb ) ;
312+
313+ projectPaths = new string [ ] { PathUtil . NormalizeDirectoryPath ( project . Value ) } ;
314+
315+ connections . Add ( new HostConnectionData (
316+ connectionString ,
317+ sslConnectionString ,
318+ requestSignalName ,
319+ readySignalName ,
320+ injectScriptVerb ,
321+ mappingDataVerb ,
322+ serverDataVerb ,
323+ projectPaths ) ) ;
324+ }
325+
326+ return connections ;
327+ }
328+
329+ private static void CreateConnectionStrings ( Dictionary < string , string > properties , string projectKey , out string connectionString , out string sslConnectionString )
330+ {
331+ connectionString = String . Empty ;
332+ sslConnectionString = String . Empty ;
333+
334+ string hostName ;
335+ string fetchScriptVerb ;
336+ if ( properties . TryGetValue ( BrowserLinkConstants . HostNameKey , out hostName ) &&
337+ properties . TryGetValue ( BrowserLinkConstants . FetchScriptVerbKey , out fetchScriptVerb ) )
338+ {
339+ string httpPort ;
340+ if ( properties . TryGetValue ( BrowserLinkConstants . HttpPortKey , out httpPort ) )
341+ {
342+ connectionString = String . Format ( "http://{0}:{1}/{2}/{3}" ,
343+ hostName ,
344+ httpPort ,
345+ projectKey ,
346+ fetchScriptVerb ) ;
347+ }
348+
349+ string httpsPort ;
350+ if ( properties . TryGetValue ( BrowserLinkConstants . HttpsPortKey , out httpsPort ) )
351+ {
352+ sslConnectionString = String . Format ( "https://{0}:{1}/{2}/{3}" ,
353+ hostName ,
354+ httpsPort ,
355+ projectKey ,
356+ fetchScriptVerb ) ;
357+ }
358+ }
359+ }
360+
361+ private static void CreateSignalNames ( string instanceFileName , out string requestSignalName , out string readySignalName )
362+ {
363+ requestSignalName = instanceFileName + BrowserLinkConstants . RequestSignalSuffix ;
364+ readySignalName = instanceFileName + BrowserLinkConstants . ReadySignalSuffix ;
365+ }
366+
367+ private static void CreateVerbUrls ( IReadOnlyDictionary < string , string > properties , string httpConnectionString , out string injectScriptVerb , out string mappingDataVerb , out string serverDataVerb )
368+ {
369+ injectScriptVerb = null ;
370+ mappingDataVerb = null ;
371+ serverDataVerb = null ;
372+
373+ if ( httpConnectionString != null )
374+ {
375+ Uri connectionUri ;
376+ if ( Uri . TryCreate ( httpConnectionString , UriKind . Absolute , out connectionUri ) )
377+ {
378+ string verbName ;
379+
380+ if ( properties . TryGetValue ( BrowserLinkConstants . InjectScriptVerbKey , out verbName ) )
381+ {
382+ injectScriptVerb = new Uri ( connectionUri , verbName ) . ToString ( ) ;
383+ }
384+
385+ if ( properties . TryGetValue ( BrowserLinkConstants . MappingDataVerbKey , out verbName ) )
386+ {
387+ mappingDataVerb = new Uri ( connectionUri , verbName ) . ToString ( ) ;
388+ }
389+
390+ if ( properties . TryGetValue ( BrowserLinkConstants . ServerDataVerbKey , out verbName ) )
391+ {
392+ serverDataVerb = new Uri ( connectionUri , verbName ) . ToString ( ) ;
393+ }
394+ }
395+ }
396+ }
397+
398+ private static void ParseValuesFromLines ( List < string > lines , Dictionary < string , string > properties , Dictionary < string , string > projects )
399+ {
400+ foreach ( string line in lines )
401+ {
402+ int colonIndex = line . IndexOf ( ':' ) ;
403+ if ( colonIndex < 0 )
404+ {
405+ continue ;
406+ }
407+
408+ string key = line . Substring ( 0 , colonIndex ) ;
409+ string value = line . Substring ( colonIndex + 1 ) ;
410+
411+ if ( String . Equals ( key , BrowserLinkConstants . ProjectDataKey , StringComparison . Ordinal ) )
412+ {
413+ string [ ] parts = value . Split ( ';' ) ;
414+ if ( parts . Length < 2 )
415+ {
416+ continue ;
417+ }
418+
419+ projects [ parts [ 1 ] ] = parts [ 0 ] ;
420+ }
421+ else
422+ {
423+ properties [ key ] = value ;
424+ }
425+ }
426+ }
427+
192428 private static List < string > ReadAllLinesFrom ( string fileName )
193429 {
194430 MemoryMappedFile file = null ;
0 commit comments