using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Reflection; using System.Web; using System.Web.Caching; using AshMind.Web.Snapshots.Sizing; namespace AshMind.Web.Snapshots.Handlers { public class SnapshotHandler : IHttpHandler { public void ProcessRequest(HttpContext context) { context.Response.ContentType = "image/" + this.ImageFormat.ToString().ToLowerInvariant(); context.Response.Cache.SetExpires(DateTime.Now + this.ExpiresIn); context.Response.Cache.SetCacheability(HttpCacheability.Public); var cacheKey = this.GetCacheKey(context); var bytes = context.Cache.Get(cacheKey) as byte[]; if (bytes == null) { var url = new Uri(context.Request["url"]); this.EnsureUriIsAllowed(url); var size = GetSnapshotSize(context); bytes = this.GetSnapshot(url, size); context.Cache.Add( cacheKey, bytes, null, DateTime.Now + this.ExpiresIn, Cache.NoSlidingExpiration, CacheItemPriority.Default, null ); } context.Response.OutputStream.Write(bytes, 0, bytes.Length); } protected virtual void EnsureUriIsAllowed(Uri uri) { if (IsUriAllowed(uri)) return; throw new UnauthorizedAccessException(); } protected virtual bool IsUriAllowed(Uri uri) { return uri.Scheme.StartsWith(Uri.UriSchemeHttp); } private string GetCacheKey(HttpContext context) { return context.Request.Url.PathAndQuery; } private byte[] GetSnapshot(Uri url, IWebSnapshotSize size) { using (var stream = new MemoryStream()) { using (var bitmap = WebSnapshot.Create(url, size)) { bitmap.Save(stream, this.ImageFormat); } return stream.ToArray(); } } private IWebSnapshotSize GetSnapshotSize(HttpContext context) { var sizeMemberName = context.Request["size"]; if (sizeMemberName == null) return WebSnapshotSizes.Auto; var sizeMember = typeof(WebSnapshotSizes) .GetMembers() .Single(member => member.Name.Equals(sizeMemberName, StringComparison.InvariantCultureIgnoreCase)); var property = sizeMember as PropertyInfo; if (property != null) return (IWebSnapshotSize)property.GetValue(null, null); var method = (MethodInfo)sizeMember; var values = from parameter in method.GetParameters() let converter = TypeDescriptor.GetConverter(parameter.ParameterType) let stringValue = context.Request[parameter.Name] select converter.ConvertFromInvariantString(stringValue); return (IWebSnapshotSize)method.Invoke(null, values.ToArray()); } protected virtual ImageFormat ImageFormat { get { return ImageFormat.Png; } } protected virtual TimeSpan ExpiresIn { get { return TimeSpan.FromMinutes(10); } } public virtual bool IsReusable { get { return true; } } } }