Exemple #1
0
        async Task ListenerAbortWhileClientReadingTest(EndpointTestType endpointTestType)
        {
            HybridConnectionListener listener = null;

            try
            {
                listener = GetHybridConnectionListener(endpointTestType);
                var client = GetHybridConnectionClient(endpointTestType);

                TestUtility.Log($"Opening {listener}");
                await listener.OpenAsync(TimeSpan.FromSeconds(30));

                var clientStream = await client.CreateConnectionAsync();

                var listenerStream = await listener.AcceptConnectionAsync();

                TestUtility.Log("Client and Listener HybridStreams are connected!");

                using (var cancelSource = new CancellationTokenSource())
                {
                    TestUtility.Log("Aborting listener WebSocket");
                    cancelSource.Cancel();
                    await listenerStream.CloseAsync(cancelSource.Token);
                }

                byte[] readBuffer = new byte[1024];
                await Assert.ThrowsAsync <RelayException>(() => clientStream.ReadAsync(readBuffer, 0, readBuffer.Length));

                TestUtility.Log("Calling clientStream.Close");
                var clientCloseTask = clientStream.CloseAsync(CancellationToken.None);
            }
            finally
            {
                await this.SafeCloseAsync(listener);
            }
        }
        public ServiceConnectionForwarder(
            string serviceNamespace,
            string ruleName,
            string ruleKey,
            string targetHost,
            string targetHostAlias,
            string allowedPortsString)
        {
            this.targetHost   = targetHost;
            noPortConstraints = false;
            allowedPorts      = new List <int>();

            allowedPortsString = allowedPortsString.Trim();
            if (allowedPortsString == "*")
            {
                noPortConstraints = true;
            }
            else
            {
                noPortConstraints = false;
                string[] portList = allowedPortsString.Split(',');
                for (int i = 0; i < portList.Length; i++)
                {
                    allowedPorts.Add(int.Parse(portList[i].Trim()));
                }
            }

            endpointVia = new UriBuilder("sb", serviceNamespace, -1, targetHostAlias).Uri;

            tokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(ruleName, ruleKey);
            relayListener = new HybridConnectionListener(endpointVia, tokenProvider);

            relayListener.Online     += (s, e) => Trace.TraceInformation("{0} Online", relayListener);
            relayListener.Connecting += (s, e) => Trace.TraceWarning("{0} Re-connecting! {1}: {2}", relayListener, relayListener.LastError.GetType(), relayListener.LastError.Message);
            relayListener.Offline    += (s, e) => Trace.TraceError("{0} Offline! {1}: {2}", relayListener, relayListener.LastError.GetType(), relayListener.LastError.Message);
        }
        static async void RunAcceptPump(HybridConnectionListener listener)
        {
            while (true)
            {
                try
                {
                    HybridConnectionStream stream = await listener.AcceptConnectionAsync();

                    if (stream == null)
                    {
                        return;
                    }

                    string connectionName = $"L:HybridConnectionStream({stream.TrackingContext.TrackingId})";
                    RelayTraceSource.TraceInfo($"{connectionName} accepted");
                    RunConnectionPump(stream, connectionName, echoBytes: true);
                }
                catch (Exception exception)
                {
                    RelayTraceSource.TraceException(exception, nameof(RunAcceptPump));
                    await Task.Delay(TimeSpan.FromMilliseconds(100));
                }
            }
        }
        async Task NonExistantNamespaceTest(EndpointTestType endpointTestType)
        {
            HybridConnectionListener listener = null;

            try
            {
                TestUtility.Log("Setting ConnectionStringBuilder.Endpoint to 'sb://fakeendpoint.com'");

                var fakeEndpointConnectionStringBuilder = new RelayConnectionStringBuilder(this.ConnectionString)
                {
                    Endpoint = new Uri("sb://fakeendpoint.com")
                };

                if (endpointTestType == EndpointTestType.Authenticated)
                {
                    fakeEndpointConnectionStringBuilder.EntityPath = Constants.AuthenticatedEntityPath;
                }
                else
                {
                    fakeEndpointConnectionStringBuilder.EntityPath = Constants.UnauthenticatedEntityPath;
                }

                var fakeEndpointConnectionString = fakeEndpointConnectionStringBuilder.ToString();

                listener = new HybridConnectionListener(fakeEndpointConnectionString);
                var client = new HybridConnectionClient(fakeEndpointConnectionString);

                await Assert.ThrowsAsync <EndpointNotFoundException>(() => listener.OpenAsync());

                await Assert.ThrowsAsync <EndpointNotFoundException>(() => client.CreateConnectionAsync());
            }
            finally
            {
                await this.SafeCloseAsync(listener);
            }
        }
        public RelayEpoxyListener(
            RelayEpoxyTransport parentTransport,
            string listenEndpoint,
            TokenProvider tokenProvider,
            Logger logger,
            Metrics metrics) : base(logger, metrics)
        {
            Debug.Assert(parentTransport != null);
            Debug.Assert(listenEndpoint != null);

            this.parentTransport = parentTransport;

            // will be null if not using TLS
            this.tokenProvider = tokenProvider;

            var endpoint = new Uri(listenEndpoint);

            listener            = new HybridConnectionListener(endpoint, tokenProvider);
            serviceHost         = new ServiceHost(logger);
            connections         = new HashSet <RelayEpoxyConnection>();
            shutdownTokenSource = new CancellationTokenSource();

            ListenEndpoint = endpoint;
        }
        static async Task RunAsync(string[] args)
        {
            var cts = new CancellationTokenSource();

            if (args.Length < 4)
            {
                Console.WriteLine("server [ns] [hc] [keyname] [key]");
                return;
            }


            var ns      = args[0];
            var hc      = args[1];
            var keyname = args[2];
            var key     = args[3];


            // Create a new hybrid connection listener to listen for
            // incoming connections.
            var tokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(keyname, key);
            var listener      = new HybridConnectionListener(new Uri(String.Format("sb://{0}/{1}", ns, hc)), tokenProvider);

            // Subscribe to the status events
            listener.Connecting += (o, e) => { Console.WriteLine("Connecting"); };
            listener.Offline    += (o, e) => { Console.WriteLine("Offline"); };
            listener.Online     += (o, e) => { Console.WriteLine("Online"); };

            // Opening the listener will establish the control channel to
            // the Azure Relay service. The control channel will be continuously
            // maintained and reestablished when connectivity is disrupted.
            await listener.OpenAsync(cts.Token);

            Console.WriteLine("Server listening");

            // trigger cancellation when the user presses enter. Not awaited.
#pragma warning disable CS4014
            cts.Token.Register(() => listener.CloseAsync(CancellationToken.None));
            Task.Run(() => Console.In.ReadLineAsync().ContinueWith((s) => { cts.Cancel(); }));
#pragma warning restore CS4014

            do
            {
                // Accept the next available, pending connection request.
                // Shutting down the listener will allow a clean exit with
                // this method returning null
                var relayConnection = await listener.AcceptConnectionAsync();

                if (relayConnection == null)
                {
                    break;
                }

                // The following task processes a new session. We turn off the
                // warning here since we intentially don't 'await'
                // this call, but rather let the task handdling the connection
                // run out on its own without holding for it

#pragma warning disable CS4014
                Task.Run(async() =>
                {
                    Console.WriteLine("New session");
                    // The connection is a fully bidrectional stream.
                    // We put a stream reader and a stream writer over it
                    // that allows us to read UTF-8 text data that comes from
                    // the sender and to write text replies back.
                    var reader = new StreamReader(relayConnection);
                    var writer = new StreamWriter(relayConnection)
                    {
                        AutoFlush = true
                    };
                    do
                    {
                        // Read a line of input until a newline is encountered
                        string line = await reader.ReadLineAsync();
                        if (String.IsNullOrEmpty(line))
                        {
                            // If there's no input data, we will signal that
                            // we will no longer send data on this connection
                            // and then break out of the processing loop.
                            await relayConnection.ShutdownAsync(cts.Token);
                            break;
                        }
                        // Output the line on the console
                        Console.WriteLine(line);
                        // Write the line back to the client, prepending "Echo:"
                        await writer.WriteLineAsync("Echo: " + line);
                    }while (!cts.IsCancellationRequested);
                    Console.WriteLine("End session");
                    // closing the connection from this end
                    await relayConnection.CloseAsync(cts.Token);
                });
#pragma warning restore CS4014
            }while (true);

            // close the listener after we exit the processing loop
            await listener.CloseAsync(cts.Token);
        }
        private ServiceForwarder(ILogger logger, MetricsRegistry registry, int forwarderIdx, HybridConnectionListener listener, RelayMetadata metadata, string entityPath)
        {
            _log = logger.ForContext(GetType());

            _forwarderIdx  = forwarderIdx;
            _relayListener = listener;
            _metadata      = metadata;

            var tags = new MetricTags(nameof(entityPath), entityPath);

            var metrics = new TunnelMetrics(registry, tags);

            _tunnelFactory = new RelayTunnelFactory(logger, metrics);
        }
        public async Task StartAsync(CancellationToken cancellationToken)
        {
            configuration.InstrumentationKey = "ed24685e-d783-4306-bdff-be8887d21cd7";
            configuration.TelemetryInitializers.Add(new HttpDependenciesParsingTelemetryInitializer());

            var telemetryClient = new TelemetryClient(configuration);

            telemetryClient.TrackTrace("Hello World!");
            logger.LogInformation("HERE");

            var module = new DependencyTrackingTelemetryModule();

            // prevent Correlation Id to be sent to certain endpoints. You may add other domains as needed.
            module.ExcludeComponentCorrelationHttpHeadersOnDomains.Add("core.windows.net");
            //...

            // enable known dependency tracking, note that in future versions, we will extend this list.
            // please check default settings in https://github.com/Microsoft/ApplicationInsights-dotnet-server/blob/develop/Src/DependencyCollector/DependencyCollector/ApplicationInsights.config.install.xdt

            module.IncludeDiagnosticSourceActivities.Add("Microsoft.Azure.ServiceBus");
            module.IncludeDiagnosticSourceActivities.Add("Microsoft.Azure.EventHubs");
            //....

            // initialize the module
            module.Initialize(configuration);

            var cts = new CancellationTokenSource();

            var tokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(KeyName, Key);

            listener = new HybridConnectionListener(new Uri(string.Format("sb://{0}/{1}", RelayNamespace, ConnectionName)), tokenProvider);

            // Subscribe to the status events.
            listener.Connecting += (o, e) => { logger.LogInformation("Connecting"); };
            listener.Offline    += (o, e) => { logger.LogInformation("Offline"); };
            listener.Online     += (o, e) => { logger.LogInformation("Online"); };

            using (InitializeDependencyTracking(configuration))
            {
                // Provide an HTTP request handler
                listener.RequestHandler = (context) =>
                {
                    telemetryClient.TrackTrace("Hello World!");
                    // Do something with context.Request.Url, HttpMethod, Headers, InputStream...
                    context.Response.StatusCode        = HttpStatusCode.OK;
                    context.Response.StatusDescription = "OK, This is pretty neat";
                    using (var sw = new StreamWriter(context.Response.OutputStream))
                    {
                        sw.WriteLine("hello! I have come from the server");
                    }
                    logger.LogInformation("Server Responded");
                    logger.LogInformation(context.TrackingContext.Address);
                    // The context MUST be closed here
                    context.Response.Close();

                    using (var httpClient = new HttpClient())
                    {
                        // Http dependency is automatically tracked!
                        httpClient.GetAsync("https://google.com").Wait();
                    }


                    // before exit, flush the remaining data
                    telemetryClient.Flush();

                    // flush is not blocking so wait a bit
                    Task.Delay(5000).Wait();
                };
            }

            // Opening the listener establishes the control channel to
            // the Azure Relay service. The control channel is continuously
            // maintained, and is reestablished when connectivity is disrupted.
            await listener.OpenAsync();

            logger.LogInformation("Server listening");
        }
        public static async Task <int> VerifyListenAsync(TraceSource traceSource, RelayConnectionStringBuilder connectionString, string responseBody, int responseChunkLength, HttpStatusCode statusCode, string statusDescription)
        {
            var  namespaceManager        = new RelayNamespaceManager(connectionString.ToString());
            bool createdHybridConnection = await EnsureHybridConnectionExists(traceSource, connectionString, namespaceManager);

            HybridConnectionListener listener = null;

            try
            {
                listener             = new HybridConnectionListener(connectionString.ToString());
                listener.Connecting += (s, e) => RelayTraceSource.TraceException(listener.LastError, TraceEventType.Warning, "HybridConnectionListener Re-Connecting");
                listener.Online     += (s, e) => RelayTraceSource.Instance.TraceEvent(TraceEventType.Information, (int)ConsoleColor.Green, "HybridConnectionListener is online");
                EventHandler offlineHandler = (s, e) => RelayTraceSource.TraceException(listener.LastError, "HybridConnectionListener is OFFLINE");
                listener.Offline += offlineHandler;

                var responseBytes = Encoding.UTF8.GetBytes(responseBody);
                listener.RequestHandler = async(context) =>
                {
                    try
                    {
                        var stopwatch = new Stopwatch();
                        LogHttpRequest(context, traceSource);
                        context.Response.StatusCode = statusCode;
                        if (statusDescription != null)
                        {
                            context.Response.StatusDescription = statusDescription;
                        }

                        context.Response.Headers[HttpResponseHeader.ContentType] = "text/html";
                        int bytesWritten = 0;
                        do
                        {
                            int countToWrite = Math.Min(responseBody.Length - bytesWritten, responseChunkLength);
                            stopwatch.Restart();
                            await context.Response.OutputStream.WriteAsync(responseBytes, bytesWritten, countToWrite);

                            bytesWritten += countToWrite;
                            traceSource.TraceEvent(TraceEventType.Verbose, 0, "Sent {0} bytes in {1} ms", countToWrite, stopwatch.ElapsedMilliseconds);
                        }while (bytesWritten < responseBody.Length);

                        stopwatch.Restart();
                        await context.Response.CloseAsync();

                        traceSource.TraceEvent(TraceEventType.Verbose, 0, "Close completed in {0} ms", stopwatch.ElapsedMilliseconds);
                    }
                    catch (Exception exception)
                    {
                        RelayTraceSource.TraceException(exception, $"RequestHandler Error");
                    }
                };

                traceSource.TraceInformation($"Opening {listener}");
                await listener.OpenAsync();

                RunAcceptPump(listener);
                traceSource.TraceInformation("Press <ENTER> to close the listener ");
                Console.ReadLine();

                traceSource.TraceInformation($"Closing {listener}");
                listener.Offline -= offlineHandler; // Avoid a spurious trace on expected shutdown.
                await listener.CloseAsync();

                traceSource.TraceInformation("Closed");
                return(0);
            }
            catch (Exception)
            {
                listener?.CloseAsync();
                throw;
            }
            finally
            {
                if (createdHybridConnection)
                {
                    try
                    {
                        traceSource.TraceEvent(TraceEventType.Information, (int)ConsoleColor.White, $"Deleting HybridConnection '{connectionString.EntityPath}'");
                        await namespaceManager.DeleteHybridConnectionAsync(connectionString.EntityPath);

                        traceSource.TraceInformation("Deleted");
                    }
                    catch (Exception exception)
                    {
                        RelayTraceSource.TraceException(exception, "Deleting HybridConnection");
                    }
                }
            }
        }
Exemple #10
0
        async Task AcceptHandlerTest(EndpointTestType endpointTestType)
        {
            HybridConnectionListener listener = null;

            try
            {
                listener = GetHybridConnectionListener(endpointTestType);
                TestUtility.Log($"Opening {listener}");
                await listener.OpenAsync(TimeSpan.FromSeconds(30));

                // Install a Custom AcceptHandler which allows using Headers to control the StatusCode, StatusDescription,
                // and whether to accept or reject the client.
                listener.AcceptHandler = TestAcceptHandler;

                var clientConnectionString = GetConnectionString(endpointTestType);

                var connectionStringBuilder = new RelayConnectionStringBuilder(clientConnectionString);

                var wssUri = await GetWebSocketConnectionUri(endpointTestType);

                TestUtility.Log($"Using WebSocket address {wssUri}");
                using (var cancelSource = new CancellationTokenSource(TimeSpan.FromMinutes(1)))
                {
                    TestUtility.Log("Testing HybridConnectionListener.AcceptHandler accepting with only returning true");
                    AcceptEchoListener(listener);
                    var clientWebSocket = new ClientWebSocket();
                    clientWebSocket.Options.SetRequestHeader(TestAcceptHandlerResultHeader, true.ToString());
                    await clientWebSocket.ConnectAsync(wssUri, cancelSource.Token);

                    await clientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Test closing web socket", cancelSource.Token);

                    TestUtility.Log("Testing HybridConnectionListener.AcceptHandler accepting and setting response header");
                    AcceptEchoListener(listener);
                    clientWebSocket = new ClientWebSocket();
                    clientWebSocket.Options.SetRequestHeader(TestAcceptHandlerResultHeader, true.ToString());
                    clientWebSocket.Options.SetRequestHeader(TestAcceptHandlerSetResponseHeader, "X-CustomHeader: Test value");
                    await clientWebSocket.ConnectAsync(wssUri, cancelSource.Token);

                    await clientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Test closing web socket", cancelSource.Token);

                    TestUtility.Log("Testing HybridConnectionListener.AcceptHandler rejecting with only returning false");
                    AcceptEchoListener(listener);
                    HttpStatusCode expectedStatusCode        = HttpStatusCode.BadRequest;
                    string         expectedStatusDescription = "Rejected by user code";
                    clientWebSocket = new ClientWebSocket();
                    clientWebSocket.Options.SetRequestHeader(TestAcceptHandlerResultHeader, false.ToString());
                    var webSocketException = await Assert.ThrowsAsync <WebSocketException>(() => clientWebSocket.ConnectAsync(wssUri, cancelSource.Token));

                    VerifyHttpStatusCodeAndDescription(webSocketException, expectedStatusCode, expectedStatusDescription);

                    TestUtility.Log("Testing HybridConnectionListener.AcceptHandler rejecting with setting status code and returning false");
                    AcceptEchoListener(listener);
                    expectedStatusCode        = HttpStatusCode.Unauthorized;
                    expectedStatusDescription = "Unauthorized";
                    clientWebSocket           = new ClientWebSocket();
                    clientWebSocket.Options.SetRequestHeader(TestAcceptHandlerResultHeader, false.ToString());
                    clientWebSocket.Options.SetRequestHeader(TestAcceptHandlerStatusCodeHeader, ((int)expectedStatusCode).ToString());
                    webSocketException = await Assert.ThrowsAsync <WebSocketException>(() => clientWebSocket.ConnectAsync(wssUri, cancelSource.Token));

                    VerifyHttpStatusCodeAndDescription(webSocketException, expectedStatusCode, expectedStatusDescription);

                    TestUtility.Log("Testing HybridConnectionListener.AcceptHandler rejecting with setting status code+description and returning false");
                    AcceptEchoListener(listener);
                    expectedStatusCode        = HttpStatusCode.Unauthorized;
                    expectedStatusDescription = "Status Description from test";
                    clientWebSocket           = new ClientWebSocket();
                    clientWebSocket.Options.SetRequestHeader(TestAcceptHandlerResultHeader, false.ToString());
                    clientWebSocket.Options.SetRequestHeader(TestAcceptHandlerStatusCodeHeader, ((int)expectedStatusCode).ToString());
                    clientWebSocket.Options.SetRequestHeader(TestAcceptHandlerStatusDescriptionHeader, expectedStatusDescription);
                    webSocketException = await Assert.ThrowsAsync <WebSocketException>(() => clientWebSocket.ConnectAsync(wssUri, cancelSource.Token));

                    VerifyHttpStatusCodeAndDescription(webSocketException, expectedStatusCode, expectedStatusDescription);

                    TestUtility.Log("Testing HybridConnectionListener.AcceptHandler with a custom handler that returns null instead of a valid Task<bool>");
                    listener.AcceptHandler = context => null;
                    AcceptEchoListener(listener);
                    expectedStatusCode        = HttpStatusCode.BadGateway;
                    expectedStatusDescription = "The Listener's custom AcceptHandler threw an exception. See Listener logs for details.";
                    clientWebSocket           = new ClientWebSocket();
                    webSocketException        = await Assert.ThrowsAsync <WebSocketException>(() => clientWebSocket.ConnectAsync(wssUri, cancelSource.Token));

                    VerifyHttpStatusCodeAndDescription(webSocketException, expectedStatusCode, expectedStatusDescription, false);
                }
            }
            finally
            {
                await SafeCloseAsync(listener);
            }
        }
 public ListenerInfo(HybridConnectionListener listener, int index)
 {
     this.Listener = listener;
     this.Index    = index;
 }
        async Task QueryString(EndpointTestType endpointTestType)
        {
            HybridConnectionListener listener = this.GetHybridConnectionListener(endpointTestType);

            try
            {
                RelayConnectionStringBuilder connectionString = GetConnectionStringBuilder(endpointTestType);
                Uri endpointUri = connectionString.Endpoint;

                TestUtility.Log("Calling HybridConnectionListener.Open");
                await listener.OpenAsync(TimeSpan.FromSeconds(30));

                var queryStringTests = new[]
                {
                    new { Original = "?foo=bar", Output = "?foo=bar" },
                    new { Original = "?sb-hc-id=1", Output = "" },
                    new { Original = "?sb-hc-id=1&custom=value", Output = "?custom=value" },
                    new { Original = "?custom=value&sb-hc-id=1", Output = "?custom=value" },
                    new { Original = "?sb-hc-undefined=true", Output = "" },
                    new { Original = "? Key =  Value With Space ", Output = "?+Key+=++Value+With+Space" }, // HttpUtility.ParseQueryString.ToString() in the cloud service changes this
                    new { Original = "?key='value'", Output = "?key=%27value%27" },                        // HttpUtility.ParseQueryString.ToString() in the cloud service changes this
                    new { Original = "?key=\"value\"", Output = "?key=%22value%22" },                      // HttpUtility.ParseQueryString.ToString() in the cloud service changes this
                    new { Original = "?key=<value>", Output = "?key=%3cvalue%3e" },
#if PENDING_SERVICE_UPDATE
                    new { Original = "?foo=bar&", Output = "?foo=bar&" },
                    new { Original = "?&foo=bar", Output = "?foo=bar" }, // HttpUtility.ParseQueryString.ToString() in the cloud service changes this
                    new { Original = "?sb-hc-undefined", Output = "?sb-hc-undefined" },
                    new { Original = "?CustomValue", Output = "?CustomValue" },
                    new { Original = "?custom-Value", Output = "?custom-Value" },
                    new { Original = "?custom&value", Output = "?custom&value" },
                    new { Original = "?&custom&value&", Output = "?&custom&value&" },
                    new { Original = "?&&value&&", Output = "?&&value&&" },
                    new { Original = "?+", Output = "?+" },
                    new { Original = "?%20", Output = "?+" },                                        // HttpUtility.ParseQueryString.ToString() in the cloud service changes this
                    new { Original = "? Not a key value pair ", Output = "?+Not+a+key+value+pair" }, // HttpUtility.ParseQueryString.ToString() in the cloud service changes this
                    new { Original = "?&+&", Output = "?&+&" },
                    new { Original = "?%2f%3a%3d%26", Output = "?%2f%3a%3d%26" },
#endif
                };

                RelayedHttpListenerContext actualRequestContext = null;
                listener.RequestHandler = async(context) =>
                {
                    TestUtility.Log($"RequestHandler {context.Request.HttpMethod} {context.Request.Url}");
                    actualRequestContext = context;
                    await context.Response.CloseAsync();
                };

                foreach (var queryStringTest in queryStringTests)
                {
                    string originalQueryString = queryStringTest.Original;
                    string expectedQueryString = queryStringTest.Output;
                    actualRequestContext = null;

                    TestUtility.Log($"Testing Query String '{originalQueryString}'");
                    Uri hybridHttpUri = new UriBuilder("https://", endpointUri.Host, endpointUri.Port, connectionString.EntityPath, originalQueryString).Uri;
                    using (var client = new HttpClient {
                        BaseAddress = hybridHttpUri
                    })
                    {
                        client.DefaultRequestHeaders.ExpectContinue = false;

                        var getRequest = new HttpRequestMessage();
                        getRequest.Method = HttpMethod.Get;
                        await AddAuthorizationHeader(connectionString, getRequest, hybridHttpUri);

                        LogRequestLine(getRequest, client);
                        using (HttpResponseMessage response = await client.SendAsync(getRequest))
                        {
                            LogResponseLine(response);
                            Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                            Assert.Equal(expectedQueryString, actualRequestContext.Request.Url.Query);
                        }
                    }
                }

                await listener.CloseAsync(TimeSpan.FromSeconds(10));
            }
            finally
            {
                await SafeCloseAsync(listener);
            }
        }
        async Task MultiValueHeader(EndpointTestType endpointTestType)
        {
            HybridConnectionListener listener = this.GetHybridConnectionListener(endpointTestType);

            try
            {
                RelayConnectionStringBuilder connectionString = GetConnectionStringBuilder(endpointTestType);
                Uri endpointUri = connectionString.Endpoint;

                TestUtility.Log("Calling HybridConnectionListener.Open");
                await listener.OpenAsync(TimeSpan.FromSeconds(30));

                const string CustomHeaderName   = "X-CustomHeader";
                string       requestHeaderValue = string.Empty;
                listener.RequestHandler = (context) =>
                {
                    TestUtility.Log("HybridConnectionListener.RequestHandler invoked with Request:");
                    TestUtility.Log($"{context.Request.HttpMethod} {context.Request.Url}");
                    context.Request.Headers.AllKeys.ToList().ForEach((k) => TestUtility.Log($"{k}: {context.Request.Headers[k]}"));
                    TestUtility.Log(StreamToString(context.Request.InputStream));
                    requestHeaderValue = context.Request.Headers[CustomHeaderName];

                    context.Response.Headers.Add(CustomHeaderName, "responseValue1");
                    context.Response.Headers.Add(CustomHeaderName, "responseValue2");
                    context.Response.OutputStream.Close();
                };

                Uri hybridHttpUri = new UriBuilder("https://", endpointUri.Host, endpointUri.Port, connectionString.EntityPath).Uri;
                using (var client = new HttpClient {
                    BaseAddress = hybridHttpUri
                })
                {
                    client.DefaultRequestHeaders.ExpectContinue = false;

                    var getRequest = new HttpRequestMessage();
                    getRequest.Method = HttpMethod.Get;
                    await AddAuthorizationHeader(connectionString, getRequest, hybridHttpUri);

                    getRequest.Headers.Add(CustomHeaderName, "requestValue1");
                    getRequest.Headers.Add(CustomHeaderName, "requestValue2");

                    LogRequest(getRequest, client);
                    using (HttpResponseMessage response = await client.SendAsync(getRequest))
                    {
                        LogResponse(response);
                        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                        Assert.Equal("requestValue1, requestValue2", requestHeaderValue);
                        string[] responseHeaders = string.Join(",", response.Headers.GetValues(CustomHeaderName)).Split(new[] { ',' });
                        for (int i = 0; i < responseHeaders.Length; i++)
                        {
                            responseHeaders[i] = responseHeaders[i].Trim(' ', '\t');
                        }

                        Assert.Equal(new [] { "responseValue1", "responseValue2" }, responseHeaders);
                    }
                }

                await listener.CloseAsync(TimeSpan.FromSeconds(10));
            }
            finally
            {
                await SafeCloseAsync(listener);
            }
        }
        async Task LoadBalancedListeners(EndpointTestType endpointTestType)
        {
            HybridConnectionListener listener1 = null;
            HybridConnectionListener listener2 = null;
            var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));

            try
            {
                listener1 = this.GetHybridConnectionListener(endpointTestType);
                listener2 = this.GetHybridConnectionListener(endpointTestType);
                RelayConnectionStringBuilder connectionString = GetConnectionStringBuilder(endpointTestType);
                Uri endpointUri = connectionString.Endpoint;

                TestUtility.Log("Opening HybridConnectionListeners");
                await Task.WhenAll(
                    listener1.OpenAsync(cts.Token),
                    listener2.OpenAsync(cts.Token));

                const int TotalExpectedRequestCount = 50;
                long      listenerRequestCount1     = 0;
                long      listenerRequestCount2     = 0;

                listener1.RequestHandler = async(context) =>
                {
                    Interlocked.Increment(ref listenerRequestCount1);
                    context.Response.OutputStream.WriteByte(1);
                    await context.Response.CloseAsync();
                };

                listener2.RequestHandler = async(context) =>
                {
                    Interlocked.Increment(ref listenerRequestCount2);
                    context.Response.OutputStream.WriteByte(2);
                    await context.Response.CloseAsync();
                };

                Uri hybridHttpUri = new UriBuilder("https://", endpointUri.Host, endpointUri.Port, connectionString.EntityPath).Uri;
                await Enumerable.Range(0, TotalExpectedRequestCount).ParallelBatchAsync(
                    batchSize: 10,
                    parallelTasksCount: 10,
                    asyncTask: async(indexes) =>
                {
                    string messageIndexes = string.Join(",", indexes);
                    TestUtility.Log($"Messages {messageIndexes} starting");
                    try
                    {
                        foreach (var index in indexes)
                        {
                            var httpRequest = (HttpWebRequest)WebRequest.Create(hybridHttpUri);
                            using (var abortRegistration = cts.Token.Register(() => httpRequest.Abort()))
                            {
                                httpRequest.Method = HttpMethod.Get.Method;
                                await AddAuthorizationHeader(connectionString, httpRequest.Headers, hybridHttpUri);

                                using (var httpResponse = (HttpWebResponse)(await httpRequest.GetResponseAsync()))
                                {
                                    Assert.Equal(HttpStatusCode.OK, httpResponse.StatusCode);
                                }
                            }
                        }
                    }
                    catch (WebException webException)
                    {
                        TestUtility.Log($"Messages {messageIndexes} Error: {webException}");
                        throw;
                    }

                    TestUtility.Log($"Messages {messageIndexes} complete");
                });

                TestUtility.Log($"Listener1 Request Count: {listenerRequestCount1}");
                TestUtility.Log($"Listener2 Request Count: {listenerRequestCount2}");

                Assert.Equal(TotalExpectedRequestCount, listenerRequestCount1 + listenerRequestCount2);
                Assert.True(listenerRequestCount1 > 0, "Listener 1 should have received some of the events.");
                Assert.True(listenerRequestCount2 > 0, "Listener 2 should have received some of the events.");

                await Task.WhenAll(
                    listener1.CloseAsync(cts.Token),
                    listener2.CloseAsync(cts.Token));
            }
            finally
            {
                TestUtility.Log("Shutting down");
                cts.Dispose();
                await Task.WhenAll(
                    SafeCloseAsync(listener1),
                    SafeCloseAsync(listener2));
            }
        }
Exemple #15
0
 public HybridConnectionListenerServerTransport(HybridConnectionListener listener)
 {
     this.listener = listener;
 }
        async Task RequestHeadersTest(EndpointTestType endpointTestType)
        {
            HybridConnectionListener listener = null;

            try
            {
                listener = this.GetHybridConnectionListener(endpointTestType);
                var client = GetHybridConnectionClient(endpointTestType);

                var listenerRequestTcs = new TaskCompletionSource <IDictionary <string, string> >();
                listener.AcceptHandler = (context) =>
                {
                    try
                    {
                        var headers = new Dictionary <string, string>();
                        foreach (string headerName in context.Request.Headers.AllKeys)
                        {
                            headers[headerName] = context.Request.Headers[headerName];
                        }

                        listenerRequestTcs.SetResult(headers);
                        return(Task.FromResult(true));
                    }
                    catch (Exception e)
                    {
                        listenerRequestTcs.TrySetException(e);
                        throw;
                    }
                };

                TestUtility.Log($"Opening {listener}");
                await listener.OpenAsync(TimeSpan.FromSeconds(30));

                const string ExpectedRequestHeaderName  = "CustomHeader1";
                const string ExpectedRequestHeaderValue = "Some value here; other-value/here.";

                var clientRequestHeaders = new Dictionary <string, string>();
                clientRequestHeaders[ExpectedRequestHeaderName] = ExpectedRequestHeaderValue;
                var clientStream = await client.CreateConnectionAsync(clientRequestHeaders);

                var listenerStream = await listener.AcceptConnectionAsync();

                TestUtility.Log("Client and Listener HybridStreams are connected!");

                Assert.True(listenerRequestTcs.Task.Wait(TimeSpan.FromSeconds(5)), "AcceptHandler should have been invoked by now.");
                IDictionary <string, string> listenerRequestHeaders = await listenerRequestTcs.Task;
                Assert.True(listenerRequestHeaders.ContainsKey(ExpectedRequestHeaderName), "Expected header name should be present.");
                Assert.Equal(ExpectedRequestHeaderValue, listenerRequestHeaders[ExpectedRequestHeaderName]);

                byte[] sendBuffer = this.CreateBuffer(1025, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 });
                await clientStream.WriteAsync(sendBuffer, 0, sendBuffer.Length);

                TestUtility.Log($"clientStream wrote {sendBuffer.Length} bytes");

                byte[] readBuffer = new byte[sendBuffer.Length];
                await this.ReadCountBytesAsync(listenerStream, readBuffer, 0, sendBuffer.Length, TimeSpan.FromSeconds(30));

                Assert.Equal(sendBuffer, readBuffer);

                var clientStreamCloseTask = clientStream.CloseAsync(new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token);
                await listenerStream.CloseAsync(new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token);

                await clientStreamCloseTask;

                TestUtility.Log($"Closing {listener}");
                await listener.CloseAsync(TimeSpan.FromSeconds(10));

                listener = null;
            }
            finally
            {
                await this.SafeCloseAsync(listener);
            }
        }
        async Task RequestHandlerErrors(EndpointTestType endpointTestType)
        {
            HybridConnectionListener listener = this.GetHybridConnectionListener(endpointTestType);

            try
            {
                RelayConnectionStringBuilder connectionString = GetConnectionStringBuilder(endpointTestType);
                Uri endpointUri = connectionString.Endpoint;
                await listener.OpenAsync(TimeSpan.FromSeconds(30));

                Uri hybridHttpUri = new UriBuilder("https://", endpointUri.Host, endpointUri.Port, connectionString.EntityPath).Uri;
                using (var client = new HttpClient {
                    BaseAddress = hybridHttpUri
                })
                {
                    client.DefaultRequestHeaders.ExpectContinue = false;

                    var request = new HttpRequestMessage();
                    request.Method = HttpMethod.Get;
                    await AddAuthorizationHeader(connectionString, request, hybridHttpUri);

                    LogRequestLine(request, client);
                    using (HttpResponseMessage response = await client.SendAsync(request))
                    {
                        LogResponse(response);
                        Assert.Equal(HttpStatusCode.NotImplemented, response.StatusCode);
                        Assert.Contains("RequestHandler has not been configured", response.ReasonPhrase);
                        Assert.Contains("TrackingId", response.ReasonPhrase);
                        Assert.Contains(hybridHttpUri.Host, response.ReasonPhrase);
                        Assert.Contains(connectionString.EntityPath, response.ReasonPhrase);
                        string viaHeader = response.Headers.Via.ToString();
                        Assert.Contains(hybridHttpUri.Host, viaHeader);
                    }

                    string userExceptionMessage = "User Error";
                    listener.RequestHandler = (context) =>
                    {
                        throw new InvalidOperationException(userExceptionMessage);
                    };

                    request        = new HttpRequestMessage();
                    request.Method = HttpMethod.Get;
                    await AddAuthorizationHeader(connectionString, request, hybridHttpUri);

                    LogRequestLine(request, client);
                    using (HttpResponseMessage response = await client.SendAsync(request))
                    {
                        LogResponse(response);
                        Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
                        Assert.Contains("RequestHandler", response.ReasonPhrase);
                        Assert.Contains("exception", response.ReasonPhrase, StringComparison.OrdinalIgnoreCase);
                        Assert.Contains("TrackingId", response.ReasonPhrase);
                        Assert.Contains(hybridHttpUri.Host, response.ReasonPhrase);
                        Assert.Contains(connectionString.EntityPath, response.ReasonPhrase);
                        string viaHeader = response.Headers.Via.ToString();
                        Assert.Contains(hybridHttpUri.Host, viaHeader);

                        // Details of the Exception in the Listener must not be sent
                        Assert.DoesNotContain("InvalidOperationException", response.ReasonPhrase);
                        Assert.DoesNotContain(userExceptionMessage, response.ReasonPhrase);
                    }
                }

                await listener.CloseAsync(TimeSpan.FromSeconds(10));
            }
            finally
            {
                await SafeCloseAsync(listener);
            }
        }
Exemple #18
0
        /// <summary>
        /// Start accepting incoming requests.
        /// </summary>
        public void Start()
        {
            CheckDisposed();

            LogHelper.LogInfo(Logger, "Start");

            // Make sure there are no race conditions between Start/Stop/Abort/Close/Dispose.
            // Start needs to setup all resources. Abort/Stop must not interfere while Start is
            // allocating those resources.
            lock (_internalLock)
            {
                try
                {
                    CheckDisposed();
                    if (_state == State.Started)
                    {
                        return;
                    }

                    try
                    {
                        foreach (var urlPrefix in Options.UrlPrefixes)
                        {
                            RelayConnectionStringBuilder rcb = new RelayConnectionStringBuilder();

                            var relayListener = new HybridConnectionListener(
                                new UriBuilder(urlPrefix.FullPrefix)
                            {
                                Scheme = "sb", Port = -1
                            }.Uri,
                                urlPrefix.TokenProvider != null ? urlPrefix.TokenProvider : Options.TokenProvider);

                            relayListener.RequestHandler = (ctx) => requestHandler(new RequestContext(ctx, new Uri(urlPrefix.FullPrefix)));
                            relayListener.AcceptHandler  = WebSocketAcceptHandler;
                            _relayListeners.Add(relayListener);
                        }
                    }
                    catch (Exception exception)
                    {
                        LogHelper.LogException(Logger, ".Ctor", exception);
                        throw;
                    }


                    foreach (var listener in _relayListeners)
                    {
                        listener.OpenAsync().GetAwaiter().GetResult();
                        //listener.AcceptConnectionAsync().ContinueWith((t) => {
                        //    Console.WriteLine(t);
                        //});
                    }
                    _state = State.Started;
                }
                catch (Exception exception)
                {
                    // Make sure the HttpListener instance can't be used if Start() failed.
                    _state = State.Disposed;
                    LogHelper.LogException(Logger, "Start", exception);
                    throw;
                }
            }
        }
        /// <summary>
        /// Start accepting incoming requests.
        /// </summary>
        public void Start()
        {
            CheckDisposed();

            LogHelper.LogInfo(Logger, nameof(Start));

            // Make sure there are no race conditions between Start/Stop/Abort/Close/Dispose.
            // Start needs to setup all resources. Abort/Stop must not interfere while Start is
            // allocating those resources.
            lock (_internalLock)
            {
                try
                {
                    CheckDisposed();
                    if (_state == State.Started)
                    {
                        return;
                    }

                    try
                    {
                        foreach (var urlPrefix in Options.UrlPrefixes)
                        {
                            var rcb = new RelayConnectionStringBuilder();

                            var tokenProvider = urlPrefix.TokenProvider != null ? urlPrefix.TokenProvider : Options.TokenProvider;
                            if (tokenProvider == null)
                            {
                                throw new InvalidOperationException("No relay token provider defined.");
                            }
                            var relayListener = new HybridConnectionListener(
                                new UriBuilder(urlPrefix.FullPrefix)
                            {
                                Scheme = "sb", Port = -1
                            }.Uri, tokenProvider);

                            relayListener.RequestHandler = (ctx) => requestHandler(new RequestContext(ctx, new Uri(urlPrefix.FullPrefix)));
                            // TODO: CR: An accept handler which simply returns true is the same as no handler at all.
                            // Would returning false and rejecting relayed connection requests be better?
                            relayListener.AcceptHandler = WebSocketAcceptHandler;
                            _relayListeners.Add(relayListener);
                        }
                    }
                    catch (Exception exception)
                    {
                        LogHelper.LogException(Logger, ".Ctor", exception);
                        throw;
                    }
                    foreach (var listener in _relayListeners)
                    {
                        listener.OpenAsync().GetAwaiter().GetResult();
                    }
                    _state = State.Started;
                }
                catch (Exception exception)
                {
                    // Make sure the HttpListener instance can't be used if Start() failed.
                    _state = State.Disposed;
                    LogHelper.LogException(Logger, nameof(Start), exception);
                    throw;
                }
            }
        }
Exemple #20
0
        public ServiceConnectionForwarder(
            string serviceNamespace,
            string ruleName,
            string ruleKey,
            string targetHost,
            string targetHostAlias,
            string allowedPortsString,
            string allowedPipesString)
        {
            this.targetHost   = targetHost;
            noPipeConstraints = false;
            noPortConstraints = false;
            allowedPipes      = new List <string>();
            allowedPorts      = new List <int>();

            allowedPortsString = allowedPortsString.Trim();
            if (allowedPortsString == "*")
            {
                noPortConstraints = true;
            }
            else
            {
                noPortConstraints = false;
                string[] portList = allowedPortsString.Split(',');
                for (int i = 0; i < portList.Length; i++)
                {
                    allowedPorts.Add(int.Parse(portList[i].Trim()));
                }
            }

            allowedPipesString = allowedPipesString.Trim();
            if (allowedPipesString == "*")
            {
                noPipeConstraints = true;
            }
            else
            {
                noPipeConstraints = false;
                string[] pipeList = allowedPipesString.Split(',');
                for (int i = 0; i < pipeList.Length; i++)
                {
                    string pipeName = pipeList[i].Trim();
                    if (pipeName.StartsWith("\\", StringComparison.OrdinalIgnoreCase))
                    {
                        if (!pipeName.StartsWith(localPipePrefix, StringComparison.OrdinalIgnoreCase))
                        {
                            throw new ArgumentException(
                                      string.Format("Invalid pipe name in allowedPipesString. Only relative and local paths permitted: {0}", pipeName),
                                      "allowedPipesString");
                        }
                        pipeName = pipeName.Substring(localPipePrefix.Length);
                    }
                    allowedPipes.Add(pipeName);
                }
            }

            endpointVia = new UriBuilder("sb", serviceNamespace, -1, targetHostAlias).Uri;


            tokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(ruleName, ruleKey);
            relayListener = new HybridConnectionListener(endpointVia, tokenProvider);
        }
        private HybridConnectionListener CreateHybridListener()
        {
            //var tokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(connectionStringBuilder.SharedAccessKeyName, connectionStringBuilder.SharedAccessKey);
            //var uri = new Uri(string.Format("https://{0}/{1}", connectionStringBuilder.Endpoint.Host, hybridConnectionName));
            listener = new HybridConnectionListener(connectionItems.ToString());

            // Subscribe to the status events.
            listener.Connecting += (o, e) => { System.Diagnostics.Debug.WriteLine("Connecting"); };
            listener.Offline    += (o, e) => { System.Diagnostics.Debug.WriteLine("Offline"); };
            listener.Online     += (o, e) => { System.Diagnostics.Debug.WriteLine("Online"); };

            // Provide an HTTP request handler
            listener.RequestHandler = (context) =>
            {
                //TODO if string then handle response
                IActorMessage msg = null;
                if (typeof(MsgType) == typeof(string))
                {
                    var    reader    = new StreamReader(context.Request.InputStream);
                    string msgString = reader.ReadToEnd();
                    msg = msgString.ToActorMessage();
                }
                else if (typeof(MsgType) == typeof(byte[]))
                {
                    var    reader   = new BinaryReader(context.Request.InputStream);
                    byte[] msgBytes = reader.ReadBytes(1024);
                    msg = msgBytes.ToActorMessage();
                }
                else
                {
                    byte[] msgBytes = new byte[context.Request.InputStream.Length];
                    var    reader   = new BinaryReader(context.Request.InputStream);
                    reader.Read(msgBytes, 0, msgBytes.Length);
                    msg = Telegraph.Instance.Ask(new DeserializeMessage <IActorMessage>(msgBytes)).Result;
                }

                if (null == msg.Status)
                {
                    msg.Status = new TaskCompletionSource <IActorMessage>();
                }

                // Store the message in the global queue,
                // call Telegraphy.Net.TPLExtentions Task.Then to send the result back to the relay
                // after we are done processing it
                msg.Status.Task.Then(() =>
                {
                    // Do something with context.Request.Url, HttpMethod, Headers, InputStream...
                    context.Response.StatusCode        = HttpStatusCode.OK;
                    context.Response.StatusDescription = "OK";
                    // The context MUST be closed here
                    context.Response.Close();

                    //using (var sw = new StreamWriter(context.Response.OutputStream))
                    {
                        var relay = new RecieveResponseFromRequest <MsgType, MsgType>(connectionItems.ToString());
                        relay.Tell(msg.Status.Task.Result); // send the answer back to the calling application.
                        //sw.Write(responseMessage);
                    }
                });

                NextMessage = msg;
            };

            listener.OpenAsync().Wait();
            System.Diagnostics.Debug.WriteLine("Hybrid Connection Operator Listening");
            return(listener);
        }
        async Task StatusCodes()
        {
            var endpointTestType = EndpointTestType.Authenticated;
            HybridConnectionListener listener = this.GetHybridConnectionListener(endpointTestType);

            try
            {
                RelayConnectionStringBuilder connectionString = GetConnectionStringBuilder(endpointTestType);
                Uri endpointUri = connectionString.Endpoint;

                TestUtility.Log("Calling HybridConnectionListener.Open");
                await listener.OpenAsync(TimeSpan.FromSeconds(30));

                var httpHandler = new HttpClientHandler {
                    AllowAutoRedirect = false
                };
                Uri hybridHttpUri = new UriBuilder("https://", endpointUri.Host, endpointUri.Port, connectionString.EntityPath).Uri;
                using (var client = new HttpClient(httpHandler)
                {
                    BaseAddress = hybridHttpUri
                })
                {
                    client.DefaultRequestHeaders.ExpectContinue = false;

                    HttpStatusCode[] expectedStatusCodes = new HttpStatusCode[]
                    {
                        HttpStatusCode.Accepted, HttpStatusCode.Ambiguous, HttpStatusCode.BadGateway, HttpStatusCode.BadRequest, HttpStatusCode.Conflict,
                        /*HttpStatusCode.Continue,*/ HttpStatusCode.Created, HttpStatusCode.ExpectationFailed, HttpStatusCode.Forbidden,
                        HttpStatusCode.GatewayTimeout, HttpStatusCode.Gone, HttpStatusCode.HttpVersionNotSupported, HttpStatusCode.InternalServerError,
                        HttpStatusCode.LengthRequired, HttpStatusCode.MethodNotAllowed, HttpStatusCode.MovedPermanently, HttpStatusCode.MultipleChoices,
                        HttpStatusCode.NoContent, HttpStatusCode.NonAuthoritativeInformation, HttpStatusCode.NotAcceptable, HttpStatusCode.NotFound,
                        HttpStatusCode.NotImplemented, HttpStatusCode.NotModified, HttpStatusCode.PartialContent, HttpStatusCode.PaymentRequired,
                        HttpStatusCode.PreconditionFailed, HttpStatusCode.ProxyAuthenticationRequired, HttpStatusCode.Redirect, HttpStatusCode.TemporaryRedirect,
                        HttpStatusCode.RedirectMethod, HttpStatusCode.RequestedRangeNotSatisfiable, HttpStatusCode.RequestEntityTooLarge, HttpStatusCode.RequestTimeout,
                        HttpStatusCode.RequestUriTooLong, HttpStatusCode.ResetContent, HttpStatusCode.ServiceUnavailable,
                        /*HttpStatusCode.SwitchingProtocols,*/ HttpStatusCode.Unauthorized, HttpStatusCode.UnsupportedMediaType,
                        HttpStatusCode.Unused, HttpStatusCode.UpgradeRequired, HttpStatusCode.UseProxy, (HttpStatusCode)418, (HttpStatusCode)450
                    };

                    foreach (HttpStatusCode expectedStatusCode in expectedStatusCodes)
                    {
                        TestUtility.Log($"Testing HTTP Status Code: {(int)expectedStatusCode} {expectedStatusCode}");
                        listener.RequestHandler = (context) =>
                        {
                            TestUtility.Log($"RequestHandler: {context.Request.HttpMethod} {context.Request.Url}");
                            context.Response.StatusCode = expectedStatusCode;
                            context.Response.Close();
                        };

                        var getRequest = new HttpRequestMessage();
                        getRequest.Method = HttpMethod.Get;
                        await AddAuthorizationHeader(connectionString, getRequest, hybridHttpUri);

                        LogRequestLine(getRequest, client);
                        using (HttpResponseMessage response = await client.SendAsync(getRequest))
                        {
                            TestUtility.Log($"Response: HTTP/{response.Version} {(int)response.StatusCode} {response.ReasonPhrase}");
                            Assert.Equal(expectedStatusCode, response.StatusCode);
                        }

                        var postRequest = new HttpRequestMessage();
                        postRequest.Method = HttpMethod.Post;
                        await AddAuthorizationHeader(connectionString, postRequest, hybridHttpUri);

                        string body = "{  \"a\": 11,   \"b\" :22, \"c\":\"test\",    \"d\":true}";
                        postRequest.Content = new StringContent(body);
                        postRequest.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                        LogRequestLine(postRequest, client);
                        using (HttpResponseMessage response = await client.SendAsync(postRequest))
                        {
                            TestUtility.Log($"Response: HTTP/{response.Version} {(int)response.StatusCode} {response.ReasonPhrase}");
                            Assert.Equal(expectedStatusCode, response.StatusCode);
                        }
                    }
                }

                await listener.CloseAsync(TimeSpan.FromSeconds(10));
            }
            finally
            {
                await SafeCloseAsync(listener);
            }
        }
        public static async Task <int> RunTestsAsync(RelayConnectionStringBuilder connectionString, TraceSource traceSource)
        {
            if (string.IsNullOrEmpty(connectionString.EntityPath))
            {
                connectionString.EntityPath = HybridConnectionCommands.DefaultPath;
            }

            var namespaceManager = new RelayNamespaceManager(connectionString.ToString());

            namespaceManager.Settings.OperationTimeout = TimeSpan.FromSeconds(5);
            HybridConnectionListener listener = null;
            bool createdHybridConnection      = false;
            int  returnCode  = 0;
            var  testResults = new List <TestResult>();
            var  cts         = new CancellationTokenSource(TimeSpan.FromSeconds(70));

            try
            {
                createdHybridConnection = await EnsureHybridConnectionExists(traceSource, connectionString, namespaceManager);

                listener = new HybridConnectionListener(connectionString.ToString());
                traceSource.TraceInformation($"Opening {listener}");
                await listener.OpenAsync(cts.Token);

                traceSource.TraceInformation("Listener Opened");

                Uri hybridHttpUri = new Uri($"https://{connectionString.Endpoint.GetComponents(UriComponents.HostAndPort, UriFormat.SafeUnescaped)}/{connectionString.EntityPath}");
                var token         = await listener.TokenProvider.GetTokenAsync(hybridHttpUri.AbsoluteUri, TimeSpan.FromMinutes(20));

                using (var client = new HttpClient {
                    BaseAddress = hybridHttpUri
                })
                {
                    client.DefaultRequestHeaders.ExpectContinue = false;

                    await RunTestAsync("TestPostLargeRequestSmallResponse", null, testResults, () => TestPostLargeRequestSmallResponse(listener, token, client, traceSource));
                    await RunTestAsync("TestPostLargeRequestWithLargeResponse", null, testResults, () => TestPostLargeRequestWithLargeResponse(listener, token, client, traceSource));
                    await RunTestAsync("TestGetLargeResponse", null, testResults, () => TestGetLargeResponse(listener, token, client, traceSource));
                    await RunTestAsync("TestGetSmallResponse", null, testResults, () => TestGetSmallResponse(listener, token, client, traceSource));
                }

                await RunTestAsync("TestStreaming", null, testResults, () => TestStreaming(listener, connectionString, traceSource));

                returnCode = ReportTestResults(testResults);
            }
            catch (Exception exception)
            {
                traceSource.TraceError("FAILURE WHILE RUNNING TESTS");
                RelayTraceSource.TraceException(exception, nameof(HybridConnectionTests));
                returnCode = exception.HResult;
            }
            finally
            {
                cts.Dispose();
                var cleanupCancelSource = new CancellationTokenSource(TimeSpan.FromSeconds(10));
                try
                {
                    if (listener != null)
                    {
                        traceSource.TraceInformation($"Closing {listener}");
                        await listener.CloseAsync(cleanupCancelSource.Token);

                        traceSource.TraceInformation("Listener Closed");
                    }

                    if (createdHybridConnection)
                    {
                        traceSource.TraceEvent(TraceEventType.Information, (int)ConsoleColor.White, $"Deleting HybridConnection '{connectionString.EntityPath}'");
                        await namespaceManager.DeleteHybridConnectionAsync(connectionString.EntityPath);
                    }
                }
                catch (Exception cleanupException)
                {
                    traceSource.TraceWarning($"Error during cleanup: {cleanupException.GetType()}: {cleanupException.Message}");
                }
                finally
                {
                    cleanupCancelSource.Dispose();
                }
            }

            return(returnCode);
        }
 private void StartListener()
 {
     this.listener = CreateHybridListener();
 }
Exemple #25
0
        RelayListenerInitializeAsync(
            string relayNamespace,
            string connectionName,
            string keyName,
            string key,
            TimeSpan?timeout = null,
            CancellationTokenSource cancellationTokenSource = null)
        {
            if (_isInitialized)
            {
                throw new RelayListenerException("Relay Listener can only be initialized once. Create a new instance if multiple listeners are needed.");
            }

            _isInitialized = true;

            // Set default timout to 10 seconds.
            var to = timeout ?? TimeSpan.FromSeconds(10);

            var cts = cancellationTokenSource ?? new CancellationTokenSource();

            var tokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(keyName, key);

            var listener = new HybridConnectionListener(new Uri($"sb://{relayNamespace}/{connectionName}"), tokenProvider);

            // Subscribe to the connection status events.
            listener.Connecting += ConnectingHandler;
            listener.Offline    += OfflineHandler;
            listener.Online     += OnlineHandler;

            await listener.OpenAsync(cts.Token);

            _relayStateObserver.OnNext(RelayListenerConnectionState.Listening);

            var observableRelayMessages = Observable.Create <IMessage>(obs =>
            {
                IDisposable disposableRelayMessages = null;

                var disposableConnections = Observable.While(
                    () => !cts.IsCancellationRequested,
                    Observable.FromAsync(() => listener.AcceptConnectionAsync()))
                                            .Subscribe(connection =>
                {
                    if (connection != null)
                    {
                        disposableRelayMessages = _observableRelayStringLine(connection, cts.Token, to)
                                                  .Subscribe(obs.OnNext, obs.OnError);
                    }
                },
                                                       ex =>
                {
                    _relayStateObserver.OnError(ex);
                    obs.OnError(ex);
                },
                                                       () =>
                {
                    _relayStateObserver.OnCompleted();
                    obs.OnCompleted();
                });

                return(Disposable.Create(() =>
                {
                    disposableConnections?.Dispose();
                    disposableRelayMessages?.Dispose();

                    _relayStateObserver.OnNext(RelayListenerConnectionState.ExitingListener);

                    try
                    {
                        listener.CloseAsync(CancellationToken.None).Wait(new CancellationTokenSource(to).Token);
                    }
                    catch (Exception ex)
                    {
                        _relayStateObserver.OnError(ex);
                    }
                    finally
                    {
                        cts?.Dispose();
                    }

                    listener.Connecting -= ConnectingHandler;
                    listener.Offline -= OfflineHandler;
                    listener.Online -= OnlineHandler;

                    _relayStateObserver.OnCompleted();
                }));
            }).Publish().RefCount();

            return(_relayStateObservable, observableRelayMessages);
        }
Exemple #26
0
        async Task SmallRequestSmallResponse(EndpointTestType endpointTestType)
        {
            var cts = new CancellationTokenSource(TimeSpan.FromSeconds(60));
            HybridConnectionListener listener = null;

            try
            {
                listener = this.GetHybridConnectionListener(endpointTestType);
                RelayConnectionStringBuilder connectionString = GetConnectionStringBuilder(endpointTestType);
                Uri endpointUri = connectionString.Endpoint;

                string         expectedResponse   = "{ \"a\" : true }";
                HttpStatusCode expectedStatusCode = HttpStatusCode.OK;
                listener.RequestHandler = (context) =>
                {
                    TestUtility.Log("HybridConnectionListener.RequestHandler invoked with Request:");
                    TestUtility.Log($"{context.Request.HttpMethod} {context.Request.Url}");
                    context.Request.Headers.AllKeys.ToList().ForEach((k) => TestUtility.Log($"{k}: {context.Request.Headers[k]}"));
                    TestUtility.Log(StreamToString(context.Request.InputStream));

                    context.Response.StatusCode = expectedStatusCode;
                    byte[] responseBytes = Encoding.UTF8.GetBytes(expectedResponse);
                    context.Response.OutputStream.Write(responseBytes, 0, responseBytes.Length);
                    context.Response.Close();
                };

                TestUtility.Log($"Opening {listener}");
                await listener.OpenAsync(cts.Token);

                Uri hybridHttpUri = new UriBuilder("https://", endpointUri.Host, endpointUri.Port, connectionString.EntityPath).Uri;
                using (var client = new HttpClient {
                    BaseAddress = hybridHttpUri
                })
                {
                    client.DefaultRequestHeaders.ExpectContinue = false;

                    var getRequest = new HttpRequestMessage();
                    await AddAuthorizationHeader(connectionString, getRequest, hybridHttpUri);

                    getRequest.Method = HttpMethod.Get;
                    LogHttpRequest(getRequest, client);
                    using (HttpResponseMessage response = await client.SendAsync(getRequest, cts.Token))
                    {
                        LogHttpResponse(response);
                        Assert.Equal(expectedStatusCode, response.StatusCode);
                        Assert.Equal("OK", response.ReasonPhrase);
                        Assert.Equal(expectedResponse, await response.Content.ReadAsStringAsync());
                    }

                    var postRequest = new HttpRequestMessage();
                    await AddAuthorizationHeader(connectionString, postRequest, hybridHttpUri);

                    postRequest.Method = HttpMethod.Post;
                    string body = "{  \"a\": 11,   \"b\" :22, \"c\":\"test\",    \"d\":true}";
                    postRequest.Content = new StringContent(body);
                    postRequest.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                    LogHttpRequest(postRequest, client);
                    using (HttpResponseMessage response = await client.SendAsync(postRequest, cts.Token))
                    {
                        LogHttpResponse(response);
                        Assert.Equal(expectedStatusCode, response.StatusCode);
                        Assert.Equal("OK", response.ReasonPhrase);
                        Assert.Equal(expectedResponse, await response.Content.ReadAsStringAsync());
                    }
                }

                TestUtility.Log($"Closing {listener}");
                await listener.CloseAsync(cts.Token);

                listener = null;
            }
            finally
            {
                cts.Dispose();
                await this.SafeCloseAsync(listener);
            }
        }
Exemple #27
0
        static async Task Main(string[] args)
        {
            string hostAddress;
            string hybridConnectionName;
            string clientId     = null;
            string tenantId     = null;
            string clientSecret = null;
            RbacAuthenticationOption option;

            if (args.Length == 2)
            {
                option               = RbacAuthenticationOption.ManagedIdentity;
                hostAddress          = args[0];
                hybridConnectionName = args[1];
            }
            else if (args.Length == 3)
            {
                option               = RbacAuthenticationOption.UserAssignedIdentity;
                hostAddress          = args[0];
                hybridConnectionName = args[1];
                clientId             = args[2];
            }
            else if (args.Length == 5)
            {
                option               = RbacAuthenticationOption.AAD;
                hostAddress          = args[0];
                hybridConnectionName = args[1];
                clientId             = args[2];
                tenantId             = args[3];
                clientSecret         = args[4];
            }
            else
            {
                Console.WriteLine("Please run with parameters of the following format for the corresponding RBAC authentication method:");
                Console.WriteLine("System Managed Identity: [HostAddress] [HybridConnectionName]");
                Console.WriteLine("User Assigned Identity: [HostAddress] [HybridConnectionName] [ClientId]");
                Console.WriteLine("Azure Active Directory:  [HostAddress] [HybridConnectionName] [ClientId] [TenantId] [ClientSecret]");
                Console.WriteLine("Press <Enter> to exit...");
                Console.ReadLine();
                return;
            }

            TokenProvider tokenProvider = null;

            switch (option)
            {
            case RbacAuthenticationOption.ManagedIdentity:
                tokenProvider = TokenProvider.CreateManagedIdentityTokenProvider();
                break;

            case RbacAuthenticationOption.UserAssignedIdentity:
                var managedCredential = new ManagedIdentityCredential(clientId);
                tokenProvider = TokenProvider.CreateManagedIdentityTokenProvider(managedCredential);
                break;

            case RbacAuthenticationOption.AAD:
                tokenProvider = GetAadTokenProvider(clientId, tenantId, clientSecret);
                break;
            }

            var hybridConnectionUri           = new Uri($"{hostAddress}/{hybridConnectionName}");
            HybridConnectionListener listener = null;

            try
            {
                // The HybridConnection should be already created through Azure Portal or other means
                Console.WriteLine($"Creating the Relay listener instance with RBAC option: {option}");
                listener = new HybridConnectionListener(hybridConnectionUri, tokenProvider);

                await listener.OpenAsync(TimeSpan.FromSeconds(10));

                Console.WriteLine("Created and connected the Relay listener instance.");

                Console.WriteLine($"Creating the Relay sender instance with RBAC option: {option}");
                var sender             = new HybridConnectionClient(hybridConnectionUri, tokenProvider);
                var createSenderTask   = sender.CreateConnectionAsync();
                var listenerAcceptTask = listener.AcceptConnectionAsync();
                using (HybridConnectionStream senderStream = await createSenderTask)
                    using (HybridConnectionStream listenerStream = await listenerAcceptTask)
                    {
                        Console.WriteLine("Created and connected the Relay sender instance.");
                        var senderCloseTask = senderStream.CloseAsync(CancellationToken.None);
                        await listenerStream.CloseAsync(CancellationToken.None);

                        await senderCloseTask;
                    }

                // Configure a RequestHandler for HTTP request/response mode
                listener.RequestHandler = (context) =>
                {
                    context.Response.StatusCode = HttpStatusCode.OK;
                    using (var sw = new StreamWriter(context.Response.OutputStream))
                    {
                        sw.WriteLine("hello!");
                    }

                    // The context must be closed to complete sending the response
                    context.Response.Close();
                };

                Console.WriteLine($"Sending a HTTP request by setting the token in request header with RBAC option: {option}");
                SecurityToken token = await tokenProvider.GetTokenAsync(hybridConnectionUri.AbsoluteUri, TimeSpan.FromMinutes(30));

                var request = new HttpRequestMessage();
                request.Headers.Add(HttpRequestHeader.Authorization.ToString(), token.TokenString);
                var requestUri = new UriBuilder(hybridConnectionUri)
                {
                    Scheme = "https"
                }.Uri;
                using (HttpClient client = new HttpClient {
                    BaseAddress = requestUri
                })
                {
                    using (var response = await client.SendAsync(request))
                    {
                        Console.WriteLine($"Response status code: {response.StatusCode}. Response reason phrase: {response.ReasonPhrase}");
                    }
                }

                Console.WriteLine($"Sending a HTTP request by setting the token in query string with RBAC option: {option}");
                token = await tokenProvider.GetTokenAsync(hybridConnectionUri.AbsoluteUri, TimeSpan.FromMinutes(30));

                request    = new HttpRequestMessage();
                requestUri = new UriBuilder(requestUri)
                {
                    Query = $"?sb-hc-token={token.TokenString}"
                }.Uri;
                using (HttpClient client = new HttpClient {
                    BaseAddress = requestUri
                })
                {
                    using (var response = await client.SendAsync(request))
                    {
                        Console.WriteLine($"Response status code: {response.StatusCode}. Response reason phrase: {response.ReasonPhrase}");
                    }
                }

                Console.WriteLine("Press <Enter> to exit...");
                Console.ReadLine();
            }
            finally
            {
                if (listener != null)
                {
                    await listener.CloseAsync();
                }
            }
        }