Пример #1
0
        public IActionResult Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req,
            ILogger log,
            ExecutionContext context)
        {
            _config = FunctionsHelper.GetConfig(context);
            _log    = log;

            string url = req.Query["url"];

            if (!IsWhitelisted(url))
            {
                return(new NotFoundResult());
            }

            log.LogInformation($"Redirect: 302 {url}");

            InsightsHelper.TrackEvents(_telemetryClient, "FunMetrics.Redirect", url, req);

            return(new RedirectResult(url, false));
        }
Пример #2
0
        public async Task <IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "head", Route = null)] HttpRequest req,
            ILogger log,
            ExecutionContext context)
        {
            _config = FunctionsHelper.GetConfig(context);

            string path = req.Query["path"];

            log.LogInformation($"FunMetrics.Blob.Run: {req.Method} {path}");

            if (string.IsNullOrWhiteSpace(path))
            {
                log.LogError("Querystring param \"path\" is null, empty or missing.");
                return(new NotFoundResult());
            }
            if (path.StartsWith('/') || !path.Contains('/'))
            {
                log.LogError("Querystring param \"path\" is malformed. Must be a relative path to a blob file, with no leading \"/\".");
                return(new NotFoundResult());
            }

            var uri = new Uri($"{CloudBlobClient.BaseUri}{path}");

            log.LogInformation($"FunMetrics.Blob.Run: {req.Method} {uri}");

            ICloudBlob blob;

            try
            {
                blob = await CloudBlobClient.GetBlobReferenceFromServerAsync(uri);
            }
            catch (StorageException ex)
            {
                log.LogError(ex, "Returning 404 / Not found.");
                return(new NotFoundResult());
            }

            if (req.Method == HttpMethods.Head)
            {
                // HEAD - Return empty body but with headers as if GET
                req.HttpContext.Response.Headers["ETag"] = blob.Properties.ETag;
                req.HttpContext.Response.ContentLength   = blob.Properties.Length;
                req.HttpContext.Response.ContentType     = blob.Properties.ContentType;

                if (blob.Properties.LastModified.HasValue)
                {
                    req.HttpContext.Response.Headers["Last-Modified"] = blob.Properties.LastModified.Value.ToString("r");
                }

                return(new OkResult());
            }

            // GET - get blob and stream to client
            InsightsHelper.TrackEvents(_telemetryClient, "FunMetrics.Blob", uri.ToString(), req);

            Stream stream = null;

            // try local cache
#if DEBUG
            string cachePath = Path.GetTempPath();
#else
            string cachePath = "D:\\Local\\";
#endif

            string filePath   = $"{cachePath}{path.Replace("/", "__")}";
            bool   cacheError = false;

            if (File.Exists(filePath))
            {
                // retry three times
                for (int i = 0; i < 3; i++)
                {
                    // get from local cache
                    try
                    {
                        stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
                        log.LogInformation($"FunMetrics.Blob.Run: Cache HIT {filePath}");
                        break;
                    }
                    catch (Exception ex)
                    {
                        log.LogError(ex, $"Could not open file \"{filePath}\" on attempt {i + 1}: {ex} {ex.Message}");
                        await Task.Delay(10);
                    }

                    cacheError = true;
                }
            }

            if (stream == null)
            {
                // get from Blob
                log.LogInformation($"FunMetrics.Blob.Run: Cache MISS {filePath}");
                stream = new MemoryStream();
                await blob.DownloadToStreamAsync(stream);

                // don't try to save to cache if could not read from cache. File exists, was busy
                if (!cacheError)
                {
                    // save to cache
                    try
                    {
                        using (var fileStream = new FileStream(filePath, FileMode.CreateNew, FileAccess.Write))
                        {
                            stream.Seek(0, SeekOrigin.Begin);
                            stream.CopyTo(fileStream);
                        }
                    }
                    catch (Exception ex)
                    {
                        log.LogError(ex, $"Could not cache file \"{filePath}\".");
                    }
                }
            }

            stream.Seek(0, SeekOrigin.Begin);

            return(new FileStreamResult(stream, blob.Properties.ContentType)
            {
                EnableRangeProcessing = true,
                EntityTag = new EntityTagHeaderValue(blob.Properties.ETag),
                LastModified = blob.Properties.LastModified
            });
        }