Ejemplo n.º 1
0
        public async void GetWebRequest(int connectionID, Uri webUri, bool autoConvertResponse)
        {
            // Block all non-internet IP address
            if (HostnameIsPrivateIPAddress(webUri))
            {
                midiManager.SendWebRequestFailedResponse(connectionID, WEB_REQUEST_FAILED_ERROR_CODE);
                return;
            }

            // Block all non http/https traffic
            if (webUri.Scheme != Uri.UriSchemeHttp && webUri.Scheme != Uri.UriSchemeHttps)
            {
                Console.WriteLine("Error: World attempted to open unsupported URI: " + webUri.Scheme);
                midiManager.SendWebRequestFailedResponse(connectionID, WEB_REQUEST_FAILED_ERROR_CODE);
                return;
            }

            // Block all rate limited domain+path combos
            // Temporarily changed to include entire host
            var hostAndPath = new HostnameAndPath(webUri.Host, "");

            if (rateLimitedURIs.ContainsKey(hostAndPath))
            {
                if (DateTime.Now < rateLimitedURIs[hostAndPath])
                {
                    Console.WriteLine("ERROR: Could not make web request, currently rate limited.");
                    midiManager.SendWebRequestFailedResponse(connectionID, RATE_LIMITED_ERROR_CODE);
                    return;
                }
                else
                {
                    rateLimitedURIs.Remove(hostAndPath);
                }
            }

            HttpResponseMessage response;

            try
            {
                response = await httpClient.GetAsync(webUri, ctSource.Token);
            }
            catch (Exception e)
            {
                Console.WriteLine("HTTP request failed: " + e.Message);
                rateLimitedURIs.Add(hostAndPath, DateTime.Now.AddSeconds(RATE_LIMIT_TIMEOUT_SECONDS));
                midiManager.SendWebRequestFailedResponse(connectionID, WEB_REQUEST_FAILED_ERROR_CODE);
                return;
            }

            // Rate limit unsuccessful requests
            if (!response.IsSuccessStatusCode)
            {
                rateLimitedURIs.Add(hostAndPath, DateTime.Now.AddSeconds(RATE_LIMIT_TIMEOUT_SECONDS));
            }
            Console.WriteLine("Received web response (" + connectionID + "): " + webUri.AbsoluteUri);
            AddWebResponse(response, connectionID, autoConvertResponse);
        }
Ejemplo n.º 2
0
        public async void OpenWebSocketConnection(int connectionID, Uri webUri, bool autoConvertResponses)
        {
            // Block all non-internet IP address
            if (HostnameIsPrivateIPAddress(webUri))
            {
                Console.WriteLine("Closing websocket connection " + connectionID);
                midiManager.SendWebSocketClosedResponse(connectionID);
                return;
            }

            if (webUri.Scheme != "ws" && webUri.Scheme != "wss")
            {
                Console.WriteLine("Error: World attempted to open unsupported URI: " + webUri.Scheme);
                Console.WriteLine("Closing websocket connection " + connectionID);
                midiManager.SendWebSocketClosedResponse(connectionID);
                return;
            }

            // Block all rate limited domain+path combos
            var hostAndPath = new HostnameAndPath(webUri.Host, "");

            if (rateLimitedURIs.ContainsKey(hostAndPath))
            {
                if (DateTime.Now < rateLimitedURIs[hostAndPath])
                {
                    Console.WriteLine("ERROR: Could not open websocket connection, currently rate limited.");
                    Console.WriteLine("Closing websocket connection " + connectionID);
                    midiManager.SendWebSocketClosedResponse(connectionID);
                    return;
                }
                else
                {
                    rateLimitedURIs.Remove(hostAndPath);
                }
            }

            webSockets[connectionID] = new ClientWebSocket();
            ClientWebSocket cws = webSockets[connectionID];

            try
            {
                await cws.ConnectAsync(webUri, ctSource.Token);
            }
            catch (WebSocketException e)
            {
                rateLimitedURIs.Add(hostAndPath, DateTime.Now.AddSeconds(RATE_LIMIT_TIMEOUT_SECONDS));
                Console.WriteLine("Failed to open websocket: " + e.Message);
                Console.WriteLine("Closing websocket connection " + connectionID);
                midiManager.SendWebSocketClosedResponse(connectionID);
                webSockets[connectionID] = null;
                return;
            }
            catch (OperationCanceledException)
            {
                return;
            }

            while (cws.State == WebSocketState.Connecting)
            {
                ;
            }
            if (cws.State == WebSocketState.Open)
            {
                midiManager.SendWebSocketOpenedResponse(connectionID);
            }

            wsBuffers[connectionID]             = new ArraySegment <byte>(new byte[WEBSOCKET_BUFFER_SIZE]);
            wsAutoConvertMessages[connectionID] = autoConvertResponses;
            while (cws.State == WebSocketState.Open)
            {
                WebSocketReceiveResult wssr = null;
                try
                {
                    wssr = await cws.ReceiveAsync(wsBuffers[connectionID], ctSource.Token);
                }
                catch (WebSocketException e)
                {
                    // Aborted state.  To or to not rate limit, because twitch likes to
                    // abort any connection when a nickname is already taken...
                    Console.WriteLine("WebSocketException: " + e.Message);
                    Console.WriteLine("Closing websocket connection " + connectionID);
                    midiManager.SendWebSocketClosedResponse(connectionID);
                    webSockets[connectionID] = null;
                    break;
                }
                catch (OperationCanceledException)
                {
                    break;
                }
                catch (Exception e)
                {
                    Console.WriteLine("Exception: " + e.Message);
                    Console.WriteLine("Closing websocket connection " + connectionID);
                    midiManager.SendWebSocketClosedResponse(connectionID);
                    webSockets[connectionID] = null;
                    break;
                }

                // Copy data to an intermediate array in case it needs to be converted from UTF8 to UTF16
                byte[] message = new byte[wssr.Count];
                Array.Copy(wsBuffers[connectionID].Array, 0, message, 0, wssr.Count);
                Console.WriteLine("Received websocket message: " + Encoding.UTF8.GetString(message));
                if (wsAutoConvertMessages[connectionID] && (wssr.MessageType == WebSocketMessageType.Text))
                {
                    message = Encoding.Convert(Encoding.UTF8, Encoding.Unicode, message);
                }

                // Send 4 bytes for response length, 1 bytes for txt/bin flag, and then response data
                byte[] responseData = new byte[4 + 1 + message.Length];
                Array.Copy(BitConverter.GetBytes(message.Length + 1), 0, responseData, 0, 4);
                responseData[4] = wssr.MessageType == WebSocketMessageType.Text ? (byte)0x0 :(byte)0x1;
                Array.Copy(message, 0, responseData, 5, message.Length);
                midiManager.AddConnectionResponse((byte)connectionID, responseData);
            }
        }