/BlogEngine/DotNetSlave.BusinessLogic/Web/HttpHandlers/TrackbackHandler.cs
C# | 301 lines | 170 code | 38 blank | 93 comment | 29 complexity | a4f8d2bc95a604efee99a9988f2676d9 MD5 | raw file
Possible License(s): LGPL-2.1, Apache-2.0, BSD-3-Clause
- namespace BlogEngine.Core.Web.HttpHandlers
- {
- using System;
- using System.ComponentModel;
- using System.Linq;
- using System.Net;
- using System.Text.RegularExpressions;
- using System.Web;
-
- /// <summary>
- /// Trackback Handler
- /// </summary>
- public class TrackbackHandler : IHttpHandler
- {
- #region Constants and Fields
-
- /// <summary>
- /// The HTML Regex.
- /// </summary>
- private static readonly Regex RegexHtml =
- new Regex(
- @"</?\w+((\s+\w+(\s*=\s*(?:"".*?""|'.*?'|[^'"">\s]+))?)+\s*|\s*)/?>",
- RegexOptions.Singleline | RegexOptions.Compiled);
-
- /// <summary>
- /// Whether the source has link.
- /// </summary>
- private bool sourceHasLink;
-
- #endregion
-
- #region Events
-
- /// <summary>
- /// Occurs when a trackback is accepted as valid and added as a comment.
- /// </summary>
- public static event EventHandler<EventArgs> Accepted;
-
- /// <summary>
- /// Occurs when a hit is made to the trackback.axd handler.
- /// </summary>
- public static event EventHandler<CancelEventArgs> Received;
-
- /// <summary>
- /// Occurs when a trackback request is rejected because the sending
- /// website already made a trackback or pingback to the specific page.
- /// </summary>
- public static event EventHandler<EventArgs> Rejected;
-
- /// <summary>
- /// Occurs when the request comes from a spammer.
- /// </summary>
- public static event EventHandler<EventArgs> Spammed;
-
- #endregion
-
- #region Properties
-
- /// <summary>
- /// Gets a value indicating whether another request can use the <see cref = "T:System.Web.IHttpHandler"></see> instance.
- /// </summary>
- /// <value></value>
- /// <returns>true if the <see cref = "T:System.Web.IHttpHandler"></see> instance is reusable; otherwise, false.</returns>
- public bool IsReusable
- {
- get
- {
- return true;
- }
- }
-
- #endregion
-
- #region Public Methods
-
- /// <summary>
- /// Called when [spammed].
- /// </summary>
- /// <param name="url">The URL string.</param>
- public static void OnSpammed(string url)
- {
- if (Spammed != null)
- {
- Spammed(url, EventArgs.Empty);
- }
- }
-
- #endregion
-
- #region Implemented Interfaces
-
- #region IHttpHandler
-
- /// <summary>
- /// Enables processing of HTTP Web requests by a custom HttpHandler that
- /// implements the <see cref="T:System.Web.IHttpHandler"></see> interface.
- /// </summary>
- /// <param name="context">
- /// An <see cref="T:System.Web.HttpContext"></see>
- /// object that provides references to the intrinsic server objects
- /// (for example, Request, Response, Session, and Server) used to service HTTP requests.
- /// </param>
- public void ProcessRequest(HttpContext context)
- {
- if (!BlogSettings.Instance.IsCommentsEnabled || !BlogSettings.Instance.EnableTrackBackReceive)
- {
- context.Response.StatusCode = 404;
- context.Response.End();
- }
-
- var e = new CancelEventArgs();
- this.OnReceived(e);
- if (e.Cancel)
- {
- return;
- }
-
- var postId = context.Request.Params["id"];
-
- var title = context.Request.Params["title"];
- var excerpt = context.Request.Params["excerpt"];
- var blogName = context.Request.Params["blog_name"];
- var url = string.Empty;
-
- if (context.Request.Params["url"] != null)
- {
- url = context.Request.Params["url"].Split(',')[0];
- }
-
- Post post;
-
- if (!string.IsNullOrEmpty(title) && !string.IsNullOrEmpty(postId) && !string.IsNullOrEmpty(blogName) &&
- postId.Length == 36)
- {
- post = Post.GetPost(new Guid(postId));
- this.ExamineSourcePage(url, post.AbsoluteLink.ToString());
- var containsHtml = !string.IsNullOrEmpty(excerpt) &&
- (RegexHtml.IsMatch(excerpt) || RegexHtml.IsMatch(title) ||
- RegexHtml.IsMatch(blogName));
-
- if (IsFirstPingBack(post, url) && this.sourceHasLink && !containsHtml)
- {
- AddComment(url, post, blogName, title, excerpt);
- this.OnAccepted(url);
- context.Response.Write(
- "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?><response><error>0</error></response>");
- context.Response.End();
- }
- else if (!IsFirstPingBack(post, url))
- {
- this.OnRejected(url);
- context.Response.Write(
- "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?><response><error>Trackback already registered</error></response>");
- context.Response.End();
- }
- else if (!this.sourceHasLink || containsHtml)
- {
- OnSpammed(url);
- context.Response.Write(
- "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?><response><error>The source page does not link</error></response>");
- context.Response.End();
- }
- }
- else
- {
- context.Response.Redirect(Utils.RelativeWebRoot);
- }
- }
-
- #endregion
-
- #endregion
-
- #region Methods
-
- /// <summary>
- /// Called when [accepted].
- /// </summary>
- /// <param name="url">The URL string.</param>
- protected virtual void OnAccepted(string url)
- {
- if (Accepted != null)
- {
- Accepted(url, EventArgs.Empty);
- }
- }
-
- /// <summary>
- /// Raises the <see cref="Received"/> event.
- /// </summary>
- /// <param name="e">The <see cref="System.ComponentModel.CancelEventArgs"/> instance containing the event data.</param>
- protected virtual void OnReceived(CancelEventArgs e)
- {
- if (Received != null)
- {
- Received(null, e);
- }
- }
-
- /// <summary>
- /// Called when [rejected].
- /// </summary>
- /// <param name="url">The URL string.</param>
- protected virtual void OnRejected(string url)
- {
- if (Rejected != null)
- {
- Rejected(url, EventArgs.Empty);
- }
- }
-
- /// <summary>
- /// Insert the pingback as a comment on the post.
- /// </summary>
- /// <param name="sourceUrl">
- /// The source Url.
- /// </param>
- /// <param name="post">
- /// The post to comment on.
- /// </param>
- /// <param name="blogName">
- /// The blog Name.
- /// </param>
- /// <param name="title">
- /// The title.
- /// </param>
- /// <param name="excerpt">
- /// The excerpt.
- /// </param>
- private static void AddComment(string sourceUrl, Post post, string blogName, string title, string excerpt)
- {
- var comment = new Comment
- {
- Id = Guid.NewGuid(),
- Author = blogName,
- Website = new Uri(sourceUrl),
- Content = title + Environment.NewLine + Environment.NewLine + excerpt,
- Email = "trackback",
- Parent = post,
- DateCreated = DateTime.Now,
- IP = HttpContext.Current.Request.UserHostAddress,
- IsApproved = true
- };
- post.AddComment(comment);
- }
-
- /// <summary>
- /// Checks to see if the source has already pinged the target.
- /// If it has, there is no reason to add it again.
- /// </summary>
- /// <param name="post">
- /// The post to check.
- /// </param>
- /// <param name="sourceUrl">
- /// The source Url.
- /// </param>
- /// <returns>
- /// Whether is first ping back.
- /// </returns>
- private static bool IsFirstPingBack(Post post, string sourceUrl)
- {
- return
- !post.Comments.Any(
- comment =>
- comment.Website != null &&
- comment.Website.ToString().Equals(sourceUrl, StringComparison.OrdinalIgnoreCase)) &&
- !post.Comments.Any(
- comment =>
- comment.IP != null &&
- comment.IP == HttpContext.Current.Request.UserHostAddress);
- }
-
- /// <summary>
- /// Parse the HTML of the source page.
- /// </summary>
- /// <param name="sourceUrl">
- /// The source Url.
- /// </param>
- /// <param name="targetUrl">
- /// The target Url.
- /// </param>
- private void ExamineSourcePage(string sourceUrl, string targetUrl)
- {
- try
- {
- var remoteFile = new RemoteFile(new Uri(sourceUrl), true);
- var html = remoteFile.GetFileAsString();
- this.sourceHasLink = html.ToUpperInvariant().Contains(targetUrl.ToUpperInvariant());
-
- }
- catch (WebException)
- {
- this.sourceHasLink = false;
-
- // throw new ArgumentException("Trackback sender does not exists: " + sourceUrl, ex);
- }
- }
-
- #endregion
- }
- }