private static string CachedWebGet(XUri uri, double?ttl, bool?nilIfMissing)
        {
            // fetch message from cache or from the web
            string result;

            lock (_webTextCache) {
                if (_webTextCache.TryGetValue(uri, out result))
                {
                    return(result);
                }
            }

            // do the web request
            Result <DreamMessage> response = new Result <DreamMessage>();

            Plug.New(uri).WithTimeout(DEFAULT_WEB_TIMEOUT).InvokeEx("GET", DreamMessage.Ok(), response);
            DreamMessage message = response.Wait();

            try {
                // check message status
                if (!message.IsSuccessful)
                {
                    if (nilIfMissing.GetValueOrDefault())
                    {
                        return(null);
                    }
                    return(message.Status == DreamStatus.UnableToConnect
                        ? string.Format("(unable to fetch text document from uri [status: {0} ({1}), message: \"{2}\"])", (int)message.Status, message.Status, message.ToDocument()["message"].AsText)
                        : string.Format("(unable to fetch text document from uri [status: {0} ({1})])", (int)message.Status, message.Status));
                }

                // check message size
                Result resMemorize = message.Memorize(InsertTextLimit, new Result()).Block();
                if (resMemorize.HasException)
                {
                    return(nilIfMissing.GetValueOrDefault() ? null : "(text document is too large)");
                }

                // detect encoding and decode response
                var stream   = message.AsStream();
                var encoding = stream.DetectEncoding() ?? message.ContentType.CharSet;
                result = encoding.GetString(stream.ReadBytes(-1));
            } finally {
                message.Close();
            }

            // start timer to clean-up cached result
            lock (_webTextCache) {
                _webTextCache[uri] = result;
            }
            double timeout = Math.Min(60 * 60 * 24, Math.Max(ttl ?? MinCacheTtl, 60));

            TaskEnv.ExecuteNew(() => TaskTimer.New(TimeSpan.FromSeconds(timeout), timer => {
                lock (_webTextCache) {
                    _webTextCache.Remove((XUri)timer.State);
                }
            }, uri, TaskEnv.None));
            return(result);
        }
        public Yield PutFile(DreamContext context, DreamMessage request, Result <DreamMessage> response)
        {
            // Retrieve the file
            PageBE     page;
            string     userFileName;
            ResourceBE file = GetAttachmentFromUrl(context, false, out page, false, false);

            // If the file does not exist, attempt to retrieve the page
            if (null == file)
            {
                if (null == page)
                {
                    if (null != DreamContext.Current.GetParam <string>("fileid"))
                    {
                        throw new AttachmentNotFoundException();
                    }
                    page = PageBL_GetPageFromUrl(context, true);
                }
                userFileName = GetFilenameFromPathSegment(DreamContext.Current.GetParam <string>("filename"));
            }
            else
            {
                string fileNameParam = DreamContext.Current.GetParam("filename", null);
                if (fileNameParam == null)
                {
                    userFileName = file.Name;
                }
                else
                {
                    userFileName = GetFilenameFromPathSegment(fileNameParam);
                }
            }

            // Retrieve the file description
            string userDescription = context.GetParam("description", string.Empty);

            if (userDescription.Length > AttachmentBL.MAX_DESCRIPTION_LENGTH)
            {
                userDescription = userDescription.Substring(0, AttachmentBL.MAX_DESCRIPTION_LENGTH);
            }

            // Validate the page
            PageBL.AuthorizePage(DekiContext.Current.User, Permissions.UPDATE, page, false);

            // Get entire stream so it can be reused
            var        isMSWebDAV        = MSWEBDAV_USER_AGENT_REGEX.IsMatch(request.Headers.UserAgent ?? string.Empty);
            ResourceBE savedFileRevision = AttachmentBL.Instance.AddAttachment(file, request.AsStream(), request.ContentLength, request.ContentType, page, userDescription, userFileName, isMSWebDAV);

            // report an error on failure, and don't redirect
            if (savedFileRevision == null)
            {
                throw new AttachmentUploadSaveFatalException();
            }
            response.Return(DreamMessage.Ok(AttachmentBL.Instance.GetFileXml(savedFileRevision, true, null, null)));
            yield break;
        }
        internal Yield PutSiteLogo(DreamContext context, DreamMessage request, Result <DreamMessage> response)
        {
            //Confirm image type
            if (!new MimeType("image/*").Match(request.ContentType))
            {
                throw new SiteImageMimetypeInvalidArgumentException();
            }
            try {
                //Save file to storage provider
                DekiContext.Current.Instance.Storage.PutSiteFile(LOGO_LABEL, new StreamInfo(request.AsStream(), request.ContentLength, request.ContentType));
                ConfigBL.SetInstanceSettingsValue(ConfigBL.UI_LOGO_UPLOADED, "true");
            } catch (Exception x) {
                DekiContext.Current.Instance.Log.Warn("Failed to save logo to storage provider", x);
                ConfigBL.DeleteInstanceSettingsValue(ConfigBL.UI_LOGO_UPLOADED);
                throw;
            }

            StreamInfo file = DekiContext.Current.Instance.Storage.GetSiteFile(LOGO_LABEL, false);

            if (file != null)
            {
                StreamInfo thumb = AttachmentPreviewBL.BuildThumb(file, FormatType.PNG, RatioType.UNDEFINED, DekiContext.Current.Instance.LogoWidth, DekiContext.Current.Instance.LogoHeight);
                if (thumb != null)
                {
                    DekiContext.Current.Instance.Storage.PutSiteFile(LOGO_LABEL, thumb);
                }
                else
                {
                    DekiContext.Current.Instance.Log.WarnMethodCall("PUT:site/logo", "Unable to process logo through imagemagick");
                    DekiContext.Current.ApiPlug.At("site", "logo").Delete();
                    throw new SiteUnableToProcessLogoInvalidOperationException();
                }
            }
            else
            {
                DekiContext.Current.Instance.Log.WarnMethodCall("PUT:site/logo", "Unable to retrieve saved logo");
            }
            response.Return(DreamMessage.Ok());
            yield break;
        }
 public ResourceContentBE CreateDbSerializedContentFromRequest(DreamMessage request)
 {
     return(CreateDbSerializedContentFromStream(request.AsStream(), request.ContentLength, request.ContentType));
 }