We have moved to GitHub Issues
You are viewing the read-only archive of Umbraco's issue tracker. To create new issues, please head over to GitHub Issues.
Make sure to read the blog posts announcing the move for more information.
Created by simone chiaretta 20 Oct 2016, 15:08:46 Updated by Alessandro Calzavara 06 Jun 2017, 10:28:46
I had an umbraco project with the default configuration <add key="virtualRoot" value="~/media/" />
I started using the site and adding some media files.
Then I realized it was a better idea to store media files on a NAS as it would have been backed-up and not take up space on the application server.
So I changed the configuration to be
<add key="rootPath" value="\\ServerName\Storage\UmbracoMedia" />
<add key="rootUrl" value="/UmbracoMedia" />
Now I cannot edit the pre-existing files anymore as I get the following error when pressing the save button:
An error occured
File '/media/1051/1010562_10151560546423881_2024154195_n.jpg' is outside this filesystem's root.
EXCEPTION DETAILS
Umbraco.Core.IO.FileSecurityException: File '/media/1051/1010562_10151560546423881_2024154195_n.jpg' is outside this filesystem's root.
STACKTRACE
at Umbraco.Core.IO.PhysicalFileSystem.GetFullPath(String path)
at Umbraco.Web.MediaPropertyExtensions.PopulateFileMetaDataProperties(IContentBase content, IImagingAutoFillUploadField uploadFieldConfigNode, String relativeFilePath)
at Umbraco.Web.PropertyEditors.ImageCropperPropertyEditor.AutoFillProperties(IContentBase model)
at Umbraco.Web.PropertyEditors.ImageCropperPropertyEditor.MediaServiceSaving(IMediaService sender, SaveEventArgs`1 e)
at Umbraco.Core.Events.TypedEventHandler`2.Invoke(TSender sender, TEventArgs e)
at Umbraco.Core.Events.EventExtensions.IsRaisedEventCancelled[TSender,TArgs](TypedEventHandler`2 eventHandler, TArgs args, TSender sender)
at Umbraco.Core.Services.MediaService.Umbraco.Core.Services.IMediaServiceOperations.Save(IMedia media, Int32 userId, Boolean raiseEvents)
at Umbraco.Web.Editors.MediaController.PostSave(MediaItemSave contentItem)
at lambda_method(Closure , Object , Object[] )
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters)
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments)
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()
The only way to fix the problem is by manually updating the DB tables and changing the url of the media file.
Not sure how this should be handled: I think all files should be moved to the new url automatically, not keeping pre-existing files on a URL and new files in another.
This error happens even after moving the files manually to the new rootPath
.
I think the exception is correctly thrown, but there must be an easier way to re-evaluate the url of media files after a change of location
Hi Simone,
I think what you are trying to do is actually not possible. The default file system provider: https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/src/Umbraco.Web.UI/config/FileSystemProviders.config is only meant to be used with paths that exist within the web application. This means that the URLs returned for media are the web file locations of where they exists. If you point this to somewhere outside of your web root, then there is no way that the URL will work - these are not proxied URLs, these are just the locations of your media on disk that are served by IIS.
The source for this is here: https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/src/Umbraco.Core/IO/PhysicalFileSystem.cs
So even if you specify an absolute location, that location would still need to exist within your web root so that it can return a URL to fetch your media that IIS knows about.
If you want to continue down this path, you have 2 choices:
media
virtual folder for your website that points to your NAS and revert your changes to the file system provider config and use the defaultsIFileSystem
to deal with this, this would mean that the URL you return would need to be a proxy URL to return the actual media from outside of your web root.Well.. actually, apart from the problem with the pre-existing files, specifying a folder on a NAS and have it served from another url works fine.
What would be reason to have the additional 2 properties (rootPath
and rootUrl
) otherwise?
I think it just needs better documentation :) I've sent a PR on the configuration for the filesystemprovider.config
So if you have a rootPath outside of the web root, how is it serving media files via IIS? i.e. what is the URL it uses?
At the moment I tried with just another path (/UmbracoMedia
) configured as virtual folder, but the way it works I suppose it can work also when specifying a complete different domain. I'll give it a try and let you know.
Just made the test:
<Provider alias="media" type="Umbraco.Core.IO.PhysicalFileSystem, Umbraco.Core">
<Parameters>
<add key="rootPath" value="C:\Temp\UmbracoMedia" />
<add key="rootUrl" value="//media.whatever.com" />
</Parameters>
</Provider>
With http://media.whatever.com
configured as separate website on top of C:\Temp\UmbracoMedia
.
Can add new files and edit them, and media files are served correctly from http://media.whatever.com/1058/summits.png
If I also go back to the DB and edit the path of pre-existing media, I can edit them without exception happening and they are displayed from the new absolute url
So everything works even when the path is outside of root of the website
In my scenario, I really want just bypass this exception and just replace the broken media file (upload field), so why not give us the ability to replace the broken media even if Umbraco can't delete the file.
@simonech quick Q, when you "edit the path of pre-existing media" can you give me an example of what you changed exactly? The error ("outside of the filesystem root") indicates that the physical file system's root is eg "c:/foo/bar" and we are trying to read a file at eg "c:/some/place" - which should obviously be illegal for security reasons. But I'm not sure why changing the file system's root would case an issue.
@zpqrtbnk The error happens before I edit the path of pre-existing media.
If I just change the config of the provider, the full relative path is stored in the imagesrc property, so, in my example, they where /media/...
while the provider now points to /UmbracoMedia
.
If I manually update the property to reflect the new root, it works fine.
Is that what you were asking?
More or less ;-) The original property value would be "/media/1234/image.jpg" - what do you need to change this into so it works?
I had changed the config to
<add key="rootPath" value="\\ServerName\Storage\UmbracoMedia" />
<add key="rootUrl" value="/UmbracoMedia" />
So /media/1234/image.jpg
had to become /UmbracoMedia/1234/image.jpg
Actually I didn't try setting rootUrl
to media
... could have worked indeed
The change from "/media/1234/..." to "/UmbracoMedia/1234/..." was what I was looking for - now need to check but yes, since "/media" is there, it cannot go away so easily so maybe \Server\Storage\media and /media would do the trick.
If fixed it by just mapping the remote folder as virtual folder under IIS. Everything works fine.
Root cause would be:
The MediaFileSystem handles virtual file paths eg "1234/image.jpg" and depending on how it is configured, it maps those virtual paths to a physical path eg "c:/path/to/root/media/1234/image.jpg" which is where the file is actually stored, and to a url eg "/media/1234/image.jpg". In ''theory'' changing the "/media" part in the url in config ''should'' work. However, what we store in eg property values is the full url "/media/1234/image.jpg" and not the virtual path "1234/image.jpg" -- meaning that if you change the configuration, the "/media" part is still there and breaks everything.
Ideally we should only store the virtual path in property values, but that's not going to change in the near future due to backward compatibility.
So... whenever someone ''changes'' the configuration ... either make sure the "/media" part does not change, or use a virtual folder in IIS, or update all the media paths in property values.
I had sent a PR to update the documentation, so now there is a note in the filesysemprovider doc page that explains what you need to do to avoid the issue :) https://our.umbraco.org/Documentation/Reference/Config/fileSystemProviders/
hi simone - what version is your documentation compatible with? Should it work for 7.4.3? thanks
is this earlier option mentioned by Shannon the simplest? thanks "Change your IIS setup and just create a media virtual folder for your website that points to your NAS and revert your changes to the file system provider config and use the defaults"
@shearer3000 Yes it's really easy to set the virtual folder and it just works, even with the old media (if you moved them to the NAS). Just check that the permissions are right (or set them via pass-through authentication)
Priority: Normal
Type: Bug
State: Workaround posted
Assignee:
Difficulty: Normal
Category:
Backwards Compatible: True
Fix Submitted:
Affected versions: 7.4.2, 7.4.3, 7.5.1, 7.5.2, 7.5.3
Due in version:
Sprint: Sprint 57
Story Points:
Cycle: