Added the XrdsPublisher ASP.NET control.
[dotnetoauth.git] / src / DotNetOpenAuth / XrdsPublisher.cs
blob142e5b476ce6041b521a671d8b6eb0d5011a2175
1 //-----------------------------------------------------------------------
2 // <copyright file="XrdsPublisher.cs" company="Andrew Arnott">
3 // Copyright (c) Andrew Arnott. All rights reserved.
4 // </copyright>
5 //-----------------------------------------------------------------------
7 namespace DotNetOpenAuth {
8 using System;
9 using System.Collections.Generic;
10 using System.ComponentModel;
11 using System.Diagnostics.CodeAnalysis;
12 using System.Text;
13 using System.Web;
14 using System.Web.UI;
15 using System.Web.UI.WebControls;
16 using DotNetOpenAuth.Messaging;
17 using DotNetOpenAuth.Yadis;
19 /// <summary>
20 /// The locations the YADIS protocol describes can contain a reference
21 /// to an XRDS document.
22 /// </summary>
23 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Xrds", Justification = "Correct spelling")]
24 [Flags]
25 public enum XrdsUrlLocations {
26 /// <summary>
27 /// Indicates XRDS document referencing from an HTTP protocol header (outside the HTML).
28 /// </summary>
29 HttpHeader = 0x1,
31 /// <summary>
32 /// Indicates XRDS document referencing from within an HTML page's &lt;HEAD&gt; tag.
33 /// </summary>
34 HtmlMeta = 0x2,
36 /// <summary>
37 /// Indicates XRDS document referencing in both HTTP headers and HTML HEAD tags.
38 /// </summary>
39 Both = 0x3,
42 /// <summary>
43 /// An ASP.NET control that advertises an XRDS document and even responds to specially
44 /// crafted requests to retrieve it.
45 /// </summary>
46 [DefaultProperty("XrdsLocation")]
47 [ToolboxData("<{0}:XrdsPublisher runat=server></{0}:XrdsPublisher>")]
48 public class XrdsPublisher : Control {
49 /// <summary>
50 /// The view state key to ues for storing the value of the <see cref="XrdsUrl"/> property.
51 /// </summary>
52 private const string XrdsUrlViewStateKey = "XrdsUrl";
54 /// <summary>
55 /// The default value for the <see cref="XrdsAdvertisement"/> property.
56 /// </summary>
57 private const XrdsUrlLocations XrdsAdvertisementDefault = XrdsUrlLocations.HttpHeader;
59 /// <summary>
60 /// The view state key to ues for storing the value of the <see cref="XrdsAdvertisement"/> property.
61 /// </summary>
62 private const string XrdsAdvertisementViewStateKey = "XrdsAdvertisement";
64 /// <summary>
65 /// The default value for the <see cref="XrdsAutoAnswer"/> property.
66 /// </summary>
67 private const bool XrdsAutoAnswerDefault = true;
69 /// <summary>
70 /// The view state key to ues for storing the value of the <see cref="XrdsAutoAnswer"/> property.
71 /// </summary>
72 private const string XrdsAutoAnswerViewStateKey = "XrdsAutoAnswer";
74 /// <summary>
75 /// The default value for the <see cref="Enabled"/> property.
76 /// </summary>
77 private const bool EnabledDefault = true;
79 /// <summary>
80 /// The view state key to ues for storing the value of the <see cref="Enabled"/> property.
81 /// </summary>
82 private const string EnabledViewStateKey = "Enabled";
84 #region Properties
86 /// <summary>
87 /// Gets or sets the location of the XRDS document.
88 /// </summary>
89 [SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings", Justification = "Property grid")]
90 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Xrds", Justification = "Correct spelling")]
91 [Category("Behavior"), Bindable(true)]
92 public string XrdsUrl {
93 get {
94 return (string)ViewState[XrdsUrlViewStateKey];
97 set {
98 UriUtil.ValidateResolvableUrl(Page, DesignMode, value);
99 ViewState[XrdsUrlViewStateKey] = value;
103 /// <summary>
104 /// Gets or sets where the XRDS document URL is advertised in the web response.
105 /// </summary>
106 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Xrds", Justification = "Correct spelling")]
107 [Category("Behavior"), DefaultValue(XrdsAdvertisementDefault), Bindable(true)]
108 [Description("Where the XRDS document URL is advertised in the web response.")]
109 public XrdsUrlLocations XrdsAdvertisement {
110 get {
111 return ViewState[XrdsAdvertisementViewStateKey] == null ?
112 XrdsAdvertisementDefault : (XrdsUrlLocations)ViewState[XrdsAdvertisementViewStateKey];
115 set {
116 ViewState[XrdsAdvertisementViewStateKey] = value;
120 /// <summary>
121 /// Gets or sets a value indicating whether a specially crafted YADIS
122 /// search for an XRDS document is immediately answered by this control.
123 /// </summary>
124 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Xrds", Justification = "Correct spelling")]
125 [Category("Behavior"), DefaultValue(XrdsAutoAnswerDefault), Bindable(true)]
126 [Description("Whether XRDS requests should be immediately answered with the XRDS document if it is served by this web application.")]
127 public bool XrdsAutoAnswer {
128 get {
129 return ViewState[XrdsAutoAnswerViewStateKey] == null ?
130 XrdsAutoAnswerDefault : (bool)ViewState[XrdsAutoAnswerViewStateKey];
133 set {
134 ViewState[XrdsAutoAnswerViewStateKey] = value;
138 /// <summary>
139 /// Gets or sets a value indicating whether the XRDS document is advertised.
140 /// </summary>
141 [Category("Behavior"), DefaultValue(EnabledDefault)]
142 public bool Enabled {
143 get {
144 return ViewState[EnabledViewStateKey] == null ?
145 EnabledDefault : (bool)ViewState[EnabledViewStateKey];
148 set {
149 ViewState[EnabledViewStateKey] = value;
153 #endregion
155 /// <summary>
156 /// Detects YADIS requests for the XRDS document and responds immediately
157 /// if <see cref="XrdsAutoAnswer"/> is true.
158 /// </summary>
159 /// <param name="e">The <see cref="T:System.EventArgs"/> object that contains the event data.</param>
160 protected override void OnLoad(EventArgs e) {
161 base.OnLoad(e);
163 if (!this.Enabled) {
164 return;
167 if (!this.Page.IsPostBack) {
168 if (this.XrdsAutoAnswer && !string.IsNullOrEmpty(this.XrdsUrl) &&
169 this.XrdsUrl.StartsWith("~/", StringComparison.Ordinal)) {
170 // Check for the presence of an accept types header that is looking
171 // for the XRDS document specifically.
172 if (this.Page.Request.AcceptTypes != null && Array.IndexOf(this.Page.Request.AcceptTypes, ContentTypes.Xrds) >= 0) {
173 // Respond to the caller immediately with an XRDS document
174 // and avoid sending the whole web page's contents to the
175 // client since it isn't interested anyway.
176 // We do NOT simply send a 301 redirect here because that would
177 // alter the Claimed Identifier.
178 this.Page.Server.Transfer(this.XrdsUrl);
184 /// <summary>
185 /// Renders the HTTP Header and/or HTML HEAD tags.
186 /// </summary>
187 /// <param name="writer">The <see cref="T:System.Web.UI.HtmlTextWriter"/> object that receives the server control content.</param>
188 protected override void Render(HtmlTextWriter writer) {
189 if (this.Enabled && this.Visible && !string.IsNullOrEmpty(this.XrdsUrl)) {
190 Uri xrdsAddress = new Uri(MessagingUtilities.GetRequestUrlFromContext(), Page.Response.ApplyAppPathModifier(this.XrdsUrl));
191 if ((this.XrdsAdvertisement & XrdsUrlLocations.HttpHeader) != 0) {
192 Page.Response.AddHeader(Yadis.Yadis.HeaderName, xrdsAddress.AbsoluteUri);
194 if ((this.XrdsAdvertisement & XrdsUrlLocations.HtmlMeta) != 0) {
195 writer.WriteBeginTag("meta");
196 writer.WriteAttribute("http-equiv", Yadis.Yadis.HeaderName);
197 writer.WriteAttribute("content", xrdsAddress.AbsoluteUri);
198 writer.Write("/>");
199 writer.WriteLine();