Ejemplo n.º 1
0
        private static void SendFile(Stream stream, FileInfo fileInfo, string contentType, string contentDisposition)
        {
            if (fileInfo.Exists)
            {
                var messageBytes = Encoding.UTF8.GetBytes("HTTP/1.1 200 OK\r\n" +
                                                          $"Date: {DateTime.UtcNow:R}\r\n" +
                                                          $"Content-Type: {contentType}\r\n" +
                                                          $"Content-Disposition: {contentDisposition}; filename=\"{fileInfo.Name}\"\r\n" +
                                                          $"Last-Modified: {fileInfo.LastWriteTimeUtc:R}\r\n" +
                                                          "Content-Transfer-Encoding: binary\r\n" +
                                                          $"Content-Length: {fileInfo.Length}\r\n\r\n");
                stream.Write(messageBytes, 0, messageBytes.Length);

                try
                {
                    WebStats.AddFileDownload(fileInfo.Length);
                    using (var fs = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        fs.CopyTo(stream);
                    }
                }
                catch (Exception e)
                {
                    Helper.WriteLogEntry($"{fileInfo.FullName}\n{e.Message}");
                }
            }
            else
            {
                WebStats.Increment404Response();
                var messageBytes = Encoding.UTF8.GetBytes($"HTTP/1.1 404 Not Found\r\nDate: {DateTime.UtcNow:R}\r\n\r\n");
                stream.Write(messageBytes, 0, messageBytes.Length);
            }
        }
Ejemplo n.º 2
0
        private static void SendImage(Stream stream, FileInfo fileInfo)
        {
            if (fileInfo != null && fileInfo.Exists)
            {
                var ext          = fileInfo.Extension.ToLower().Substring(1);
                var messageBytes = Encoding.UTF8.GetBytes("HTTP/1.1 200 OK\r\n" +
                                                          "Accept-Ranges: bytes\r\n" +
                                                          $"Content-Length: {fileInfo.Length}\r\n" +
                                                          $"Content-Type: image/{ext}\r\n" +
                                                          $"Date: {DateTime.UtcNow:R}\r\n" +
                                                          $"Last-Modified: {fileInfo.LastWriteTimeUtc:R}\r\n\r\n");
                stream.Write(messageBytes, 0, messageBytes.Length);

                try
                {
                    using (var fs = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        fs.CopyTo(stream);
                    }
                }
                catch (Exception e)
                {
                    Helper.WriteLogEntry($"{fileInfo.FullName}\n{e.Message}");
                }
            }
            else
            {
                WebStats.Increment404Response();
                var messageBytes = Encoding.UTF8.GetBytes($"HTTP/1.1 404 Not Found\r\nDate: {DateTime.UtcNow:R}\r\n\r\n");
                stream.Write(messageBytes, 0, messageBytes.Length);
            }
        }
Ejemplo n.º 3
0
        private static bool Send304OrImageFromCache(Stream stream, DateTime ifModifiedSince, FileInfo fileInfo, bool logo = false)
        {
            if (ifModifiedSince != DateTime.MinValue && ifModifiedSince.ToUniversalTime() + TimeSpan.FromSeconds(1) > (fileInfo?.LastWriteTimeUtc ?? DateTime.MinValue))
            {
                WebStats.Increment304Response();
                var message = "HTTP/1.1 304 Not Modified\r\n" +
                              $"Date: {DateTime.UtcNow:R}\r\n" +
                              $"Last-Modified: {ifModifiedSince.ToUniversalTime() - TimeSpan.FromSeconds(1):R}\r\n";
                var messageBytes = Encoding.UTF8.GetBytes($"{message}\r\n");
                stream.Write(messageBytes, 0, messageBytes.Length);
                return(true);
            }

            if (fileInfo == null)
            {
                return(false);
            }
            if (!logo)
            {
                WebStats.AddCacheDownload(fileInfo.Length);
            }
            else
            {
                WebStats.AddLogoDownload(fileInfo.Length);
            }
            SendImage(stream, fileInfo);
            return(true);
        }
Ejemplo n.º 4
0
        private static void ProcessLogoRequest(Stream stream, string asset, DateTime ifModifiedSince)
        {
            WebStats.IncrementLogoRequestReceived();
            var fileInfo = new FileInfo($"{Helper.Epg123LogosFolder}\\{asset.Substring(7)}");

            if (fileInfo.Exists && Send304OrImageFromCache(stream, ifModifiedSince, fileInfo, true))
            {
                return;
            }

            // nothing to give the client
            WebStats.Increment404Response();
            var messageBytes = Encoding.UTF8.GetBytes($"HTTP/1.1 404 Not Found\r\nDate: {DateTime.UtcNow:R}\r\n\r\n");

            stream.Write(messageBytes, 0, messageBytes.Length);
        }
Ejemplo n.º 5
0
        private static void ProcessFileRequest(Stream stream, string asset)
        {
            string filepath = null, type = "text/xml", disposition = "attachment";

            switch (asset)
            {
            case "/trace.log":
                filepath    = Helper.Epg123TraceLogPath;
                type        = "text/plain";
                disposition = "inline";
                break;

            case "/server.log":
                filepath    = Helper.Epg123ServerLogPath;
                type        = "text/plain";
                disposition = "inline";
                break;

            case "/output/epg123.mxf":
                filepath = Helper.Epg123MxfPath;
                break;

            case "/output/epg123.xmltv":
                filepath = Config.GetXmltvPath();
                break;
            }

            if (filepath != null)
            {
                WebStats.IncrementFileRequestReceived();
                SendFile(stream, new FileInfo(filepath), type, disposition);
            }
            else
            {
                var messageBytes = Encoding.UTF8.GetBytes($"HTTP/1.1 404 Not Found\r\nDate: {DateTime.UtcNow:R}\r\n\r\n");
                stream.Write(messageBytes, 0, messageBytes.Length);
            }
        }
Ejemplo n.º 6
0
        public static bool RefreshTokenFromSD()
        {
            if (DateTime.Now - lastRefresh < TimeSpan.FromMinutes(1))
            {
                return(true);
            }

            // get username and passwordhash
            var config = Config.GetEpgConfig();

            if (config?.UserAccount == null)
            {
                goto End;
            }

            // create the request with headers
            var body = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new TokenRequest {
                Username = config.UserAccount.LoginName, PasswordHash = config.UserAccount.PasswordHash
            }));
            var req = (HttpWebRequest)WebRequest.Create($"{Helper.SdBaseName}/token");

            req.UserAgent              = "EPG123";
            req.Method                 = "POST";
            req.ContentType            = "application/json";
            req.Accept                 = "application/json";
            req.ContentLength          = body.Length;
            req.AutomaticDecompression = DecompressionMethods.Deflate;
            req.Timeout                = 3000;

            // write the json username and password hash to the request stream
            var reqStream = req.GetRequestStream();

            reqStream.Write(body, 0, body.Length);
            reqStream.Close();

            // send request and get response
            try
            {
                using (var response = req.GetResponse() as HttpWebResponse)
                    using (var sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
                    {
                        var ret = JsonConvert.DeserializeObject <TokenResponse>(sr.ReadToEnd());
                        if (ret == null || ret.Code != 0)
                        {
                            goto End;
                        }
                        WebStats.IncrementTokenRefresh();

                        using (var key = Registry.LocalMachine.CreateSubKey(@"SOFTWARE\GaRyan2\epg123", RegistryKeyPermissionCheck.ReadWriteSubTree))
                        {
                            if (key != null)
                            {
                                key.SetValue("token", ret.Token);
                                key.SetValue("tokenExpires", $"{ret.Datetime.AddDays(1):R}");
                                Helper.WriteLogEntry("Refreshed token upon receiving an UNKNOWN_USER (5004) error code.");
                                lastRefresh = DateTime.Now;
                                return(GoodToken = true);
                            }
                        }
                    }
            }
            catch (WebException ex)
            {
                Helper.WriteLogEntry($"SD API WebException Thrown. Message: {ex.Message} , Status: {ex.Status}");
            }

End:
            Helper.WriteLogEntry("Failed to refresh token upon receiving an UNKNOWN_USER (5004) error code.");
            return(GoodToken = false);
        }
Ejemplo n.º 7
0
        private void HandleRequestError(Stream stream, string asset, WebResponse webResponse, DateTime ifModifiedSince, MemoryStream memStream, bool retry)
        {
            using (var sr = new StreamReader(memStream, Encoding.UTF8))
                using (var response = webResponse as HttpWebResponse)
                {
                    var statusCode        = (int)response.StatusCode;
                    var statusDescription = response.StatusDescription;

                    var resp = sr.ReadToEnd();
                    var err  = new BaseResponse();
                    try
                    {
                        err = JsonConvert.DeserializeObject <BaseResponse>(resp);
                        switch (err.Code)
                        {
                        case 5000: // IMAGE_NOT_FOUND
                            statusCode        = 404;
                            statusDescription = "Not Found";
                            break;

                        case 5002: // MAX_IMAGE_DOWNLOADS
                            lock (_limitLock) _limitExceeded = WebStats.LimitLocked = true;
                            statusCode        = 429;
                            statusDescription = "Too Many Requests";
                            break;

                        case 5004: // UNKNOWN_USER
                            bool refresh;
                            lock (_tokenLock) refresh = TokenService.GoodToken && TokenService.RefreshToken && !retry && TokenService.RefreshTokenFromSD();

                            if (refresh)
                            {
                                WebStats.AddSdDownload(0);
                                ProcessImageRequest(stream, asset, ifModifiedSince, true);
                                return;
                            }
                            statusCode        = 401;
                            statusDescription = "Unauthorized";
                            break;
                        }
                    }
                    catch
                    {
                        // do nothing
                    }

                    switch (statusCode)
                    {
                    case 401:
                        WebStats.Increment401Response();
                        break;

                    case 404:
                        WebStats.Increment404Response();
                        break;

                    case 429:
                        WebStats.Increment429Response();
                        break;

                    case 502:
                        WebStats.Increment502Response();
                        break;

                    default:
                        WebStats.IncrementOtherResponse();
                        break;
                    }

                    // log the error response
                    if (!(err.Code == 5002 && _limitExceeded) && !(err.Code == 5004 && !TokenService.GoodToken))
                    {
                        Helper.WriteLogEntry($"{asset}: {statusCode} {statusDescription}{(!string.IsNullOrEmpty(resp) ? $"\n{resp}" : "")}");
                    }

                    // send response header and body to client
                    var message = $"HTTP/1.1 {statusCode} {statusDescription}\r\n";
                    for (var i = 0; i < response.Headers.Count; ++i)
                    {
                        message += $"{response.Headers.Keys[i]}: {response.Headers[i]}\r\n";
                    }
                    var messageBytes = Encoding.UTF8.GetBytes($"{message}\r\n");
                    stream.Write(messageBytes, 0, messageBytes.Length);

                    if (string.IsNullOrEmpty(resp))
                    {
                        return;
                    }
                    var body = Encoding.UTF8.GetBytes(resp);
                    stream.Write(body, 0, body.Length);
                }
        }
Ejemplo n.º 8
0
        private void ProcessImageRequest(Stream stream, string asset, DateTime ifModifiedSince, bool retry = false)
        {
            // update web stats
            if (ifModifiedSince == DateTime.MinValue)
            {
                WebStats.IncrementRequestReceived();
            }
            else
            {
                WebStats.IncrementConditionalRequestReceived();
            }

            // throttle refreshing images that have already been checked recently
            if (JsonImageCache.cacheImages && JsonImageCache.IsImageRecent(asset.Substring(7), ifModifiedSince))
            {
                if (Send304OrImageFromCache(stream, ifModifiedSince, JsonImageCache.GetCachedImage(asset)))
                {
                    return;
                }
            }

            // build url for Schedules Direct with token
            var url = $"{Helper.SdBaseName}{asset}";

            if (!string.IsNullOrEmpty(TokenService.Token))
            {
                url += $"?token={TokenService.Token}";
            }

            // create web request
            var request = (HttpWebRequest)WebRequest.Create(url);

            // add if-modified-since as needed
            var fileInfo = JsonImageCache.cacheImages ? JsonImageCache.GetCachedImage(asset) : null;

            if (ifModifiedSince != DateTime.MinValue || fileInfo != null)
            {
                request.IfModifiedSince = new[] { ifModifiedSince.ToUniversalTime(), fileInfo?.LastWriteTimeUtc ?? DateTime.MinValue }.Max();
            }

            try
            {
                // update web stats
                if (request.IfModifiedSince == DateTime.MinValue)
                {
                    WebStats.IncrementRequestSent();
                }
                else
                {
                    WebStats.IncrementConditionalRequestSent();
                }

                // get response
                using (var response = request.GetResponseWithoutException() as HttpWebResponse)
                    using (var memStream = new MemoryStream())
                    {
                        response.GetResponseStream().CopyTo(memStream);
                        memStream.Position = 0;

                        // if image is included
                        if (memStream.Length > 0 && response.ContentType.StartsWith("image"))
                        {
                            // update web stats
                            WebStats.AddSdDownload(memStream.Length);

                            // success implies limit has not been exceeded
                            lock (_limitLock) { _limitExceeded = WebStats.LimitLocked = false; }

                            // send response to client
                            var message = $"HTTP/1.1 {(int) response.StatusCode} {response.StatusDescription}\r\n";
                            for (var i = 0; i < response.Headers.Count; ++i)
                            {
                                message += $"{response.Headers.Keys[i]}: {response.Headers[i]}\r\n";
                            }
                            var messageBytes = Encoding.UTF8.GetBytes($"{message}\r\n");
                            stream.Write(messageBytes, 0, messageBytes.Length);
                            memStream.CopyTo(stream);
                            if (!JsonImageCache.cacheImages)
                            {
                                return;
                            }

                            // save image to cache if enabled
                            memStream.Position = 0;
                            var filename = asset.Substring(7);
                            var dirInfo  = Directory.CreateDirectory($"{Helper.Epg123ImageCache}\\{filename.Substring(0, 1)}");
                            var location = $"{dirInfo.FullName}\\{filename}";
                            using (var fStream = new FileStream(location, FileMode.Create, FileAccess.Write))
                            {
                                memStream.CopyTo(fStream);
                                fStream.Flush();
                            }
                            File.SetLastWriteTimeUtc(location, response.LastModified);
                            JsonImageCache.AddImageToCache(filename, response.LastModified);
                            return;
                        }

                        // handle any 304 or 404 responses by providing either a 304 response or the cached image if available
                        if (Send304OrImageFromCache(stream, ifModifiedSince, fileInfo))
                        {
                            return;
                        }

                        // reject a 200 response that has no content
                        if (response.StatusCode == HttpStatusCode.OK && memStream.Length == 0)
                        {
                            WebStats.Increment502Response();
                            var message = "HTTP/1.1 502 Bad Gateway\r\n" +
                                          $"Date: {DateTime.UtcNow:R}\r\n";
                            var messageBytes = Encoding.UTF8.GetBytes($"{message}\r\n");
                            stream.Write(messageBytes, 0, messageBytes.Length);
                            return;
                        }

                        // handle any errors from SD
                        HandleRequestError(stream, asset, response, ifModifiedSince, memStream, retry); // 200 for exceeded image limit or unknown user
                        return;
                    }
            }
            catch (WebException e)
            {
                Helper.WriteLogEntry($"{asset}\nWebException: {e.Status} - {e.Message}");
            }

            // fallback for failed connection
            if (Send304OrImageFromCache(stream, ifModifiedSince, fileInfo))
            {
                return;
            }

            // nothing to give the client
            WebStats.Increment404Response();
            var messageBytes2 = Encoding.UTF8.GetBytes($"HTTP/1.1 404 Not Found\r\nDate: {DateTime.UtcNow:R}\r\n\r\n");

            stream.Write(messageBytes2, 0, messageBytes2.Length);
        }