Allowing full file path in URI for Web API call

By : Tomuke
Source: Stackoverflow.com
Question!

I am currently working on a 'download file' implementation using Web API 2.

However, as the files that can be downloaded are NOT stored in the database, I am passing in the full file path as the parameter for identification.

It seems the problem with this approach is that the filePath contains characters that are invalid for a URI... Has anyone got any suggestions to resolve this or an alternate approach?

Download file method:

    [HttpGet]
    [Route("Files/{*filePath}")]
    public HttpResponseMessage Get([FromUri]string filePath)
    {
        try
        {
            var file = new FileInfo(filePath);

            byte[] bytes = System.IO.File.ReadAllBytes(filePath);

            var result = Request.CreateResponse(HttpStatusCode.OK);

            result.Content = new ByteArrayContent(bytes);
            result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
            result.Content.Headers.ContentDisposition.FileName = file.Name + file.Extension;

            return result;

        }
        catch(Exception ex)
        {
            return Request.CreateResponse(HttpStatusCode.InternalServerError, ex);
        }
    }
By : Tomuke


Answers

Requiring the client to put the full path in the URI (even if it were encoded so that it only contains valid characters for the URI) implies that you may be publishing these paths somewhere... this is not a great idea for a few reasons:

  1. Security - full Path Disclosure and associated Relative Path Traversal
    1. i.e. what's to stop someone passing in the path to a sensitive file (e.g. your web.config file) and potentially obtaining information that could assist with attacking your system?
  2. Maintainability
    1. Clients may maintain a copy of a URI for reuse or distribution - what happens if the file paths change? Some related conversation on this topic here: Cool URIs don't change

My suggestion - you don't have to put the files themselves in a database, but put a list of files in a database, and use a unique identifier in the URL (e.g. perhaps a slug or GUID). Look up the identifier in the database to discover the path, then return that file.

This ensures:

  1. Nobody can read a file that you haven't indexed and determined is safe to be downloaded
  2. If you move the files you can update the database and client URIs will not change
  3. And to respond to your original question, you can easily ensure the unique identifier is only made up of URI safe characters

Once you have the database, over time you may also fine it useful to maintain other metadata in the database such as who uploaded the file, when, who downloaded it, and when, etc.



While this is perfectly valid it breaks modularity. A component can style its own root-element:

my-page.component.css

:host{
  background-color: grey;
}

header {
    ...
}

.sticky-footer {
    position: absolute;
}

This will achieve the same thing and contains CSS that's vital to your MyPageComponent in the component.

By : j2L4e


If you have to pass multiple parameter please use class object:

public class PortalClass
{
    public ApplicationModel applicationModel { get; set; }
    public string user_id { get; set; }
    public string id { get; set; }
    public object pageCollection { get; set; }
}

public object GetApplication(PortalClass data)
{
    JsonSerializerSettings settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All, PreserveReferencesHandling = PreserveReferencesHandling.None };
    var myObject=JsonConvert.DeserializeObject<PageCollection>(data.pageCollection.ToString(), settings)
    return null;
}

Client Side:

var data = {
    user_id: userId,
    id: id
};

http.post(url, data).then(
   function (response) {

}, function (err) {
   callback.reject(err);
});


This video can help you solving your question :)
By: admin