public Yield Invoke(Plug plug, string verb, XUri uri, DreamMessage request, Result <DreamMessage> response) { // we only support GET as verb DreamMessage reply; if ((verb != Verb.GET) && (verb != Verb.HEAD)) { reply = new DreamMessage(DreamStatus.MethodNotAllowed, null, null); reply.Headers.Allow = Verb.GET + "," + Verb.HEAD; } else { bool head = (verb == Verb.HEAD); // try to load the assembly System.Reflection.Assembly assembly = System.Reflection.Assembly.Load(uri.Host); Version version = assembly.GetName().Version; DateTime timestamp = new DateTime(2000, 1, 1).AddDays(version.Build).AddSeconds(version.Revision * 2); // check if request is just about re-validation if (!head && request.CheckCacheRevalidation(timestamp)) { reply = DreamMessage.NotModified(); } else { try { System.IO.Stream stream = assembly.GetManifestResourceStream(uri.Path.Substring(1)); if (stream != null) { MimeType mime = MimeType.New(uri.GetParam(DreamOutParam.TYPE, null)) ?? MimeType.BINARY; reply = new DreamMessage(DreamStatus.Ok, null, mime, stream.Length, head ? System.IO.Stream.Null : stream); if (head) { stream.Close(); } else { reply.SetCacheMustRevalidate(timestamp); } } else { reply = DreamMessage.NotFound("could not find resource"); } } catch (System.IO.FileNotFoundException) { reply = DreamMessage.NotFound("could not find resource"); } catch (Exception e) { reply = DreamMessage.InternalError(e); } } } response.Return(reply); yield break; }
/// <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) { }
/// <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) { }
//--- Constructors --- /// <summary> /// Create a new instance for an <see cref="DreamStatus.InternalError"/> failure. /// </summary> public DreamInternalErrorException() : base(DreamMessage.InternalError()) { }
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); }
/// <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(); }
//--- 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); } }