Пример #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);
            }
        }
Пример #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);
            }
        }
Пример #3
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);
        }
Пример #4
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);
                }
        }
Пример #5
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);
        }