Example #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;
        }
Example #2
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;
        }
        public Yield GetSiteLogo(DreamContext context, DreamMessage request, Result<DreamMessage> response) {

            DreamMessage responseMsg = null;
            DateTime modified = DekiContext.Current.Instance.Storage.GetSiteFileTimestamp(LOGO_LABEL);
            try {
                if(modified != DateTime.MinValue) {
                    if(request.CheckCacheRevalidation(modified)) {
                        responseMsg = DreamMessage.NotModified();
                    }
                }

                if(responseMsg == null) {
                    StreamInfo file = DekiContext.Current.Instance.Storage.GetSiteFile(LOGO_LABEL, false);
                    if(file != null) {
                        responseMsg = DreamMessage.Ok(MimeType.PNG, file.Length, file.Stream);

                        //Build the content disposition headers
                        responseMsg.Headers.ContentDisposition = new ContentDisposition(true, file.Modified ?? DateTime.UtcNow, null, null, "logo.png", file.Length);

                        //Set caching headers
                        responseMsg.SetCacheMustRevalidate(modified);
                    } else {
                        responseMsg = DreamMessage.NotFound("Logo has not been uploaded");
                    }
                }
            } catch {
                if(responseMsg != null) {
                    responseMsg.Close();
                }
                throw;
            }
            response.Return(responseMsg);
            yield break;
        }
        public Yield GetFile(DreamContext context, DreamMessage request, Result<DreamMessage> response) {
            PageBE parentPage = null;
            DreamMessage responseMsg = null;
            AttachmentBE fileRevision = GetAttachment(request, Permissions.READ, true, false, out parentPage);

            if(fileRevision.IsHidden) {
                PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN);
            }

            // check if only file information is requested
            if(context.Verb == Verb.HEAD) {
                response.Return(new DreamMessage(DreamStatus.Ok, null, fileRevision.MimeType, (long)fileRevision.Size, Stream.Null));
                yield break;
            }
            try {
                if(request.CheckCacheRevalidation(fileRevision.Timestamp)) {
                    responseMsg = DreamMessage.NotModified();
                }
                if (responseMsg == null) {

                    #region Preview related parameter parsing
                    string sFormat = context.GetParam("format", string.Empty);
                    string sRatio = context.GetParam("ratio", string.Empty);
                    uint height = context.GetParam<uint>("height", 0);
                    uint width = context.GetParam<uint>("width", 0);
                    string cachedSize = context.GetParam("size", string.Empty);

                    // check 'ratio' parameter
                    RatioType ratio = RatioType.UNDEFINED;
                    if (!string.IsNullOrEmpty(sRatio)) {
                        switch (sRatio.ToLowerInvariant().Trim()) {
                        case "var":
                        case "variable":
                            ratio = RatioType.VARIABLE;
                            break;
                        case "fixed":
                            ratio = RatioType.FIXED;
                            break;
                        default:
                            throw new DreamBadRequestException(DekiResources.INVALID_FILE_RATIO);
                        }
                    }

                    // check 'size' parameter
                    SizeType size = SizeType.UNDEFINED;
                    if (!string.IsNullOrEmpty(cachedSize) && !SysUtil.TryParseEnum(cachedSize.Trim(), out size)) {
                        throw new DreamAbortException(DreamMessage.BadRequest(DekiResources.INVALID_FILE_SIZE));
                    }

                    // check 'format' parameter
                    FormatType format = FormatType.UNDEFINED;
                    if(!string.IsNullOrEmpty(sFormat) && !SysUtil.TryParseEnum(sFormat.Trim(), out format)) {
                        throw new DreamBadRequestException(DekiResources.INVALID_FILE_FORMAT);
                    }
                    #endregion

                    //if any preview related parameters are set, do preview logic. Otherwise return the file
                    StreamInfo file = null;
                    if((size != SizeType.UNDEFINED && size != SizeType.ORIGINAL) ||
                        ratio != RatioType.UNDEFINED ||
                        format != FormatType.UNDEFINED ||
                        height != 0 ||
                        width != 0
                    ) {
                        file = AttachmentPreviewBL.RetrievePreview(fileRevision, height, width, ratio, size, format);
                    } else {
                        file = DekiContext.Current.Instance.Storage.GetFile(fileRevision, SizeType.ORIGINAL, true);
                    }

                    // prepare response
                    if(file == null) {
                        throw new DreamInternalErrorException(string.Format(DekiResources.COULD_NOT_RETRIEVE_FILE, fileRevision.ResourceId, fileRevision.Revision));
                    }

                    if(file.Uri != null) {
                        responseMsg = DreamMessage.Redirect(file.Uri);
                    } else {
                        bool inline = fileRevision.ImageHeight.HasValue;

                        // see if we can use the MimeType map for allowing inlining
                        if(!inline) {

                            // if IE inline security is not disabled
                            bool isIE = false;
                            if(!DekiContext.Current.Instance.EnableUnsafeIEContentInlining) {

                                // check the user agent to see if we're dealing with IE
                                isIE = MSIE_USER_AGENT_REGEX.IsMatch(request.Headers.UserAgent ?? string.Empty);
                            }

                            // see if the mime-type could allow inlining
                            inline = DekiContext.Current.Instance.MimeTypeCanBeInlined(fileRevision.MimeType);
                            if(inline && isIE) {

                                // check whether the creator of the file had unsafecontent permission, to override IE security
                                IList<AttachmentBE> revisions = AttachmentBL.Instance.GetResourceRevisions(fileRevision.ResourceId, ResourceBE.ChangeOperations.CONTENT, SortDirection.DESC, 1);
                                UserBE lastContentEditor = UserBL.GetUserById(revisions[0].UserId);
                                inline = PermissionsBL.IsUserAllowed(lastContentEditor, parentPage, Permissions.UNSAFECONTENT);
                            }
                        }
                        responseMsg = DreamMessage.Ok(fileRevision.MimeType, file.Length, file.Stream);
                        responseMsg.Headers["X-Content-Type-Options"] = "nosniff";
                        responseMsg.Headers.ContentDisposition = new ContentDisposition(inline, fileRevision.Timestamp, null, null, fileRevision.Name, file.Length, request.Headers.UserAgent);

                        // MSIE6 will delete a downloaded file before the helper app trying to use it can get to it so we
                        //have to do custom cache control headers for MSIE6 so that the file can actually be opened
                        if(MSIE6_USER_AGENT_REGEX.IsMatch(request.Headers.UserAgent ?? string.Empty)) {
                            responseMsg.Headers["Expires"] = "0";
                            responseMsg.Headers.Pragma = "cache";
                            responseMsg.Headers.CacheControl = "private";
                        } else {
                            responseMsg.SetCacheMustRevalidate(fileRevision.Timestamp);
                        }
                    }
                }
            } catch {
                if(responseMsg != null) {
                    responseMsg.Close();
                }
                throw;
            }
            response.Return(responseMsg);
            yield break;
        }