public void CheckDescription() { // GET:pages/{pageid}/files/{filename}/description // http://developer.mindtouch.com/Deki/API_Reference/GET%3apages%2f%2f%7bpageid%7d%2f%2ffiles%2f%2f%7bfilename%7d%2f%2fdescription Plug p = Utils.BuildPlugForAdmin(); string id = null; DreamMessage msg = PageUtils.CreateRandomPage(p, out id); string description = "File description text"; string fileid = null; string filename = null; FileUtils.UploadRandomFile(p, id, null, description, out fileid, out filename); msg = p.At("pages", id, "files", "=" + filename, "description").Get(); Assert.AreEqual(DreamStatus.Ok, msg.Status); Assert.IsTrue(msg.AsText() == description); // GET:files/{fileid}/description // http://developer.mindtouch.com/Deki/API_Reference/GET%3afiles%2f%2f%7bfileid%7d%2f%2fdescription msg = p.At("files", fileid, "description").Get(); Assert.AreEqual(DreamStatus.Ok, msg.Status); Assert.IsTrue(msg.AsText() == description); PageUtils.DeletePageByID(p, id, true); }
public void PostPutDeleteSiteProperties() { Plug p = Utils.BuildPlugForAdmin(); string propertyContent = Utils.GetSmallRandomText(); string propertyName = Utils.GenerateUniqueName(); DreamMessage msg = null; try { msg = p.At("site", "properties").WithHeader("Slug", XUri.Encode(propertyName)).PostAsync(DreamMessage.Ok(MimeType.TEXT_UTF8, propertyContent)).Wait(); Assert.AreEqual(DreamStatus.Ok, msg.Status, "POST property got non 200"); Assert.AreEqual(msg.ToDocument()["/property/contents"].AsText, propertyContent, "Contents don't match!"); msg = p.At("site", "properties", propertyName).GetAsync().Wait(); Assert.AreEqual(DreamStatus.Ok, msg.Status, "GET property returned non 200"); Assert.AreEqual(propertyContent, msg.AsText(), "Contents don't match!"); propertyContent = Utils.GetSmallRandomText(); msg = p.At("site", "properties", propertyName).WithHeader(DreamHeaders.ETAG, msg.Headers.ETag).PutAsync(DreamMessage.Ok(MimeType.TEXT_UTF8, propertyContent)).Wait(); Assert.AreEqual(DreamStatus.Ok, msg.Status, "PUT property returned non 200"); msg = p.At("site", "properties", propertyName).GetAsync().Wait(); Assert.AreEqual(DreamStatus.Ok, msg.Status, "GET property returned non 200"); Assert.AreEqual(propertyContent, msg.AsText(), "Contents don't match on second rev!"); } finally { msg = p.At("site", "properties", propertyName).DeleteAsync().Wait(); Assert.AreEqual(DreamStatus.Ok, msg.Status, "Delete status non 200"); } msg = p.At("site", "properties", propertyName).GetAsync().Wait(); Assert.AreEqual(DreamStatus.NotFound, msg.Status, "Deleted property get status non 404"); }
public void ContentNewUser_PointsToInvalidPage_DefaultUserPageContents() { // Log in as ADMIN Plug p = Utils.BuildPlugForAdmin(); // Add content/new-user key to point to some bogus page SiteUtils.AddConfigKey(p, "content/new-user", Utils.GenerateUniqueName()); // Create a user string userid; string username; UserUtils.CreateRandomContributor(p, out userid, out username); // Retrieve user page contents DreamMessage msg = p.At("pages", "=" + XUri.DoubleEncode("User:"******"contents").Get(new Result <DreamMessage>()).Wait(); Assert.AreEqual(DreamStatus.Ok, msg.Status, "Failed to retrieve user page contents"); string content = msg.ToDocument()["body"].AsText ?? String.Empty; // Retrieve default new user page content from resources string resource = "MindTouch.Templates.userwelcome.visitor"; msg = p.At("site", "localization").With("resource", resource).Get(new Result <DreamMessage>()).Wait(); Assert.AreEqual(DreamStatus.Ok, msg.Status, "Unable to retrieve resource for string: " + resource); string expectedContent = "<p>" + msg.AsText() + "</p>" ?? String.Empty; Assert.AreEqual(expectedContent, content, "Unexpected contents"); }
public void GetComment() { // GET:pages/{pageid}/comments/{commentnumber}/content // http://developer.mindtouch.com/Deki/API_Reference/GET%3apages%2f%2f%7bpageid%7d%2f%2fcomments%2f%2f%7bcommentnumber%7d%2f%2fcontent Plug p = Utils.BuildPlugForAdmin(); string id = null; DreamMessage msg = PageUtils.CreateRandomPage(p, out id); string content = Utils.GetSmallRandomText(); DreamMessage postMsg = DreamMessage.Ok(MimeType.TEXT_UTF8, content); msg = p.At("pages", id, "comments").Post(postMsg); Assert.AreEqual(DreamStatus.Ok, msg.Status); string commentId = msg.ToDocument()["@id"].AsText; Assert.IsFalse(string.IsNullOrEmpty(commentId)); Assert.IsTrue(msg.ToDocument()["content"].AsText == content); msg = p.At("pages", id, "comments", "1", "content").Get(); Assert.AreEqual(DreamStatus.Ok, msg.Status); Assert.IsTrue(msg.AsText() == content); // GET:pages/{pageid}/comments/{commentnumber} // http://developer.mindtouch.com/Deki/API_Reference/GET%3apages%2f%2f%7bpageid%7d%2f%2fcomments%2f%2f%7bcommentnumber%7d msg = p.At("pages", id, "comments", "1").Get(); Assert.AreEqual(DreamStatus.Ok, msg.Status); Assert.IsTrue(msg.ToDocument()["@id"].AsText == commentId); Assert.IsTrue(msg.ToDocument()["content"].AsText == content); PageUtils.DeletePageByID(p, id, true); }
public void SaveGetPageProperty() { Plug p = Utils.BuildPlugForAdmin(); string id = null; string path = null; DreamMessage msg = PageUtils.CreateRandomPage(p, out id, out path); string content = Utils.GetSmallRandomText(); //NOTE: PUT: resource/{properties}/{key} is allowing property creation. Creating properties this way is undocumented and not recommended but was added for import/export //Test property creation via PUT //msg = p.At("pages", id, "properties", "foo").PutAsync(DreamMessage.Ok(MimeType.TEXT, content)).Wait(); //Assert.AreEqual(DreamStatus.Conflict, msg.Status); msg = p.At("pages", id, "properties").WithHeader("Slug", XUri.Encode("foo")).PostAsync(DreamMessage.Ok(MimeType.TEXT_UTF8, content)).Wait(); Assert.AreEqual(DreamStatus.Ok, msg.Status, "post properties returned non 200 status: " + msg.ToString()); //TODO: validate response XML for 200's msg = p.At("pages", id, "properties", "foo", "info").GetAsync().Wait(); Assert.AreEqual(DreamStatus.Ok, msg.Status, "get property returned non 200 status: " + msg.ToString()); Assert.AreEqual(content, msg.ToDocument()["/property[@name= 'foo']/contents"].AsText, "Contents don't match!"); XUri contentsUri = msg.ToDocument()["/property[@name = 'foo']/contents/@href"].AsUri; Assert.IsTrue(contentsUri != null, "Couldn't find content href"); Plug p2 = Plug.New(contentsUri).WithTimeout(p.Timeout).WithHeaders(p.Headers).WithCredentials(p.Credentials); msg = p2.GetAsync().Wait(); Assert.IsTrue(msg.Status == DreamStatus.Ok, "get property contents by uri didnt return status 200: " + msg.ToString()); Assert.IsTrue(msg.ContentType.Match(MimeType.TEXT), "get property content type didnt match: " + msg.ToString()); Assert.IsTrue(msg.AsText() == content, "get property content didnt match: " + msg.ToString()); }
public void PostBigDescription() { //Assumptions: //Actions: // create page // create big description // post file with big description to page //Expected result: // Ok Plug p = Utils.BuildPlugForAdmin(); string id = null; DreamMessage msg = PageUtils.CreateRandomPage(p, out id); try { string description = Utils.GetSmallRandomText();// Utils.GetSmallRandomText(); string fileid = null; string filename = null; msg = FileUtils.UploadRandomFile(p, id, null, description, out fileid, out filename); msg = p.At("pages", id, "files", "=" + filename, "description").Get(); Assert.AreEqual(DreamStatus.Ok, msg.Status); Assert.IsTrue(msg.AsText() == description); } catch (DreamResponseException) { Assert.Fail(); } PageUtils.DeletePageByID(p, id, true); }
public void PutFileProperties() { Plug p = Utils.BuildPlugForAdmin(); string id = null; string path = null; DreamMessage msg = PageUtils.CreateRandomPage(p, out id, out path); string propertyContent = Utils.GetSmallRandomText(); string propertyName = Utils.GenerateUniqueName(); string fileid = null; msg = FileUtils.UploadRandomFile(p, id, out fileid); msg = p.At("files", fileid, "properties").WithHeader("Slug", XUri.Encode(propertyName)).PostAsync(DreamMessage.Ok(MimeType.TEXT_UTF8, propertyContent)).Wait(); Assert.AreEqual(DreamStatus.Ok, msg.Status); Assert.AreEqual(msg.ToDocument()["/property/contents"].AsText, propertyContent, "Contents don't match!"); msg = p.At("files", fileid, "properties", propertyName).GetAsync().Wait(); Assert.AreEqual(DreamStatus.Ok, msg.Status, "Non 200 status on get:property content: " + msg.ToString()); Assert.AreEqual(propertyContent, msg.AsText(), "Contents don't match!"); PageUtils.DeletePageByID(p, id, true); }
public static CommentBE EditExistingComment(PageBE page, CommentBE comment, DreamMessage request, DreamContext context) { if (comment.PosterUserId != DekiContext.Current.User.ID) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); } ValidateCommentText(request.ContentType, request.AsText()); comment.LastEditDate = DateTime.UtcNow; comment.LastEditUserId = DekiContext.Current.User.ID; comment.Content = request.AsText(); comment.ContentMimeType = request.ContentType.ToString(); DbUtils.CurrentSession.Comments_Update(comment); PageBL.Touch(page, comment.LastEditDate.Value); RecentChangeBL.AddCommentUpdateRecentChange(comment.LastEditDate.Value, page, DekiContext.Current.User, DekiResources.COMMENT_EDITED(comment.Number), comment); return(comment); }
// TODO (brigettek): this feature currently always fails. Commenting out until we need/fix it. // [DreamFeature("POST:site/notifyadmin", "Notifies the site admin")]/ // [DreamFeatureParam("subject", "string", "Subject of the notice")] // [DreamFeatureStatus(DreamStatus.Ok, "The request completed successfully")] // [DreamFeatureStatus(DreamStatus.BadRequest, "Invalid input parameter or request body")] // [DreamFeatureStatus(DreamStatus.Forbidden, "User must be logged in")] public Yield PostSiteNotifyAdmin(DreamContext context, DreamMessage request, Result <DreamMessage> response) { if ((DekiContext.CurrentOrNull == null) || UserBL.IsAnonymous(DekiContext.Current.User)) { throw new SiteMustBeLoggedInForbiddenException(); } var siteBL = new SiteBL(); siteBL.SendNoticeToAdmin(context.GetParam("subject"), request.AsText(), request.ContentType); response.Return(DreamMessage.Ok()); yield break; }
public void UpdateDescriptionFromAnonymous() { //Assumptions: // //Actions: // create page // upload file to page // try to edit file description from anonymous account //Expected result: // Unauthorized Plug p = Utils.BuildPlugForAdmin(); string id = null; DreamMessage msg = PageUtils.CreateRandomPage(p, out id); string description = Utils.GetRandomText(220); string fileid = null; string filename = null; FileUtils.UploadRandomFile(p, id, null, description, out fileid, out filename); p = Utils.BuildPlugForAnonymous(); try { msg = DreamMessage.Ok(MimeType.TEXT_UTF8, Utils.GetRandomText(220)); msg = p.At("files", fileid, "description").Put(msg); Assert.IsTrue(false); } catch (DreamResponseException ex) { Assert.IsTrue(ex.Response.Status == DreamStatus.Unauthorized); } try { msg = DreamMessage.Ok(MimeType.TEXT_UTF8, Utils.GetRandomText(220)); msg = p.At("pages", id, "files", "=" + filename, "description").Put(msg); Assert.IsTrue(false); } catch (DreamResponseException ex) { Assert.IsTrue(ex.Response.Status == DreamStatus.Unauthorized); } msg = p.At("pages", id, "files", "=" + filename, "description").Get(); Assert.AreEqual(DreamStatus.Ok, msg.Status); Assert.IsTrue(msg.AsText() == description); p = Utils.BuildPlugForAdmin(); PageUtils.DeletePageByID(p, id, true); }
public Yield PutFileDescription(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PageBE parentPage; ResourceBE file = GetAttachment(context, request, Permissions.UPDATE, false, false, out parentPage); // determine if description needs to be set or cleared string description = StringUtil.EqualsInvariant(context.Verb, "PUT") ? request.AsText() : string.Empty; file = AttachmentBL.Instance.SetDescription(file, description); response.Return(DreamMessage.Ok(AttachmentBL.Instance.GetFileXml(file, true, null, null))); yield break; }
public static CommentBE PostNewComment(PageBE page, DreamMessage request, DreamContext context) { ValidateCommentText(request.ContentType, request.AsText()); CommentBE comment = new CommentBE(); comment.Title = context.GetParam("title", string.Empty); comment.PageId = page.ID; comment.Content = request.AsText(); comment.ContentMimeType = request.ContentType.ToString(); comment.PosterUserId = DekiContext.Current.User.ID; comment.CreateDate = DateTime.UtcNow; //Note (MaxM): Replytoid/replies not yet exposed //ulong replyToId = context.GetParam<ulong>("replyto", 0); //if (replyToId == 0) // newComment.ReplyToId = null; //else // newComment.ReplyToId = replyToId; ushort commentNumber; uint commentId = DbUtils.CurrentSession.Comments_Insert(comment, out commentNumber); if (commentId == 0) { return(null); } else { comment.Id = commentId; comment.Number = commentNumber; PageBL.Touch(page, comment.CreateDate); RecentChangeBL.AddCommentCreateRecentChange(comment.CreateDate, page, DekiContext.Current.User, DekiResources.COMMENT_ADDED(comment.Number), comment); return(comment); } }
public void PostUserProperties() { Plug p = Utils.BuildPlugForAdmin(); string id = null; DreamMessage msg = UserUtils.CreateRandomContributor(p, out id); string propertyContent = Utils.GetSmallRandomText(); string propertyName = Utils.GenerateUniqueName(); msg = p.At("users", id, "properties").WithHeader("Slug", XUri.Encode(propertyName)).PostAsync(DreamMessage.Ok(MimeType.TEXT_UTF8, propertyContent)).Wait(); Assert.AreEqual(DreamStatus.Ok, msg.Status); Assert.AreEqual(msg.ToDocument()["/property/contents"].AsText, propertyContent, "Contents don't match!"); msg = p.At("users", id, "properties", propertyName).GetAsync().Wait(); Assert.AreEqual(DreamStatus.Ok, msg.Status); Assert.AreEqual(propertyContent, msg.AsText(), "Contents don't match!"); }
public void Create_view_remove_subscription() { string id; string path; DreamMessage response = PageUtils.CreateRandomPage(_adminPlug, out id, out path); Assert.IsTrue(response.IsSuccessful); // let the page create event bubble through Thread.Sleep(1000); _log.DebugFormat("post single page subscription: {0}", id); response = _pageSub.At("pages", id).WithHeader("X-Deki-Site", "id=default").PostAsync().Wait(); Assert.IsTrue(response.IsSuccessful); _log.Debug("get subscription"); response = _pageSub.At("subscriptions").With("pages", id).WithHeader("X-Deki-Site", "id=default").GetAsync().Wait(); Assert.IsTrue(response.IsSuccessful); XDoc subscription = response.ToDocument()["subscription.page"]; Assert.AreEqual(1, subscription.ListLength); Assert.AreEqual("0", subscription["@depth"].AsText); _log.Debug("post page tree subscription"); response = _pageSub.At("pages", id).With("depth", "infinity").WithHeader("X-Deki-Site", "id=default").PostAsync().Wait(); Assert.IsTrue(response.IsSuccessful); _log.Debug("get subscription"); response = _pageSub.At("subscriptions").With("pages", id).WithHeader("X-Deki-Site", "id=default").GetAsync().Wait(); Assert.IsTrue(response.IsSuccessful); subscription = response.ToDocument()["subscription.page"]; Assert.AreEqual(1, subscription.ListLength); Assert.AreEqual("infinity", subscription["@depth"].AsText); _log.Debug("remove subscription"); response = _pageSub.At("pages", id).WithHeader("X-Deki-Site", "id=default").DeleteAsync().Wait(); Assert.IsTrue(response.IsSuccessful); _log.Debug("get subscription"); response = _pageSub.At("subscriptions").With("pages", id).WithHeader("X-Deki-Site", "id=default").GetAsync().Wait(); Assert.IsTrue(response.IsSuccessful); Assert.IsTrue(response.ToDocument()["subscription.page"].IsEmpty, response.AsText()); }
public void ContentNewUser_NoKey_DefaultUserPageContents() { // Log in as ADMIN Plug p = Utils.BuildPlugForAdmin(); // Remove content/new-user key SiteUtils.RemoveConfigKey(p, "content/new-user"); // Create a user string userid; string username; UserUtils.CreateRandomContributor(p, out userid, out username); // Retrieve a page id. This is to render the template using the "pageid" parameter in the page/{pageid}/contents feature. DreamMessage msg = PageUtils.GetPage(p, String.Empty); Assert.AreEqual(DreamStatus.Ok, msg.Status, "Failed to retrieve home page"); uint homepageid = msg.ToDocument()["@id"].AsUInt ?? 0; Assert.IsTrue(homepageid > 0, "Invalid homepage ID"); // Retrieve user page contents msg = p.At("pages", "=" + XUri.DoubleEncode("User:"******"contents").With("pageid", homepageid).Get(new Result <DreamMessage>()).Wait(); Assert.AreEqual(DreamStatus.Ok, msg.Status, "Failed to retrieve user page contents"); string content = msg.ToDocument()["body"].AsText ?? String.Empty; // Retrieve default new user page content from resources string resource = "MindTouch.Templates.userwelcome.visitor"; msg = p.At("site", "localization").With("resource", resource).Get(new Result <DreamMessage>()).Wait(); Assert.AreEqual(DreamStatus.Ok, msg.Status, "Unable to retrieve resource for string: " + resource); string expectedContent = "<p>" + msg.AsText() + "</p>" ?? String.Empty; Assert.AreEqual(expectedContent, content, "Unexpected contents"); }
public Yield PutPasswordChange(DreamContext context, DreamMessage request, Result <DreamMessage> response) { UserBE targetUser = GetUserFromUrlMustExist(); string password = request.AsText(); if (string.IsNullOrEmpty(password)) { throw new UserNewPasswordNotProvidedInvalidArgumentException(); } if (password.Length < 4) { throw new UserNewPasswordTooShortInvalidArgumentException(); } // Ensure that the password is being set only on local accounts ServiceBE s = ServiceBL.GetServiceById(targetUser.ServiceId); if (s != null && !ServiceBL.IsLocalAuthService(s)) { throw new UserCanOnlyChangeLocalUserPasswordInvalidOperationException(); } if (UserBL.IsAnonymous(targetUser)) { throw new UserCannotChangeAnonPasswordInvalidOperationException(); } // Admins can always change anyones password. if (PermissionsBL.IsUserAllowed(DekiContext.Current.User, Permissions.ADMIN)) { //For admins a currentpassword is option but if given then it should be validated string currentPwd = context.GetParam("currentpassword", string.Empty); if (!string.IsNullOrEmpty(currentPwd)) { if (!AuthBL.IsValidAuthenticationForLocalUser(targetUser, currentPwd)) { throw new UserCurrentPasswordIncorrectForbiddenException(); } } } else if (DekiContext.Current.User.ID == targetUser.ID) { if (context.GetParam("altpassword", false)) { throw new UserCannotChangeOwnAltPasswordInvalidOperationException(); } // User changing their own password requires knowledge of their current password string currentPwd = context.GetParam("currentpassword"); if (!AuthBL.IsValidAuthenticationForLocalUser(DekiContext.Current.User, currentPwd)) { throw new UserCurrentPasswordIncorrectForbiddenException(); } } else { throw new UserMustBeTargetOrAdminForbiddenException(); } bool altPassword = context.GetParam <bool>("altpassword", false); targetUser = UserBL.SetPassword(targetUser, password, altPassword); if (DekiContext.Current.User.ID == targetUser.ID) { response.Return(BuildSetAuthTokenResponse(AuthBL.CreateAuthTokenForUser(targetUser), null)); } else { response.Return(DreamMessage.Ok()); } yield break; }
//--- Methods --- internal bool RunTest(Plug converter) { foreach (KeyValuePair <string, string> setting in Settings) { converter = converter.With(setting.Key, setting.Value); } DreamMessage message = converter.With("text", Test).PostQuery(); string result = message.AsText(); string[] received = result.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None); XDoc converted = XDocFactory.From(result, MimeType.HTML); Site site = new Site(); string lang; if (Settings.TryGetValue("lang", out lang)) { site.Language = lang; } string title; if (!Settings.TryGetValue("title", out title)) { title = "None"; } WikiTextProcessor.Convert(site, converted, StringUtil.StartsWithInvariantIgnoreCase(title, "Template:")); string[] actual = converted.ToPrettyString().Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None); bool success = true; if (actual.Length == Expected.Length) { for (int i = 0; i < Expected.Length; ++i) { if (actual[i] != Expected[i]) { success = false; break; } } } else { success = false; } if (!success) { string bug; if (Settings.TryGetValue("bug", out bug)) { Console.WriteLine("Line {0}, Bug# {1}", Line, bug); } else { Console.WriteLine("Line {0}", Line); } Console.WriteLine(); Console.WriteLine("Sent"); Console.WriteLine("----"); Console.WriteLine(Test); Console.WriteLine(); Console.WriteLine("Received"); Console.WriteLine("--------"); foreach (string line in received) { Console.WriteLine(line); } Console.WriteLine(); Console.WriteLine("Converted"); Console.WriteLine("---------"); Console.WriteLine(converted.ToPrettyString()); Console.WriteLine(); Console.WriteLine("Expected"); Console.WriteLine("--------"); foreach (string line in Expected) { Console.WriteLine(line); } Console.WriteLine(); Console.WriteLine("========================================"); return(false); } return(true); }
private Yield EpilogueStats(DreamContext context, DreamMessage request, Result <DreamMessage> response) { // check if we need to skip this feature if (context.Feature.PathSegments.Length > 1 && context.Feature.PathSegments[context.Feature.ServiceUri.Segments.Length].StartsWith("@")) { response.Return(request); yield break; } // check if the epilogue was called without a deki instance (e.g. during initialization or with an invalid hostname) if (DekiContext.CurrentOrNull == null || !DekiContext.Current.HasInstance) { response.Return(request); yield break; } // compute execution time TimeSpan executionTime = TimeSpan.Zero; System.Diagnostics.Stopwatch elapsedTimeSw = context.GetState <System.Diagnostics.Stopwatch>("stats-stopwatch"); if (elapsedTimeSw != null) { elapsedTimeSw.Stop(); executionTime = TimeSpan.FromMilliseconds(elapsedTimeSw.ElapsedMilliseconds); } // increate instance hit counter DekiContext.Current.Instance.IncreasetHitCounter(request.IsSuccessful, executionTime); // if logging is enabled, grab the response text if the request was not successful string exception = string.Empty; XDoc activeConfig = DekiContext.Current.Instance.Config ?? Config; bool loggingEnabled = !String.IsNullOrEmpty(activeConfig["dblogging-conn-string"].AsText); if (loggingEnabled) { if (!request.IsSuccessful) { exception = request.AsText(); } } //Build overall request stats header StringBuilder statsHeaderSb = new StringBuilder(); statsHeaderSb.AppendFormat("{0}={1}; ", "request-time-ms", (int)executionTime.TotalMilliseconds); //Append data stats IDekiDataStats sessionStats = DbUtils.CurrentSession as IDekiDataStats; Dictionary <string, string> stats; if (sessionStats != null) { stats = sessionStats.GetStats(); if (stats != null) { foreach (KeyValuePair <string, string> kvp in stats) { statsHeaderSb.AppendFormat("{0}={1}; ", kvp.Key, kvp.Value); } } } //Append context stats stats = DekiContext.Current.Stats; if (stats.Count > 0) { foreach (KeyValuePair <string, string> kvp in stats) { statsHeaderSb.AppendFormat("{0}={1}; ", kvp.Key, kvp.Value); } } string requestStats = statsHeaderSb.ToString(); request.Headers.Add(DATA_STATS_HEADERNAME, requestStats); DekiContext.Current.Instance.Log.InfoFormat("Finished [{0}:{1}] [{2}] {3}", context.Verb, context.Uri.Path, request.Status.ToString(), requestStats); // check if there is a catalog to record per-request information if (loggingEnabled) { try { //Write request/response info to stats table after sending response back to client UserBE u = DekiContext.Current.User; string username = u == null ? string.Empty : u.Name; DbUtils.CurrentSession.RequestLog_Insert(context.Uri, context.Verb, DekiContext.Current.RequestHost, context.Request.Headers.DreamOrigin, DekiContext.Current.Instance.Id, context.Feature.Signature, request.Status, username, (uint)executionTime.TotalMilliseconds, exception); } catch (Exception x) { DekiContext.Current.Instance.Log.Error(string.Format("Failed to write request to db log. [Instance:{0}; Feature:{1}; Verb:{2}; Status:{3}; Duration:{4};]", DekiContext.Current.Instance.Id, context.Feature.Signature, context.Verb, (int)request.Status, executionTime), x); } } // continue processing response.Return(request); yield break; }