public Yield GetPageRating(DreamContext context, DreamMessage request, Result<DreamMessage> response) { UserBE user = DekiContext.Current.User; PageBE page = PageBL.AuthorizePage(user, Permissions.READ, false); XDoc ret = RatingBL.GetRatingXml(page, user); response.Return(DreamMessage.Ok(ret)); yield break; }
protected user Authenticate(DreamContext context, DreamMessage request, DekiUserLevel level) { user result = null; // get username and password string user; string password; if (!DreamUtil.GetAuthentication(context, request, out user, out password)) { // anonymous access is always granted if (level == DekiUserLevel.Anonymous) { // TODO (steveb): missing code throw new NotImplementedException("return anonymous user"); } else { throw new DreamAbortException(DreamMessage.AccessDenied(AuthenticationRealm, "authentication failed")); } } // validate username and password result = MindTouch.Deki.user.GetUserByName(user); if (result == null) { throw new DreamAbortException(DreamMessage.AccessDenied(AuthenticationRealm, "authentication failed")); } if (!result.checkPassword(password)) { throw new DreamAbortException(DreamMessage.AccessDenied(AuthenticationRealm, "authentication failed")); } if ((level == DekiUserLevel.Admin) && !result.isSysop()) { throw new DreamAbortException(DreamMessage.AccessDenied(AuthenticationRealm, "authentication failed")); } return result; }
public Yield PostBans(DreamContext context, DreamMessage request, Result<DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); BanBE ban = BanningBL.SaveBan(request.ToDocument()); DekiContext.Current.Instance.EventSink.BanCreated(context.StartTime, ban); response.Return(DreamMessage.Ok(BanningBL.GetBanXml(ban))); yield break; }
//--- Methods --- private void CallbackHandler(Plug plug, string verb, XUri uri, DreamMessage request, Result<DreamMessage> response) { if(uri.Segments.Length == 0) { response.Return(DreamMessage.Ok()); return; } var segments = uri.Segments; var wikiId = segments[0]; if(wikiId.StartsWith("=")) { var id = (HostLookupOverride == null) ? DefaultWikiId : HostLookupOverride(wikiId.Substring(1)); response.Return(DreamMessage.Ok(new XDoc("wiki").Attr("id", id))); return; } if(segments.Length == 2 && segments[1] == "license") { XDoc license; if(LicenseOverride == null) { _log.Debug("returning license from disk"); license = XDocFactory.LoadFrom(Utils.Settings.LicensePath, MimeType.TEXT_XML); } else { _log.Debug("returning license from override callback"); license = LicenseOverride(wikiId); } response.Return(DreamMessage.Ok(license)); return; } var config = (ConfigOverride == null) ? DefaultConfig : ConfigOverride(wikiId); response.Return(DreamMessage.Ok(config)); }
public Yield GetSiteStatus(DreamContext context, DreamMessage request, Result<DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.UPDATE); var status = new XDoc("status") .Elem("state", DekiContext.Current.Instance.Status); response.Return(DreamMessage.Ok(status)); yield break; }
public Yield GetTags(DreamContext context, DreamMessage request, Result<DreamMessage> response) { string type = DreamContext.Current.GetParam("type", ""); string fromStr = DreamContext.Current.GetParam("from", ""); string toStr = DreamContext.Current.GetParam("to", ""); bool showPages = DreamContext.Current.GetParam("pages", false); string partialName = DreamContext.Current.GetParam("q", ""); // parse type TagType tagType = TagType.ALL; if(!string.IsNullOrEmpty(type) && !SysUtil.TryParseEnum(type, out tagType)) { throw new DreamBadRequestException("Invalid type parameter"); } // check and validate from date DateTime from = (tagType == TagType.DATE) ? DateTime.Now : DateTime.MinValue; if(!string.IsNullOrEmpty(fromStr) && !DateTime.TryParse(fromStr, out from)) { throw new DreamBadRequestException("Invalid from date parameter"); } // check and validate to date DateTime to = (tagType == TagType.DATE) ? from.AddDays(30) : DateTime.MaxValue; if(!string.IsNullOrEmpty(toStr) && !DateTime.TryParse(toStr, out to)) { throw new DreamBadRequestException("Invalid to date parameter"); } // execute query var tags = TagBL.GetTags(partialName, tagType, from, to); XDoc doc = TagBL.GetTagListXml(tags, "tags", null, showPages); response.Return(DreamMessage.Ok(doc)); yield break; }
public Yield SubscribeToChange(DreamContext context, DreamMessage request, Result<DreamMessage> response) { var wikiId = GetWikiIdFromRequest(request); var pageId = context.GetParam<uint>("pageid"); var depth = context.GetParam("depth", "0") == "0" ? false : true; Result<PageSubscriptionUser> userResult; yield return userResult = Coroutine.Invoke(GetRequestUser, request, new Result<PageSubscriptionUser>()).Catch(); if(userResult.HasException) { ReturnUserError(userResult.Exception, response); yield break; } var userInfo = userResult.Value; DreamMessage pageAuth = null; yield return _deki .At("pages", pageId.ToString(), "allowed") .With("permissions", "read,subscribe") .WithHeaders(request.Headers) .Post(new XDoc("users").Start("user").Attr("id", userInfo.Id).End(), new Result<DreamMessage>()) .Set(x => pageAuth = x); if(!pageAuth.IsSuccessful || pageAuth.ToDocument()["user/@id"].AsText != userInfo.Id.ToString()) { throw new DreamForbiddenException("User not permitted to subscribe to page"); } var dataSession = GetDataSession(wikiId); dataSession.Subscribe(userInfo.Id, pageId, depth); response.Return(DreamMessage.Ok()); yield break; }
public Yield Register(DreamContext context, DreamMessage request, Result<DreamMessage> response) { string servicePath = context.GetParam("service-path"); string location = StringUtil.CreateAlphaNumericKey(8); // register the script XDoc config = new XDoc("config") .Elem("manifest", servicePath) .Elem("debug", true); //create the script service Result<Plug> res; yield return res = CreateService(location, "sid://mindtouch.com/2007/12/dekiscript", config, new Result<Plug>()); Plug service = res.Value; // register script functions in environment XDoc manifest = service.Get().ToDocument(); string ns = manifest["namespace"].AsText; foreach(XDoc function in manifest["function"]) { string name = function["name"].AsText; if(string.IsNullOrEmpty(ns)) { _env.Vars.AddNativeValueAt(name, function["uri"].AsUri); } else { _env.Vars.AddNativeValueAt(ns + "." + name, function["uri"].AsUri); } } response.Return(DreamMessage.Ok(MimeType.XML, manifest)); }
public Yield DeleteSource(DreamContext context, DreamMessage request, Result<DreamMessage> response) { Result<bool> result = new Result<bool>(); yield return Context.Current.Instance.SourceController.Delete(context.GetParam("id"), context.GetParam("rev",null), result); response.Return(DreamMessage.Ok(MimeType.JSON, result.Value.ToString())); }
public DreamMessage GetContentHandler(DreamContext context, DreamMessage message) { user user = Authenticate(context, message, DekiUserLevel.User); page page = Authorize(context, user, DekiAccessLevel.Read, "pageid"); DekiContext deki = new DekiContext(message, this.DekiConfig); bool nofollow = (context.Uri.GetParam("nofollow", 0, null) != null); string contents = page.getContent(nofollow); string xml = string.Format(DekiWikiService.XHTML_LOOSE, contents); XDoc doc = XDoc.FromXml(xml); if (doc == null) { LogUtils.LogWarning(_log, "GetContentHandler: null document page content", page.PrefixedName, contents); throw new DreamAbortException(DreamMessage.BadRequest("null document")); } XDoc result = new XDoc("list"); string type = context.Uri.GetParam("type", 0, null); string id = context.Uri.GetParam("id", 0, null); if (id != null) { XDoc widget = doc[string.Format("//default:span[@widgetid={0}]", id)]; if (widget.IsEmpty) { LogUtils.LogWarning(_log, "GetContentHandler: widget not found for ID", id); return DreamMessage.NotFound(""); } LogUtils.LogTrace(_log, "GetContentHandler: widget by id (id, xspan)", id, widget); result.Add(ConvertFromXSpan(widget)); } else if (type != null) { foreach (XDoc widget in doc[string.Format("//default:span[@widgettype='{0}']", type)]) result.Add(ConvertFromXSpan(widget)); LogUtils.LogTrace(_log, "GetContentHandler: widget by type (type, #)", type, result.Count); } else { foreach (XDoc widget in doc["//default:span[@class='widget']"]) result.Add(ConvertFromXSpan(widget)); LogUtils.LogTrace(_log, "GetContentHandler: all widgets (#)", type, result.Count); } return DreamMessage.Ok(result); }
public Yield GetPage(DreamContext context, DreamMessage request, Result<DreamMessage> response) { CheckResponseCache(context, false); PageBE page = PageBL.GetPageFromUrl(true); page = PageBL.AuthorizePage(DekiContext.Current.User, Permissions.READ, page, false); response.Return(DreamMessage.Ok(PageBL.GetPageXmlVerbose(page, 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, string.Format(DekiResources.COMMENT_ADDED, comment.Number.ToString()), comment); return comment; } }
public Yield GetSearchDescription(DreamContext context, DreamMessage request, Result<DreamMessage> response) { XDoc description = new XDoc("OpenSearchDescription", "http://a9.com/-/spec/opensearch/1.1/"); description.Elem("ShortName", string.Format(DekiResources.OPENSEARCH_SHORTNAME, DekiContext.Current.Instance.SiteName)) .Elem("Description", DekiResources.OPENSEARCH_DESCRIPTION) .Start("Query") .Attr("role", "example") .Attr("searchTerms", "Wiki") .End(); // HACK HACK HACK: we can't use XUri because it encodes the "{}" characters string uri = DekiContext.Current.ApiUri.At("site", "opensearch").ToString(); uri += "?q={searchTerms}&offset={startIndex}&limit={count?}&"; description.Start("Url") .Attr("type", "text/html") .Attr("indexOffset", 0) .Attr("template", DekiContext.Current.UiUri.At("Special:Search").ToString() + "?search={searchTerms}&offset=0&limit={count?}&format=html") .End() .Start("Url") .Attr("type", "application/atom+xml") .Attr("indexOffset", 0) .Attr("template", uri + "format=atom") .End() .Start("Url") .Attr("type", "application/rss+xml") .Attr("indexOffset", 0) .Attr("template", uri + "format=rss") .End() .Start("Url") .Attr("type", "application/x-suggestions+json") .Attr("template", DekiContext.Current.ApiUri.At("site", "opensearch", "suggestions").ToString() + "?q={searchTerms}") .End(); response.Return(DreamMessage.Ok(description)); yield break; }
public Yield GetServiceById(DreamContext context, DreamMessage request, Result<DreamMessage> response) { bool privateDetails = PermissionsBL.IsUserAllowed(DekiContext.Current.User, Permissions.ADMIN); //Private feature requires api-key var identifier = context.GetParam("id"); uint serviceId = 0; if(identifier.StartsWith("=")) { var serviceInfo = DekiContext.Current.Instance.RunningServices[XUri.Decode(identifier.Substring(1))]; if(serviceInfo != null) { serviceId = serviceInfo.ServiceId; } } else { if(!uint.TryParse(identifier, out serviceId)) { throw new DreamBadRequestException(string.Format("Invalid id '{0}'", identifier)); } } ServiceBE service = ServiceBL.GetServiceById(serviceId); DreamMessage responseMsg = null; if(service == null) { responseMsg = DreamMessage.NotFound(string.Format(DekiResources.SERVICE_NOT_FOUND, identifier)); } else { responseMsg = DreamMessage.Ok(ServiceBL.GetServiceXmlVerbose(DekiContext.Current.Instance, service, null, privateDetails)); } response.Return(responseMsg); yield break; }
public AwsSqsRequestException(AwsSqsError error, DreamMessage request) : base(error.Message) { Request = request; Error = error; IsSqsError = true; }
public Yield GetGroup(DreamContext context, DreamMessage request, Result<DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.READ); GroupBE group = GetGroupFromUrl(); DreamMessage responseMsg = DreamMessage.Ok(GroupBL.GetGroupXmlVerbose(group, null)); response.Return(responseMsg); yield break; }
public Yield GetPageTags(DreamContext context, DreamMessage request, Result<DreamMessage> response) { PageBE page = PageBL.AuthorizePage(DekiContext.Current.User, Permissions.READ, false); XUri href = DekiContext.Current.ApiUri.At("pages", page.ID.ToString(), "tags"); XDoc doc = TagBL.GetTagListXml(TagBL.GetTagsForPage(page), "tags", href, false); response.Return(DreamMessage.Ok(doc)); yield break; }
public Yield SubscribeToChange(DreamContext context, DreamMessage request, Result<DreamMessage> response) { uint pageId = context.GetParam<uint>("pageid"); string depth = context.GetParam("depth", "0"); Result<UserInfo> userResult; yield return userResult = Coroutine.Invoke(GetUserInfo, true, request, new Result<UserInfo>()).Catch(); if(userResult.HasException) { ReturnUserError(userResult.Exception, response); yield break; } UserInfo userInfo = userResult.Value; DreamMessage pageAuth = null; yield return _deki .At("pages", pageId.ToString(), "allowed") .With("permissions", "read,subscribe") .WithHeaders(request.Headers) .Post(new XDoc("users").Start("user").Attr("id", userInfo.Id).End(), new Result<DreamMessage>()) .Set(x => pageAuth = x); if(!pageAuth.IsSuccessful || pageAuth.ToDocument()["user/@id"].AsText != userInfo.Id.ToString()) { throw new DreamForbiddenException("User not permitted to subscribe to page"); } userInfo.AddResource(pageId, depth); userInfo.Save(); response.Return(DreamMessage.Ok()); yield break; }
public Yield Invoke(Plug plug, string verb, XUri uri, DreamMessage request, Result<DreamMessage> response) { // NOTE (steveb): we convert 'xri://@name/path?params' into 'http://xri.net/@name/path?params' // prepend segments with authority List<string> segments = new List<string>(); segments.Add(uri.Authority); if(uri.Segments != null) { segments.AddRange(uri.Segments); } // build new plug List<PlugHandler> preHandlers = (plug.PreHandlers != null) ? new List<PlugHandler>(plug.PreHandlers) : null; List<PlugHandler> postHandlers = (plug.PostHandlers != null) ? new List<PlugHandler>(plug.PostHandlers) : null; Plug xri = new Plug(new XUri("http", null, null, "xri.net", 80, segments.ToArray(), uri.TrailingSlash, uri.Params, uri.Fragment), plug.Timeout, request.Headers, preHandlers, postHandlers, plug.Credentials, plug.CookieJar, plug.MaxAutoRedirects); // add 'Accept' header for 'application/xrds+xml' mime-type if((xri.Headers == null) || (xri.Headers.Accept == null)) { xri = xri.WithHeader(DreamHeaders.ACCEPT, MimeType.RenderAcceptHeader(MimeType.XRDS)); } // BUGBUGBUG (steveb): this will probably fail in some cases since we may exit this coroutine before the call has completed! xri.InvokeEx(verb, request, response); yield break; }
public Yield GetCommentContent(DreamContext context, DreamMessage request, Result<DreamMessage> response) { PageBE page = null; CommentBE comment = null; GetCommentFromRequest(context, Permissions.READ, out page, out comment); response.Return(DreamMessage.Ok(new MimeType(comment.ContentMimeType), comment.Content)); yield break; }
public Yield GetArchiveFiles(DreamContext context, DreamMessage request, Result<DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); IList<AttachmentBE> removedFiles = AttachmentBL.Instance.GetResources(DeletionFilter.DELETEDONLY, null, null); XDoc responseXml = AttachmentBL.Instance.GetFileXml(removedFiles, true, "archive", null, null); response.Return(DreamMessage.Ok(responseXml)); yield break; }
public Yield PutSiteRole(DreamContext context, DreamMessage request, Result<DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); RoleBE role = GetRoleFromUrl(false); role = PermissionsBL.PutRole(role, request, context); response.Return(DreamMessage.Ok(PermissionsBL.GetRoleXml(role, null))); yield break; }
private void WriteErrorRequest(DreamMessage request) { try { WriteLineToLog("Request message: " + request.ToString()); } catch { } }
private Yield PrologueMediaWikiConverterContext(DreamContext context, DreamMessage request, Result<DreamMessage> response) { MediaWikiConverterContext mwContext = new MediaWikiConverterContext(Config); DreamContext.Current.SetState<MediaWikiConverterContext>(mwContext); // continue processing response.Return(request); yield break; }
public DreamMessage PostTidyXHmlt(DreamContext context, DreamMessage message) { string baseHref = context.Uri.GetParam("base", ""); string pageID = context.Uri.GetParam("context", ""); bool toEdit = context.Uri.GetParam<bool>("toEdit", false); XDoc doc = XDoc.FromHtml(new StreamReader(message.Stream, message.ContentEncoding)); XHTMLConverter.Convert(doc, baseHref, pageID, toEdit); return DreamMessage.Ok(MimeType.XHTML, doc.Root.ToXHtml()); }
public Yield GetInfo(DreamContext aContext, DreamMessage aRequest, Result<DreamMessage> aResponse) { XDoc xmlInfo = new XDoc("info"); xmlInfo.Elem("User", Context.Current.User); xmlInfo.Elem("About", "Foiremuses web service (c) 2011 Vincent DARON / Danny WILLEM"); aResponse.Return(DreamMessage.Ok(MimeType.XML, xmlInfo)); yield break; }
public Yield UpdateSource(DreamContext context, DreamMessage request, Result<DreamMessage> response) { ISource source = Context.Current.Instance.SourceController.FromJson(request.ToText()); Result<ISource> result = new Result<ISource>(); yield return Context.Current.Instance.SourceController.Update(context.GetParam("id"), context.GetParam("rev", null), source, result); response.Return(DreamMessage.Ok(MimeType.JSON, Context.Current.Instance.SourceController.ToJson(result.Value))); }
public Yield CreatePlay(DreamContext context, DreamMessage request, Result<DreamMessage> response) { IPlay play = Context.Current.Instance.PlayController.FromJson(request.ToText()); Result<IPlay> result = new Result<IPlay>(); yield return Context.Current.Instance.PlayController.Insert(play, result); response.Return(DreamMessage.Ok(MimeType.JSON, Context.Current.Instance.PlayController.ToJson(result.Value))); }
internal IEnumerator<IYield> GetImportStatus(DreamContext context, DreamMessage request, Result<DreamMessage> response) { var wikiId = context.GetParam("wikiid"); _log.DebugFormat("checking status on instance '{0}'", wikiId); var instance = GetInstance(wikiId, false); var status = instance == null ? "none" : instance.Status.ToString().ToLower(); response.Return(DreamMessage.Ok(new XDoc("package-updater").Attr("wikiid", wikiId).Attr("status", status))); yield break; }
public Yield GetArchive(DreamContext context, DreamMessage request, Result<DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); XDoc ret = new XDoc("archive"); ret.Start("pages.archive").Attr("href", DekiContext.Current.ApiUri.At("archive", "pages")).End(); ret.Start("files.archive").Attr("href", DekiContext.Current.ApiUri.At("archive", "files")).End(); response.Return(DreamMessage.Ok(ret)); yield break; }
//--- Constructors --- public DreamCachedResponseException(DreamMessage response) { this.Response = response; }
private static object GetMessageResponse(DreamContext context, DreamMessage request, Result <DreamMessage> response) { return(response); }
private static object GetContextFeatureSubpath(DreamContext context, DreamMessage request, Result <DreamMessage> response) { return(context.Uri.GetRelativePathTo(context.Feature.ServiceUri)); }
private static object GetRequestAsBytes(DreamContext context, DreamMessage request, Result <DreamMessage> response) { return(request.ToBytes()); }
//--- Methods --- internal void Handler(Result <DreamMessage> result) { DreamMessage request; // check if previous feature handler threw an exception try { if (result.HasException) { DreamAbortException abort = result.Exception as DreamAbortException; if (abort != null) { // extract contained message request = abort.Response; } else { // check if this is a cached response we need to forward DreamCachedResponseException cached = result.Exception as DreamCachedResponseException; if (cached != null) { _response.Throw(cached); return; } // convert exception into message DreamMessage exceptionMessage = null; ExceptionTranslator[] translators = _context.Feature.ExceptionTranslators; if (translators != null) { bool locallyAttachedContext = false; try { if (DreamContext.CurrentOrNull == null) { _context.AttachToCurrentTaskEnv(); locallyAttachedContext = true; } foreach (var translate in translators) { exceptionMessage = translate(_context, result.Exception); if (exceptionMessage != null) { break; } } } finally { if (locallyAttachedContext) { _context.DetachFromTaskEnv(); } } } if (exceptionMessage == null) { _log.ErrorExceptionFormat(result.Exception, "handler for {0}:{1} failed ({2})", _context.Verb, _context.Uri.ToString(false), _previousName); exceptionMessage = DreamMessage.InternalError(result.Exception); } request = exceptionMessage; } } else { request = result.Value; } } catch (Exception e) { if (result.HasException) { _log.ErrorExceptionFormat(result.Exception, "handler for {0}:{1} failed ({2}), cascading via processing exception '{3}'", _context.Verb, _context.Uri.ToString(false), _previousName, e); request = DreamMessage.InternalError(result.Exception); } else { _log.ErrorExceptionFormat(e, "handler for {0}:{1} failed completing stage '{2}'", _context.Verb, _context.Uri.ToString(false), _previousName); request = DreamMessage.InternalError(e); } } // check if feature handler can handle this message if (!MainStage || request.IsSuccessful) { TaskEnv.ExecuteNew(() => Handler_DreamMessage(request)); } else { // non-success messages skip the main stage _response.Return(request); } }
private Yield InServiceInvokeHandler(DreamContext context, DreamMessage request, Result <DreamMessage> response) { throw new InvalidOperationException("this feature should never be invoked"); }
/// <summary> /// Invoke an action in the context of a service feature. /// </summary> /// <remarks> /// Assumes that there exists a current <see cref="DreamContext"/> that belongs to a request to another feature of this service. /// </remarks> /// <param name="verb">Http verb.</param> /// <param name="path">Feature path.</param> /// <param name="handler">Action to perform in this context.</param> /// <returns>Exception thrown by handler or null.</returns> public Exception InvokeInServiceContext(string verb, string path, Action handler) { if (handler == null) { throw new ArgumentNullException("handler"); } if (string.IsNullOrEmpty(verb)) { throw new ArgumentNullException("verb"); } if (path == null) { throw new ArgumentNullException("path"); } // create new new environment for execution XUri uri = Self.AtPath(path); DreamContext current = DreamContext.Current; Exception e = TaskEnv.ExecuteNew(delegate { DreamFeatureStage[] stages = new[] { new DreamFeatureStage("InServiceInvokeHandler", InServiceInvokeHandler, DreamAccess.Private) }; // BUGBUGBUG (steveb): when invoking a remote function this way, we're are not running the proloques and epilogues, which leads to errors; // also dream-access attributes are being ignored (i.e. 'public' vs. 'private') DreamMessage message = DreamUtil.AppendHeadersToInternallyForwardedMessage(current.Request, DreamMessage.Ok()); var context = current.CreateContext(verb, uri, new DreamFeature(this, Self, 0, stages, verb, path), message); context.AttachToCurrentTaskEnv(); // pass along host and public-uri information handler(); }, TimerFactory); return(e); }
//--- Constructors --- /// <summary> /// Create new instance with a message describing the reason for the aborted request. /// </summary> /// <param name="response">Message describing the reason for the aborted request.</param> public DreamAbortException(DreamMessage response) : base(DreamMessage.GetStatusStringOrNull(response)) { this.Response = response; }
private Dictionary <string, string> CheckServiceLicense() { // check request validity (unless it's for the @config uri, which is a special case) Dictionary <string, string> result = null; if ((Feature.Service.Self != null) && (Feature.Service is IDreamServiceLicense) && !(Uri.LastSegment ?? string.Empty).EqualsInvariant("@config")) { string service_license = ((IDreamServiceLicense)Feature.Service).ServiceLicense; if (string.IsNullOrEmpty(service_license)) { throw new DreamAbortException(DreamMessage.LicenseRequired("service-license missing")); } // extract public RSA key for validation RSACryptoServiceProvider public_key = RSAUtil.ProviderFrom(Feature.Service.GetType().Assembly); if (public_key == null) { throw new DreamAbortException(DreamMessage.InternalError("service assembly invalid")); } // validate the service-license try { // parse service-license result = HttpUtil.ParseNameValuePairs(service_license); if (!Encoding.UTF8.GetBytes(service_license.Substring(0, service_license.LastIndexOf(','))).VerifySignature(result["dsig"], public_key)) { throw new DreamAbortException(DreamMessage.InternalError("invalid service-license")); } } catch (Exception e) { // unexpected error, blame it on the license if (e is DreamAbortException) { throw; } else { throw new DreamAbortException(DreamMessage.InternalError("corrupt service-license")); } } // check license string text; if ((!result.TryGetValue("licensee", out text) || string.IsNullOrEmpty(text)) && !result.ContainsKey("expire")) { // unexpected error, blame it on the license throw new DreamAbortException(DreamMessage.InternalError("corrupt service-license")); } // determine 'now' date-time DateTime now = GlobalClock.UtcNow; DateTime?request_date = Request.Headers.Date; if (request_date.HasValue) { now = (request_date.Value > now) ? request_date.Value : now; } // check expiration DateTime expire; if (result.TryGetValue("expire", out text) && (!DateTimeUtil.TryParseInvariant(text, out expire) || (expire.ToUniversalTime() < now))) { throw new DreamAbortException(DreamMessage.LicenseRequired("service-license has expired")); } } return(result); }
internal DreamContext CreateContext(string verb, XUri uri, DreamFeature feature, DreamMessage message) { return(new DreamContext(Env, verb, uri, feature, PublicUri, ServerUri, message, Culture, _requestContainerFactory, null)); }
private DreamContext(IDreamEnvironment env, string verb, XUri uri, DreamFeature feature, XUri publicUri, XUri serverUri, DreamMessage request, CultureInfo culture, Func <Action <ContainerBuilder>, ILifetimeScope> requestContainerFactory, Dictionary <string, string> license) { if (env == null) { throw new ArgumentNullException("env"); } if (verb == null) { throw new ArgumentNullException("verb"); } if (uri == null) { throw new ArgumentNullException("uri"); } if (feature == null) { throw new ArgumentNullException("feature"); } if (publicUri == null) { throw new ArgumentNullException("publicUri"); } if (request == null) { throw new ArgumentNullException("request"); } if (culture == null) { throw new ArgumentNullException("culture"); } if (requestContainerFactory == null) { throw new ArgumentNullException("requestContainerFactory"); } this.ID = System.Threading.Interlocked.Increment(ref _contextIdCounter); this.Env = env; this.Verb = verb; this.Uri = uri; this.Feature = feature; this.Feature.ExtractArguments(this.Uri, out _suffixes, out _pathParams); this.ServerUri = serverUri; this.Request = request; this.StartTime = GlobalClock.UtcNow; _publicUri = publicUri; _culture = culture; _requestContainerFactory = requestContainerFactory; _license = license; }
/// <summary> /// Append Dream specific headers from a source message to an internally forwarded one. /// </summary> /// <param name="original">Source messag.</param> /// <param name="forwarded">Message to be forwarded.</param> /// <returns>Message to be forwarded instance.</returns> public static DreamMessage AppendHeadersToInternallyForwardedMessage(DreamMessage original, DreamMessage forwarded) { // pass along host and public-uri information forwarded.Headers.DreamTransport = original.Headers.DreamTransport; forwarded.Headers.DreamPublicUri = original.Headers.DreamPublicUri; forwarded.Headers.DreamUserHost = original.Headers.DreamUserHost; forwarded.Headers.DreamOrigin = original.Headers.DreamOrigin; forwarded.Headers.DreamClientIP = original.Headers.DreamClientIP; return(forwarded); }
public virtual Yield GetServiceInfo(DreamContext context, DreamMessage request, Result <DreamMessage> response) { XDoc blueprint = Blueprint; string title = blueprint["name"].AsText ?? "Service Blueprint"; XDoc result = new XDoc("html").Attr("xmlns", "http://www.w3.org/1999/xhtml") .Start("head") .Elem("title", title) .Start("meta").Attr("http-equiv", "content-type").Attr("content", "text/html;charset=utf-8").End() .Start("meta").Attr("http-equiv", "Content-Style-Type").Attr("content", "text/css").End() .End(); if (blueprint.IsEmpty) { result.Elem("body", "Missing service blueprint"); } else { result.Start("body") .Elem("h1", title) .Start("p") .Value(blueprint["copyright"].Contents) .Value(" ") .Start("a").Attr("href", blueprint["info"].Contents).Value("(more)").End() .Value(" ") .Start("a").Attr("href", Self.Uri.At("@blueprint").Path).Value("(blueprint)").End() .End(); // show configuration information XDoc config = blueprint["configuration"]; if (!config.IsEmpty) { result.Elem("h2", "Configuration"); result.Start("ul"); foreach (XDoc entry in config["entry"]) { result.Start("li"); if (entry["valuetype"].Contents != string.Empty) { result.Value(string.Format("{0} = {1} : {2}", entry["name"].Contents, entry["valuetype"].Contents, entry["description"].Contents)); } else { result.Value(string.Format("{0} : {1}", entry["name"].Contents, entry["description"].Contents)); } result.End(); } result.End(); } // sort features by signature then verb blueprint["features"].Sort(delegate(XDoc first, XDoc second) { string[] firstPattern = first["pattern"].Contents.Split(new[] { ':' }, 2); string[] secondPattern = second["pattern"].Contents.Split(new[] { ':' }, 2); int cmp = firstPattern[1].CompareInvariantIgnoreCase(secondPattern[1]); if (cmp != 0) { return(cmp); } return(firstPattern[0].CompareInvariant(secondPattern[0])); }); // display features XDoc features = blueprint["features/feature"]; if (!features.IsEmpty) { result.Elem("h2", "Features"); List <string> modifiers = new List <string>(); foreach (XDoc feature in features) { modifiers.Clear(); // add modifiers string modifier = feature["access"].AsText; if (modifier != null) { modifiers.Add(modifier); } modifier = feature["obsolete"].AsText; if (modifier != null) { modifiers.Add("OBSOLETE => " + modifier); } if (modifiers.Count > 0) { modifier = " (" + string.Join(", ", modifiers.ToArray()) + ")"; } else { modifier = string.Empty; } // check if feature has GET verb and no path parameters string pattern = feature["pattern"].Contents; if (pattern.StartsWithInvariantIgnoreCase(Verb.GET + ":") && (pattern.IndexOfAny(new[] { '{', '*', '?' }) == -1)) { string[] parts = pattern.Split(new[] { ':' }, 2); result.Start("h3") .Start("a").Attr("href", context.AsPublicUri(Self.Uri.AtPath(parts[1]))) .Value(feature["pattern"].Contents) .End() .Value(modifier) .End(); } else { result.Elem("h3", feature["pattern"].Contents + modifier); } result.Start("p") .Value(feature["description"].Contents) .Value(" ") .Start("a").Attr("href", feature["info"].Contents).Value("(more)").End(); XDoc paramlist = feature["param"]; if (!paramlist.IsEmpty) { result.Start("ul"); foreach (XDoc param in paramlist) { result.Start("li"); if (param["valuetype"].Contents != string.Empty) { result.Value(string.Format("{0} = {1} : {2}", param["name"].Contents, param["valuetype"].Contents, param["description"].Contents)); } else { result.Value(string.Format("{0} : {1}", param["name"].Contents, param["description"].Contents)); } result.End(); } result.End(); } result.End(); } } } response.Return(DreamMessage.Ok(MimeType.HTML, result.ToString())); yield break; }
protected virtual Yield DeleteService(DreamContext context, DreamMessage request, Result <DreamMessage> response) { yield return(Env.At("stop").Post(new XDoc("service").Elem("uri", Self), new Result <DreamMessage>(TimeSpan.MaxValue)).CatchAndLog(_log)); response.Return(DreamMessage.Ok()); }
public virtual Yield GetServiceBlueprint(DreamContext context, DreamMessage request, Result <DreamMessage> response) { response.Return(DreamMessage.Ok(Blueprint)); yield break; }
/// <summary> /// Create new instance with a message describing the reason for the aborted request. /// </summary> /// <param name="response">Message describing the reason for the aborted request.</param> /// <param name="message">Additional text message about the problem.</param> public DreamAbortException(DreamMessage response, string message) : base(message) { this.Response = response; }
/// <summary> /// Create new instance with a message describing the reason for the aborted request. /// </summary> /// <param name="response">Message describing the reason for the aborted request.</param> /// <param name="message">Additional text message about the problem.</param> /// <param name="innerException">The exception that caused the message to be unsuccessful.</param> public DreamAbortException(DreamMessage response, string message, Exception innerException) : base(message, innerException) { this.Response = response; }
//--- Constructors --- /// <summary> /// Create a new instance for an <see cref="DreamStatus.InternalError"/> failure. /// </summary> public DreamInternalErrorException() : base(DreamMessage.InternalError()) { }
/// <summary> /// Create a new host with provided configuration and an Inversion of Control container. /// </summary> /// <remarks> /// The IoC container is also injected into default activator, so that <see cref="IDreamService"/> instances /// can be resolved from the container. The host configuration is provided to the container as a typed parameter. /// </remarks> /// <param name="config">Host configuration.</param> /// <param name="container">IoC Container.</param> public DreamHost(XDoc config, IContainer container) { if (config == null) { throw new ArgumentNullException("config"); } // read host settings string appDirectory = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName); int limit = config["connect-limit"].AsInt ?? 0; int httpPort = config["http-port"].AsInt ?? DEFAULT_PORT; AuthenticationSchemes authenticationScheme = AuthenticationSchemes.Anonymous; string authShemes = config["authentication-shemes"].AsText; if (!String.IsNullOrEmpty(authShemes)) { try { authenticationScheme = (AuthenticationSchemes)Enum.Parse(typeof(AuthenticationSchemes), authShemes, true); } catch (Exception e) { _log.Warn(String.Format("invalid authetication scheme specified :{0}", authShemes), e); } } // get the authtoken for whitelisting dream.in.* query args _dreamInParamAuthtoken = config["dream.in.authtoken"].AsText; if (!string.IsNullOrEmpty(_dreamInParamAuthtoken)) { _log.Debug("Host is configured in dream.in param authorizing mode"); } // read ip-addresses var addresses = new List <string>(); foreach (XDoc ip in config["host|ip"]) { addresses.Add(ip.AsText); } if (addresses.Count == 0) { // if no addresses were supplied listen to all addresses.Add("*:" + httpPort); } // use default servername XUri publicUri = config["uri.public"].AsUri; if (publicUri == null) { // backwards compatibility publicUri = config["server-name"].AsUri; if (publicUri == null) { foreach (IPAddress addr in Dns.GetHostAddresses(Dns.GetHostName())) { if (addr.AddressFamily == AddressFamily.InterNetwork) { XUri.TryParse("http://" + addr, out publicUri); } } if (publicUri == null) { // failed to get an address out of dns, fall back to localhost XUri.TryParse("http://localhost", out publicUri); } } publicUri = publicUri.AtPath(config["server-path"].AsText ?? config["path-prefix"].AsText ?? string.Empty); } // create environment and initialize it _env = new DreamHostService(container); try { // initialize environment string apikey = config["apikey"].AsText ?? StringUtil.CreateAlphaNumericKey(32); XDoc serviceConfig = new XDoc("config"); var storageType = config["storage/@type"].AsText ?? "local"; if ("s3".EqualsInvariant(storageType)) { serviceConfig.Add(config["storage"]); } else { serviceConfig.Elem("storage-dir", config["storage-dir"].AsText ?? config["service-dir"].AsText ?? appDirectory); } serviceConfig.Elem("apikey", apikey); serviceConfig.Elem("uri.public", publicUri); serviceConfig.Elem("connect-limit", limit); serviceConfig.Elem("guid", config["guid"].AsText); serviceConfig.AddAll(config["components"]); var memorize = config["memorize-aliases"]; if (!memorize.IsEmpty) { serviceConfig.Elem("memorize-aliases", memorize.AsBool); } _env.Initialize(serviceConfig); // initialize host plug _host = _env.Self.With("apikey", apikey); // load assemblies in 'services' folder string servicesFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "services"); if (Directory.Exists(servicesFolder)) { // Note (arnec): Deprecated, but the suggested alternative really doesn't apply since we don't want to // load services into a separate appdomain. #pragma warning disable 618,612 AppDomain.CurrentDomain.AppendPrivatePath("services"); #pragma warning restore 618,612 foreach (string file in Directory.GetFiles(servicesFolder, "*.dll")) { // register assembly blueprints DreamMessage response = _host.At("load").With("name", Path.GetFileNameWithoutExtension(file)).Post(new Result <DreamMessage>(TimeSpan.MaxValue)).Wait(); if (!response.IsSuccessful) { _log.WarnFormat("DreamHost: ERROR: assembly '{0}' failed to load", file); } } } // add acccess-points AddListener(new XUri(String.Format("http://{0}:{1}/", "localhost", httpPort)), authenticationScheme); // check if user prescribed a set of IP addresses to use if (addresses != null) { // listen to custom addresses (don't use the supplied port info, we expect that to be part of the address) foreach (string address in addresses) { if (!StringUtil.EqualsInvariantIgnoreCase(address, "localhost")) { AddListener(new XUri(String.Format("http://{0}/", address)), authenticationScheme); } } } else { // add listeners for all known IP addresses foreach (IPAddress address in Dns.GetHostAddresses(Dns.GetHostName())) { XUri uri = MakeUri(address, httpPort); if (uri != null) { AddListener(uri, authenticationScheme); try { foreach (string alias in Dns.GetHostEntry(address).Aliases) { AddListener(new XUri(String.Format("http://{0}:{1}/", alias, httpPort)), authenticationScheme); } } catch { } } } } } catch (Exception e) { if ((e is HttpListenerException) && e.Message.EqualsInvariant("Access is denied")) { _log.ErrorExceptionMethodCall(e, "ctor", "insufficient privileges to create HttpListener, make sure the application runs with Administrator rights"); } else { _log.ErrorExceptionMethodCall(e, "ctor"); } try { _env.Deinitialize(); } catch { } throw; } }
/// <summary> /// Create a new instance for an <see cref="DreamStatus.InternalError"/> failure. /// </summary> /// <param name="message">Text message to use for <see cref="Exception.Message"/> and the internal <see cref="DreamMessage"/>.</param> public DreamInternalErrorException(string message) : base(DreamMessage.InternalError(message), message) { }
public DreamCachedResponseException(DreamMessage response, string message) : base(message) { this.Response = response; }
/// <summary> /// Create a new instance for a <see cref="DreamStatus.InternalError"/> condition. /// </summary> /// <param name="innerException">The exception that cause the internal error for the request.</param> public DreamInternalErrorException(Exception innerException) : base(DreamMessage.InternalError(innerException), innerException.Message) { }
private static object GetContextUri(DreamContext context, DreamMessage request, Result <DreamMessage> response) { return(context.Uri); }
//--- Constructors --- /// <summary> /// Create a new instance for a <see cref="DreamStatus.BadRequest"/> condition. /// </summary> /// <param name="message">Text message to use for <see cref="Exception.Message"/> and the internal <see cref="DreamMessage"/>.</param> public DreamBadRequestException(string message) : base(DreamMessage.BadRequest(message), message) { }
private static object GetContextFeatureSubpathSegments(DreamContext context, DreamMessage request, Result <DreamMessage> response) { return(context.Uri.GetRelativePathTo(context.Feature.ServiceUri).Split(new[] { "/" }, StringSplitOptions.RemoveEmptyEntries)); }
//--- Constructors --- /// <summary> /// Create a new instance for a <see cref="DreamStatus.Forbidden"/> condition. /// </summary> /// <param name="message">Text message to use for <see cref="Exception.Message"/> and the internal <see cref="DreamMessage"/>.</param> public DreamForbiddenException(string message) : base(DreamMessage.Forbidden(message), message) { }
public object Invoke(DreamContext context, DreamMessage message, Result <DreamMessage> response) { return(_invocation(context, message, response)); }
//--- Constructors --- /// <summary> /// Create a new instance for a <see cref="DreamStatus.NotFound"/> condition. /// </summary> /// <param name="message">Text message to use for <see cref="Exception.Message"/> and the internal <see cref="DreamMessage"/>.</param> public DreamNotFoundException(string message) : base(DreamMessage.NotFound(message), message) { }
/// <summary> /// Relay a request to another service using the current query parameters, service cookies and verb. /// </summary> /// <remarks> /// Must be yielded by a coroutine or invoked with <see cref="Coroutine.Invoke"/>. /// </remarks> /// <param name="plug">Location of relay recipient.</param> /// <param name="request">Request message to relay.</param> /// <param name="response">The <see cref="Result{DreamMessage}"/> instance this coroutine will use as a synchronization handle.</param> /// <returns>Iterator used by <see cref="Coroutine"/> execution environment.</returns> public IYield Relay(Plug plug, DreamMessage request, Result <DreamMessage> response) { return(Relay(plug, Verb, request, response)); }
/// <summary> /// Perform startup configuration of a service instance. /// </summary> /// <remarks> /// Should not be manually invoked and should only be overridden if <see cref="Start(MindTouch.Xml.XDoc,Autofac.ILifetimeScope,MindTouch.Tasking.Result)"/> isn't already overriden. /// </remarks> /// <param name="config">Service configuration.</param> /// <param name="result">Synchronization handle for coroutine invocation.</param> /// <returns>Iterator used by <see cref="Coroutine"/> execution environment.</returns> protected virtual Yield Start(XDoc config, Result result) { Result <DreamMessage> res; // store configuration and uri _config = config; _self = Plug.New(config["uri.self"].AsUri); if (_self == null) { throw new ArgumentNullException("config", "Missing element'uri.self'"); } _owner = Plug.New(config["uri.owner"].AsUri); // check for service access keys var internalAccessKey = config["internal-service-key"].AsText; if (!string.IsNullOrEmpty(internalAccessKey)) { _internalAccessKey = internalAccessKey; } var privateAccessKey = config["private-service-key"].AsText; if (!string.IsNullOrEmpty(privateAccessKey)) { _privateAccessKey = privateAccessKey; } // check for api-key settings _apikey = config["apikey"].AsText; // process 'set-cookie' entries var setCookies = DreamCookie.ParseAllSetCookieNodes(config["set-cookie"]); if (setCookies.Count > 0) { Cookies.Update(setCookies, null); } // grant private access key to self, host, and owner var privateAcccessCookie = DreamCookie.NewSetCookie("service-key", PrivateAccessKey, Self.Uri); Cookies.Update(privateAcccessCookie, null); yield return(Env.At("@grants").Post(DreamMessage.Ok(privateAcccessCookie.AsSetCookieDocument), new Result <DreamMessage>(TimeSpan.MaxValue))); if (Owner != null) { yield return(res = Owner.At("@grants").Post(DreamMessage.Ok(privateAcccessCookie.AsSetCookieDocument), new Result <DreamMessage>(TimeSpan.MaxValue))); if (!res.Value.IsSuccessful) { throw new ArgumentException("unexpected failure setting grants on owner service"); } } // check if this service requires a service-license to work if (this is IDreamServiceLicense) { string service_license = config["service-license"].AsText; if (string.IsNullOrEmpty(service_license)) { throw new DreamAbortException(DreamMessage.LicenseRequired("service-license missing")); } // extract public RSA key for validation RSACryptoServiceProvider public_key = RSAUtil.ProviderFrom(GetType().Assembly); if (public_key == null) { throw new DreamAbortException(DreamMessage.InternalError("service assembly invalid")); } // validate the service-license _license = null; Dictionary <string, string> values; try { // parse service-license values = HttpUtil.ParseNameValuePairs(service_license); if (!Encoding.UTF8.GetBytes(service_license.Substring(0, service_license.LastIndexOf(','))).VerifySignature(values["dsig"], public_key)) { throw new DreamAbortException(DreamMessage.InternalError("invalid service-license (1)")); } // check if the SID matches string sid; if (!values.TryGetValue("sid", out sid) || !SID.HasPrefix(XUri.TryParse(sid), true)) { throw new DreamAbortException(DreamMessage.InternalError("invalid service-license (2)")); } _license = service_license; } catch (Exception e) { // unexpected error, blame it on the license if (e is DreamAbortException) { throw; } throw new DreamAbortException(DreamMessage.InternalError("corrupt service-license (1)")); } // validate expiration date string expirationtext; if (values.TryGetValue("expire", out expirationtext)) { try { DateTime expiration = DateTime.Parse(expirationtext); if (expiration < DateTime.UtcNow) { _license = null; } } catch (Exception e) { _license = null; // unexpected error, blame it on the license if (e is DreamAbortException) { throw; } throw new DreamAbortException(DreamMessage.InternalError("corrupt service-license (2)")); } } // check if a license was assigned if (_license == null) { throw new DreamAbortException(DreamMessage.LicenseRequired("service-license has expired")); } } else { config["service-license"].RemoveAll(); } // create built-in services _storage = Plug.New(config["uri.storage"].AsUri); _pubsub = Plug.New(config["uri.pubsub"].AsUri); // done _log.Debug("Start"); result.Return(); }