PageRenderTime 25ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/ssds/Provisioning/Authority.cs

http://mikeamundsen.googlecode.com/
C# | 260 lines | 188 code | 32 blank | 40 comment | 26 complexity | d119bd68f1be62cad8748cef2dd9be20 MD5 | raw file
  1. using System;
  2. using System.Web;
  3. using System.Net;
  4. using System.IO;
  5. using System.Globalization;
  6. using Amundsen.Utilities;
  7. namespace Amundsen.SSDS.Provisioning
  8. {
  9. /// <summary>
  10. /// Public Domain 2008 amundsen.com, inc.
  11. /// @author mike amundsen (mamund@yahoo.com)
  12. /// @version 1.5 (2008-09-08)
  13. /// @version 1.4 (2008-08-05)
  14. /// @version 1.3 (2008-07-20)
  15. /// @version 1.2 (2008-07-13)
  16. /// @version 1.1 (2008-07-09)
  17. /// @version 1.0 (2008-07-03)
  18. /// </summary>
  19. class Authority : IHttpHandler
  20. {
  21. private WebUtility wu;
  22. private HttpClient client;
  23. private HttpContext ctx;
  24. private CacheService cs;
  25. string ssdsUser = string.Empty;
  26. string ssdsPassword = string.Empty;
  27. bool showExpires = false;
  28. int maxAge = 60;
  29. string msft_request = string.Empty;
  30. bool IHttpHandler.IsReusable
  31. {
  32. get { return false; }
  33. }
  34. void IHttpHandler.ProcessRequest(HttpContext context)
  35. {
  36. ctx = context;
  37. client = new HttpClient();
  38. wu = new WebUtility();
  39. cs = new CacheService();
  40. // process request
  41. try
  42. {
  43. string rtn = wu.ConfirmXmlMediaType(ctx.Request.AcceptTypes,Constants.SsdsType);
  44. if (rtn.Length == 0)
  45. {
  46. Options();
  47. throw new HttpException((int)HttpStatusCode.NotAcceptable, HttpStatusCode.NotAcceptable.ToString());
  48. }
  49. wu.GetBasicAuthCredentials(ctx, ref ssdsUser, ref ssdsPassword);
  50. client.Credentials = new NetworkCredential(ssdsUser, ssdsPassword);
  51. wu.SetCompression(ctx);
  52. // process request
  53. switch (ctx.Request.HttpMethod.ToLower(CultureInfo.CurrentCulture))
  54. {
  55. case "get":
  56. Get();
  57. break;
  58. case "head":
  59. Get(true);
  60. break;
  61. case "post":
  62. Post();
  63. break;
  64. case "options":
  65. Options();
  66. break;
  67. default:
  68. Options();
  69. throw new HttpException((int)HttpStatusCode.MethodNotAllowed, HttpStatusCode.MethodNotAllowed.ToString());
  70. }
  71. }
  72. catch (HttpException hex)
  73. {
  74. ctx.Response.ContentType = "text/xml";
  75. ctx.Response.Write(string.Format(CultureInfo.CurrentCulture, Constants.ErrorFormat, hex.GetHttpCode(), hex.Message, Constants.SitkaNS));
  76. ctx.Response.Write(" ".PadRight(500));
  77. ctx.Response.StatusCode = hex.GetHttpCode();
  78. ctx.Response.StatusDescription = hex.Message;
  79. }
  80. catch (Exception ex)
  81. {
  82. ctx.Response.ContentType = "text/xml";
  83. ctx.Response.Write(string.Format(CultureInfo.CurrentCulture, Constants.ErrorFormat, 500, ex.Message, Constants.SitkaNS));
  84. ctx.Response.Write(" ".PadRight(500));
  85. ctx.Response.StatusCode = 500;
  86. ctx.Response.StatusDescription = ex.Message;
  87. }
  88. }
  89. // reflect valid methods and mimetypes to client
  90. private void Options()
  91. {
  92. ctx.Response.AppendHeader("Allow", "GET,HEAD,POST,OPTIONS");
  93. ctx.Response.AppendHeader("X-Acceptable", "application/x-ssds+xml,application/xml,text/xml");
  94. }
  95. // get metadata for requested authority
  96. private void Get()
  97. {
  98. Get(false);
  99. }
  100. private void Get(bool supressContent)
  101. {
  102. string rtn = string.Empty;
  103. string authority = string.Empty;
  104. CacheItem item = null;
  105. string request_url = ctx.Request.Url.ToString();
  106. // get authority from query string
  107. authority = (ctx.Request.QueryString["authority"] != null ? ctx.Request.QueryString["authority"] : string.Empty);
  108. /*
  109. if (authority.Length==0)
  110. {
  111. throw new HttpException(400, "Missing Authority ID");
  112. }
  113. */
  114. string ifNoneMatch = wu.GetHeader(ctx, "if-none-match");
  115. // check local cache first (if allowed)
  116. if (wu.CheckNoCache(ctx) == true)
  117. {
  118. ifNoneMatch = string.Empty;
  119. cs.RemoveItem(request_url);
  120. }
  121. else
  122. {
  123. item = cs.GetItem(request_url);
  124. }
  125. // did our copy expire?
  126. if (item != null && (item.Expires < DateTime.UtcNow))
  127. {
  128. cs.RemoveItem(request_url);
  129. item = null;
  130. }
  131. // get a new copy, if needed
  132. string url = string.Empty;
  133. if (item == null)
  134. {
  135. if(authority.Length!=0)
  136. {
  137. url = string.Format(CultureInfo.CurrentCulture, "https://{0}.{1}", authority, Constants.SsdsRoot);
  138. }
  139. else
  140. {
  141. url = string.Format(CultureInfo.CurrentCulture,"https://{0}?q=",Constants.SsdsRoot);
  142. }
  143. // make call to remote server
  144. rtn = client.Execute(url, "get", Constants.SsdsType);
  145. msft_request = (client.ResponseHeaders[Constants.MsftRequestId] != null ? client.ResponseHeaders[Constants.MsftRequestId] : string.Empty);
  146. // fill local cache
  147. item = cs.PutItem(
  148. new CacheItem(
  149. request_url,
  150. rtn,
  151. string.Format(CultureInfo.CurrentCulture, "\"{0}\"", cs.MD5BinHex(rtn)),
  152. DateTime.UtcNow.AddSeconds(maxAge),
  153. showExpires
  154. )
  155. );
  156. }
  157. // if client has same copy, just send 304
  158. if (ifNoneMatch == item.ETag)
  159. {
  160. throw new HttpException((int)HttpStatusCode.NotModified, HttpStatusCode.NotModified.ToString());
  161. }
  162. // compose response to client
  163. ctx.Response.SuppressContent = supressContent;
  164. ctx.Response.StatusCode = 200;
  165. ctx.Response.ContentType = "text/xml";
  166. ctx.Response.StatusDescription = "OK";
  167. ctx.Response.Write(item.Payload);
  168. // add msft_header, if present
  169. if (msft_request.Length != 0)
  170. {
  171. ctx.Response.AppendToLog(string.Format(" [{0}={1}]", Constants.MsftRequestId, msft_request));
  172. ctx.Response.AddHeader(Constants.MsftRequestId, msft_request);
  173. }
  174. // validation caching
  175. ctx.Response.AddHeader("etag", item.ETag);
  176. ctx.Response.AppendHeader("Last-Modified", string.Format(CultureInfo.CurrentCulture, "{0:R}", item.LastModified));
  177. // expiration caching
  178. if (showExpires)
  179. {
  180. ctx.Response.AppendHeader("Expires", string.Format(CultureInfo.CurrentCulture, "{0:R}", item.Expires));
  181. ctx.Response.AppendHeader("cache-control", string.Format(CultureInfo.CurrentCulture, "max-age={0}", maxAge));
  182. }
  183. // ie local caching hack
  184. if (ctx.Request.UserAgent != null && ctx.Request.UserAgent.IndexOf("IE", StringComparison.CurrentCultureIgnoreCase) != -1)
  185. {
  186. ctx.Response.AppendHeader("cache-control", "post-check=1,pre-check=2");
  187. }
  188. }
  189. // create a new authority
  190. private void Post()
  191. {
  192. string rtn = string.Empty;
  193. string body = string.Empty;
  194. string authority = string.Empty;
  195. string url = string.Empty;
  196. string data = string.Empty;
  197. // hack to support isap rewrite utility
  198. // added to support proper returning location header in response
  199. string request_url = (ctx.Request.Headers["X-Rewrite-URL"] != null ? ctx.Request.Headers["X-Rewrite-URL"] : ctx.Request.Url.ToString());
  200. // get body
  201. using (StreamReader sr = new StreamReader(ctx.Request.InputStream, ctx.Request.ContentEncoding))
  202. {
  203. body = sr.ReadToEnd();
  204. sr.Close();
  205. }
  206. authority = body.ToLower(CultureInfo.CurrentCulture).Replace("<authority>", string.Empty).Replace("</authority>", string.Empty);
  207. // handle post to ssds
  208. data = string.Format(CultureInfo.CurrentCulture, Constants.AuthorityFormat, authority, Constants.SitkaNS);
  209. url = string.Format(CultureInfo.CurrentCulture, "https://{0}", Constants.SsdsRoot);
  210. rtn = client.Execute(url, "post", Constants.SsdsType, data);
  211. msft_request = (client.ResponseHeaders[Constants.MsftRequestId] != null ? client.ResponseHeaders[Constants.MsftRequestId] : string.Empty);
  212. // remove related local cache items
  213. cs.RemoveItem(ctx.Request.Url.ToString());
  214. // add msft_header, if present
  215. if (msft_request.Length != 0)
  216. {
  217. ctx.Response.AppendToLog(string.Format(" [{0}={1}]", Constants.MsftRequestId, msft_request));
  218. ctx.Response.AddHeader(Constants.MsftRequestId, msft_request);
  219. }
  220. // compose response to client
  221. ctx.Response.StatusCode = 201;
  222. ctx.Response.ContentType = "text/xml";
  223. ctx.Response.StatusDescription = "Authority has been created.";
  224. ctx.Response.RedirectLocation = string.Format("{0}{1}", request_url, authority);
  225. ctx.Response.Write(rtn);
  226. }
  227. }
  228. }