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; }
//--- Interface Methods --- int IPlugEndpoint.GetScoreWithNormalizedUri(XUri uri, out XUri normalized) { int result; XUri prefix; lock(_aliases) { _aliases.TryGetValue(uri, out prefix, out result); } // check if we found a match if(prefix != null) { normalized = uri.ChangePrefix(prefix, _localMachineUri); // if 'dream.in.uri' is not set, set it if((normalized.GetParam(DreamInParam.URI, null) == null) && !prefix.Scheme.EqualsInvariant("local")) { normalized = normalized.With(DreamInParam.URI, prefix.ToString()); } } else { normalized = null; } return (result > 0) ? result + Plug.BASE_ENDPOINT_SCORE : 0; }
private Result<DreamMessage> SubmitRequestAsync(string verb, XUri uri, IPrincipal user, DreamMessage request, Result<DreamMessage> response, Action completion) { if(string.IsNullOrEmpty(verb)) { if(completion != null) { completion(); } throw new ArgumentNullException("verb"); } if(uri == null) { if(completion != null) { completion(); } throw new ArgumentNullException("uri"); } if(request == null) { if(completion != null) { completion(); } throw new ArgumentNullException("request"); } if(response == null) { if(completion != null) { completion(); } throw new ArgumentNullException("response"); } // ensure environment is still running if(!IsRunning) { response.Return(DreamMessage.InternalError("host not running")); if(completion != null) { completion(); } return response; } try { Interlocked.Increment(ref _requestCounter); // check if we were not able to begin processing the request DreamMessage failed = BeginRequest(completion, uri, request); if(failed != null) { response.Return(failed); EndRequest(completion, uri, request); return response; } // check if 'verb' is overwritten by a processing parameter verb = verb.ToUpperInvariant(); string requestedVerb = (uri.GetParam(DreamInParam.VERB, null) ?? request.Headers.MethodOverride ?? verb).ToUpperInvariant(); if( verb.EqualsInvariant(Verb.POST) || ( verb.EqualsInvariant(Verb.GET) && ( requestedVerb.EqualsInvariant(Verb.OPTIONS) || requestedVerb.EqualsInvariant(Verb.HEAD) ) ) ) { verb = requestedVerb; } // check if an origin was specified request.Headers.DreamOrigin = uri.GetParam(DreamInParam.ORIGIN, request.Headers.DreamOrigin); // check if a public uri is supplied XUri publicUri = XUri.TryParse(uri.GetParam(DreamInParam.URI, null) ?? request.Headers.DreamPublicUri); XUri transport = XUri.TryParse(request.Headers.DreamTransport) ?? uri.WithoutCredentialsPathQueryFragment(); if(publicUri == null) { // check if request is local if(transport.Scheme.EqualsInvariantIgnoreCase("local")) { // local:// uris with no public-uri specifier default to the configured public-uri publicUri = _publicUri; } else { // check if the request was forwarded through Apache mod_proxy string proxyOverride = uri.GetParam(DreamInParam.HOST, null); if(string.IsNullOrEmpty(proxyOverride)) { proxyOverride = request.Headers.ForwardedHost; } string serverPath = string.Join("/", transport.Segments); if(proxyOverride != null) { // request used an override, append path of public-uri serverPath = string.Join("/", _publicUri.Segments); } // set the uri scheme based-on the incoming scheme and the override header string scheme = transport.Scheme; if("On".EqualsInvariantIgnoreCase(request.Headers.FrontEndHttps ?? "")) { scheme = Scheme.HTTPS; } scheme = uri.GetParam(DreamInParam.SCHEME, scheme); // set the host port string hostPort = proxyOverride ?? request.Headers.Host ?? uri.HostPort; publicUri = new XUri(string.Format("{0}://{1}", scheme, hostPort)).AtPath(serverPath); } request.Headers.DreamPublicUri = publicUri.ToString(); } // set host header request.Headers.Host = publicUri.HostPort; // convert incoming uri to local:// XUri localFeatureUri = uri.ChangePrefix(uri.WithoutPathQueryFragment(), _localMachineUri); // check if path begins with public uri path if((transport.Segments.Length > 0) && localFeatureUri.PathStartsWith(transport.Segments)) { localFeatureUri = localFeatureUri.WithoutFirstSegments(transport.Segments.Length); } // check if the path is the application root and whether we have special behavior for that if(localFeatureUri.Path.IfNullOrEmpty("/") == "/") { if(!string.IsNullOrEmpty(_rootRedirect)) { localFeatureUri = localFeatureUri.AtAbsolutePath(_rootRedirect); } else if(IsDebugEnv) { localFeatureUri = localFeatureUri.AtAbsolutePath("/host/services"); } } // find the requested feature List<DreamFeature> features; lock(_features) { features = _features.Find(localFeatureUri); } DreamFeature feature = null; if(features != null) { // TODO (steveb): match the incoming mime-type to the feature's acceptable mime-types (mime-type overloading) // match the request verb to the feature verb foreach(DreamFeature entry in features) { if((entry.Verb == "*") || entry.Verb.EqualsInvariant(verb)) { feature = entry; break; } } // check if this is an OPTIONS request and there is no defined feature for it if(verb.EqualsInvariant(Verb.OPTIONS) && ((feature == null) || feature.Verb.EqualsInvariant("*"))) { // list all allowed methods List<string> methods = new List<string>(); foreach(DreamFeature entry in features) { if(!methods.Contains(entry.Verb)) { methods.Add(entry.Verb); } } methods.Sort(StringComparer.Ordinal.Compare); DreamMessage result = DreamMessage.Ok(); result.Headers.Allow = string.Join(", ", methods.ToArray()); response.Return(result); // decrease counter for external requests EndRequest(completion, uri, request); return response; } } // check if a feature was found if(feature == null) { DreamMessage result; // check if any feature was found if((features == null) || (features.Count == 0)) { string msg = verb + " URI: " + uri.ToString(false) + " LOCAL: " + localFeatureUri.ToString(false) + " PUBLIC: " + publicUri + " TRANSPORT: " + transport; _log.WarnMethodCall("ProcessRequest: feature not found", msg); result = DreamMessage.NotFound("resource not found"); } else { string msg = verb + " " + uri.ToString(false); _log.WarnMethodCall("ProcessRequest: method not allowed", msg); List<string> methods = new List<string>(); foreach(DreamFeature entry in features) { if(!methods.Contains(entry.Verb)) { methods.Add(entry.Verb); } } methods.Sort(StringComparer.Ordinal.Compare); result = DreamMessage.MethodNotAllowed(methods.ToArray(), "allowed methods are " + string.Join(", ", methods.ToArray())); } response.Return(result); // decrease counter for external requests EndRequest(completion, uri, request); return response; } // add uri to aliases list if(_memorizeAliases) { lock(_aliases) { _aliases[transport] = transport; _aliases[publicUri] = publicUri; } } // create context DreamContext context = new DreamContext(this, verb, localFeatureUri, feature, publicUri, _publicUri, request, CultureInfo.InvariantCulture, GetRequestLifetimeScopeFactory(feature.Service)); // attach request id to the context context.SetState(DreamHeaders.DREAM_REQUEST_ID, request.Headers.DreamRequestId); // add user to context context.User = user; // build linked-list of feature calls var chain = new Result<DreamMessage>(TimeSpan.MaxValue, TaskEnv.Current).WhenDone(result => { // extract message DreamMessage message; if(result.HasValue) { message = result.Value; } else if(result.Exception is DreamAbortException) { message = ((DreamAbortException)result.Exception).Response; } else if(result.Exception is DreamCachedResponseException) { message = ((DreamCachedResponseException)result.Exception).Response; } else { _log.ErrorExceptionFormat(response.Exception, "Failed Feature '{0}' Chain [{1}:{2}]: {3}", feature.MainStage.Name, verb, localFeatureUri.Path, response.Exception.Message ); message = DreamMessage.InternalError(result.Exception); } // decrease counter for external requests EndRequest(completion, uri, request); // need to manually dispose of the context, since we're already attaching and detaching it by hand to TaskEnvs throughout the chain if(response.IsCanceled) { _log.DebugFormat("response for '{0}' has already returned", context.Uri.Path); response.ConfirmCancel(); ((ITaskLifespan)context).Dispose(); } else { ((ITaskLifespan)context).Dispose(); response.Return(message); } }); for(int i = feature.Stages.Length - 1; i >= 0; --i) { var link = new DreamFeatureChain(feature.Stages[i], i == feature.MainStageIndex, context, chain, (i > 0) ? feature.Stages[i - 1].Name : "first"); chain = new Result<DreamMessage>(TimeSpan.MaxValue, TaskEnv.Current).WhenDone(link.Handler); } // kick-off new task AsyncUtil.Fork( () => chain.Return(request), TaskEnv.New(TimerFactory), new Result(TimeSpan.MaxValue, response.Env).WhenDone(res => { if(!res.HasException) { return; } _log.ErrorExceptionFormat(res.Exception, "handler for {0}:{1} failed", context.Verb, context.Uri.ToString(false)); ((ITaskLifespan)context).Dispose(); // forward exception to recipient response.Throw(res.Exception); // decrease counter for external requests EndRequest(completion, uri, request); }) ); } catch(Exception e) { response.Throw(e); EndRequest(completion, uri, request); } return response; }
private XDoc CreateExportDocumentFromList(string listPath) { if(!File.Exists(listPath)) { throw new ConfigurationException("No such export list: {0}", listPath); } XDoc exportDoc = new XDoc("export"); foreach(string line in File.ReadAllLines(listPath)) { if(string.IsNullOrEmpty(line)) { continue; } if(line.StartsWith("#")) { exportDoc.Comment(line.Remove(0, 1)); continue; } try { string path = line.Trim(); if(!line.StartsWith("/")) { XUri uri = new XUri(path); path = uri.Path; if(StringUtil.EqualsInvariantIgnoreCase("/index.php", path)) { path = uri.GetParam("title"); } } exportDoc.Start("page") .Attr("path", Title.FromUIUri(null, path).AsPrefixedDbPath()) .Attr("recursive", _exportRecursive) .End(); } catch(Exception) { throw new ConfigurationException("Unable to parse uri: {0}", line.Trim()); } } return exportDoc; }
//--- Class Methods --- internal static AMedia New(XUri uri, XDoc config) { // check if the uri is a viddler video if(uri.Scheme.EqualsInvariantIgnoreCase("kaltura")) { if(uri.Segments.Length >= 1) { string entryID = uri.Segments[0]; string partnerID = config["kaltura/partner-id"].AsText; // check if extension is configured for kaltura integration if(!string.IsNullOrEmpty(partnerID)) { bool remix = !(uri.GetParam("edit", null) ?? uri.GetParam("remix", "no")).EqualsInvariantIgnoreCase("no"); // verify that user has permission to remix content on current page if(remix) { Plug dekiApi = GetDekiApi(config); if(dekiApi != null) { try { DekiScriptMap env = DreamContext.Current.GetState<DekiScriptMap>(); string pageid = env.GetAt("page.id").AsString(); string userid = env.GetAt("user.id").AsString(); XDoc users = dekiApi.At("pages", pageid, "allowed").With("permissions", "UPDATE").Post(new XDoc("users").Start("user").Attr("id", userid).End()).ToDocument(); remix = !users[string.Format(".//user[@id='{0}']", userid)].IsEmpty; } catch(Exception e) { _log.Error("unable to verify user permission on page", e); } } } // check if SEO links are explicitly disabled bool seo = !(config["kaltura/seo-links"].AsText ?? "enabled").EqualsInvariantIgnoreCase("disabled"); // determin which UI configuration to use based on user's permissions and embed settings for video string uiConfID = remix ? config["kaltura/uiconf/player-mix"].AsText : config["kaltura/uiconf/player-nomix"].AsText; if(!string.IsNullOrEmpty(uiConfID)) { uri = config["kaltura/server-uri"].AsUri ?? new XUri("http://www.kaltura.com"); uri = uri.At("index.php", "kwidget", "wid", "_" + partnerID, "uiconf_id", uiConfID, "entry_id", entryID); return new KalturaVideo(uri, remix, seo); } } } } return null; }
//--- Class Methods --- internal static AMedia New(XUri uri) { // check if the uri is a google video if(uri.Host.EqualsInvariantIgnoreCase("video.google.com")) { if((null != uri.Params) && (!String.IsNullOrEmpty(uri.GetParam("docid")))) { return new GoogleVideo(new XUri("http://video.google.com/googleplayer.swf?docId=" + uri.GetParam("docid"))); } } return null; }
//--- Class Methods --- internal static AMedia New(XUri uri) { // check if the uri is a youtube video if( uri.Host.EndsWithInvariantIgnoreCase(".youtube.com") || uri.Host.EqualsInvariantIgnoreCase("youtube.com") || uri.Host.EndsWithInvariantIgnoreCase(".youtube-nocookie.com") || uri.Host.EqualsInvariantIgnoreCase("youtube-nocookie.com") ) { if(uri.GetParam("v") != null) { return new YouTubeVideo(uri.WithoutPathQueryFragment().At("v", uri.GetParam("v"))); } if(!ArrayUtil.IsNullOrEmpty(uri.Segments) && (uri.Segments.Length == 2) && (uri.Segments[0].EqualsInvariantIgnoreCase("v"))) { return new YouTubeVideo(uri); } } return null; }