Пример #1
0
        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;
        }
Пример #2
0
        //--- 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;
        }
Пример #3
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;
        }
Пример #4
0
 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;
 }
Пример #5
0
            //--- 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;
            }
Пример #6
0
            //--- 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;
            }
Пример #7
0
            //--- 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;
            }