How to validate file size and type in <p:fileUpload mode="simple">? - file-upload

In PrimeFaces 3.4, the <p:fileUpload> attributes sizeLimit and allowTypes doesn't work in case of mode="simple". How can I validate the file size and allowable types?

The mode="simple" generates a plain HTML5 <input type="file"> instead of using jQuery/Ajax file upload, so the client side facilities are limited.
If the webbrowser supports the new HTML5 File API, then you could just make use of it. It adds support for the new accept attribute on <input type="file"> and enables JavaScript to have access to specific file properties such as File#size.
E.g.
<p:fileUpload mode="simple" styleClass="imagesOnlyMax10MB" />
with this JS (using jQuery from PrimeFaces):
$("input[type=file].imagesOnlyMax10MB").attr("accept", "image/*").on("change", function() {
var max = 10 * 1024 * 1024; // 10MB
if (this.files && this.files[0].size > max) {
alert("File too large."); // Do your thing to handle the error.
this.value = null; // Clears the field.
}
});
Otherwise, your best bet is really validating it in the server side. You could use ExternalContext#getMimeType() to get a mime type based on file extension (you can manage all mime types as <mime-mapping> in web.xml; the container's own one has a bunch of default ones).
if (!externalContext.getMimeType(filename).startsWith("image/")) {
// Not an image.
}

Related

How to get full directory path of BlazorInputFile in blazor web assembly

Team,
I have a blazor web assembly app, which upload the file and process it later. However , I would like to know the base path of the file from where it it picked in the machine.
My code goes as follows . Does anyone has idea to get the file path such as "C:\myfile.txt".
With the File object, I cannot achieve the full path, I can access only its memory stream.
<h1>FILE UPLAOD </h1>
<InputFile OnChange="HandleSelection" ></InputFile>
#code
{
string status;
async Task HandleSelection(IFileListEntry[] files)
{
var file = files.FirstOrDefault();
if (file != null)
{
// Just load into .NET memory to show it can be done
// Alternatively it could be saved to disk, or parsed in memory, or similar
var ms = new MemoryStream();
await file.Data.CopyToAsync(ms);
Console.WriteLine(ms);
status = $"Finished loading {file.Size} bytes from {file.Name}";
var content = new MultipartFormDataContent
{
{ new ByteArrayContent(ms.GetBuffer()),"\"upload\"", file.Name}
};
await client.PostAsync("upload", content);
}
}
}
Even if you get the fullpath (C:\myfile.txt") file won't load
by default, all browser has a security mechanism that any local disk file won't be loaded into a website until you disable that security for your website

Enabling binary media types breaks Option POST call (CORS) in AWS Lambda

New to AWS..
We have a .NET Core Microservice running on a serverless aws instance as lambda functions.
Our Controller looks like this
[Route("api/[controller]")]
[ApiController]
public class SomeController : ControllerBase
{
[HttpGet()]
[Route("getsomedoc")]
public async Task<IActionResult> GetSomeDoc()
{
byte[] content;
//UI needs this to process the document
var contentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
contentDisposition.FileName = "File Name";
Response.Headers[HeaderNames.ContentDisposition] = contentDisposition.ToString();
return File(content, "application/octet-stream");
}
[HttpPost()]
[Route("somepost")]
public async Task<IActionResult> SomePost()
{
return null;
}
}
URL's
{{URL}}/getsomedoc
{{URL}}/somepost
We have enabled 'Binary Media Types' in AWS package settings to / for the getsomedoc to work otherwise it was returning the byte array back instead of the file.
But this is breaking our 'somepost' call when UI is accessing the API using
Method: OPTIONS & Access-Control-Request-Method as POST
When we remove the binary media type the 'somepost' starts working.
Looking for suggestions as why this might be happening? and what can we add/remove from gateway to get this fixed.
Well we ended up resolving this in a strange way.
Added two gateways for the lambda
- on one of them have binary enabled
- Disabled on the other one.
For
getsomedoc - Using the one where binary media types are enabled
postsomedoc - Using the other one
Wish there was a better way!!
I have found this same behavior with my API. While looking everywhere for some help, I found a few things that address the issue:
Basically, this bug report says the problem is having CORS enabled while also using the generic Binary Media Type "*/*". Apparently the OPTIONS method gets confused by this. They discuss this in terms of using Serverless, but it should apply to using the console or other ways of interacting with AWS.
They link to a possible solution: you can modify the Integration Response of the OPTIONS method - change the Mapping Template's Content-Type to an actual binary media type, like image/jpeg. They say this allows you to leave the binary media type in Settings as "*/*". This is a little hacky, but at least it is something.
There also was this alternate suggestion in the issues section of this GitHub repo that is a little less hacky. You can set the content handling parameter of the OPTIONS Integration Request to "CONVERT_TO_TEXT"... but you can only do this via CloudFormation or the CLI (not via the console). This is also the recommended solution by some AWS Technicians.
Another possible workaround is to setup a custom Lambda function to handle the OPTIONS request, this way the API gateway may have the "*/*" Binary Media Type.
Create a new lambda function for handling OPTIONS requests:
exports.handler = async (event) => {
const response = {
statusCode: 200,
headers:{
'access-control-allow-origin':'*',
'Access-Control-Allow-Headers': 'access-control-allow-origin, content-type, access-control-allow-methods',
'Access-Control-Allow-Methods':"GET,POST,PUT,DELETE,OPTIONS"
},
body: JSON.stringify("OK")
};
return response;
};
In your API Gateway OPTION method, change the integration type from Mock to Lambda Function.
Make sure to check 'Use Lambda proxy integration'
Select the correct region and point to the created Lambda Function
This way any OPTIONS request made from the browser will trigger the Lambda function and return the custom response.
Be aware this solution might involve costs.

how to retrieve the liferay authToken using velocity

How to I retrieve the authToken for the current page in Liferay Velocity?
For example, in the HTML code there is the following but I do not know what is the coding to retrieve the corresponding value 0H4mKLWq for the auth Token assigned for the current session of the webpage.
The following is the string in the HTML:
Liferay.authToken="0H4mKLWq";
In Freemarker you can do it using static method:
<#assign authTokenUtil = staticUtil["com.liferay.portal.security.auth.AuthTokenUtil"] />
${authTokenUtil.getToken(request)}
In velocity you can call static methods by adding AuthTokenUtil to context
or loading it using Class.forName
#set($authTokenUtil=$String.class.forName('com.liferay.portal.security.auth.AuthTokenUtil'))

ABCpdf - Download PDF with .NET Core 2.1 - HttpContext/HttpResponse

I'm creating a web page that will allow the user to download a report as a PDF using ABCpdf. But reading the documentation, the only options I see are by using doc.Save("test.pdf") (which saves the file on the server that is hosting the application) or using 'HttpContext.Current.ApplicationInstance.CompleteRequest();' (which saves on the client side, which is what I want, but HttpContext.Current is not available on .NET Core.
The band-aid solution I have is with the doc.Save(), I would save the file on the server then send a link to the view which then downloads it from the server. A potential risk I can think of is making sure to 'clean up' after the download has commenced on the server.
Is there a alternative/.NET Core equivalent for HttpContext.Current and also HttpResponse?
Here is the code that I'd like to make work:
byte[] theData = doc.GetData();
Response.ClearHeaders();
Response.ClearContent();
Response.Expires = -1000;
Response.ContentType = "application/pdf";
Response.AddHeader("content-length", theData.Length.ToString());
Response.AddHeader("content-disposition", "attachment; filename=test.pdf");
Response.BinaryWrite(theData);
HttpContext.Current.ApplicationInstance.CompleteRequest();
Errors I get (non-verbose)
'HttpResponse' does not contain a definition for 'ClearHeaders'
'HttpResponse' does not contain a definition for 'ClearContent'
'HttpResponse' does not contain a definition for 'Expires'
'HttpResponse' does not contain a definition for 'AddHeader'
'HttpResponse' does not contain a definition for 'BinaryWrite'
'HttpContext' does not contain a definition for 'Current'
I've updated this answer to something that actually works!
GetStream does what you need, however to facilitate a file download in .NET Core it would be far easier if you create a controller as described in https://learn.microsoft.com/en-us/aspnet/core/tutorials/first-web-api?view=aspnetcore-2.1.
Then you can create a route controller to serve the file from the stream as shown in Return PDF to the Browser using Asp.net core.
So your controller would look something like:
[Route("api/[controller]")]
public class PDFController : Controller {
// GET: api/<controller>
[HttpGet]
public IActionResult Get() {
using (Doc theDoc = new Doc()) {
theDoc.FontSize = 96;
theDoc.AddText("Hello World");
Response.Headers.Clear();
Response.Headers.Add("content-disposition", "attachment; filename=test.pdf");
return new FileStreamResult(theDoc.GetStream(), "application/pdf");
}
}
}
Out of curiosity I just mocked this up and it does work - serving the PDF direct to the browser as download when you go to the URL localhost:port/api/pdf. If you make the content-disposition "inline; filename=test.pdf" it will show in the browser and be downloadable as test.pdf.
More information on the GetStream method here: https://www.websupergoo.com/helppdfnet/default.htm?page=source%2F5-abcpdf%2Fdoc%2F1-methods%2Fgetstream.htm

Upload a file MVC 4 Web API .NET 4

I'm using the version of MVC that shipped with Visual Studio 2012 express. (Microsoft.AspNet.Mvc.4.0.20710.0)
I assume this is RTM version.
I've found plenty of examples online which all use this code:
public Task<HttpResponseMessage> PostFormData()
{
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = HttpContext.Current.Server.MapPath("~/App_Data");
var provider = new MultipartFormDataStreamProvider(root);
// Read the form data and return an async task.
var task = Request.Content.ReadAsMultipartAsync(provider).
ContinueWith<HttpResponseMessage>(t =>
{
if (t.IsFaulted || t.IsCanceled)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, t.Exception);
}
// This illustrates how to get the file names.
foreach (MultipartFileData file in provider.FileData)
{
Trace.WriteLine(file.Headers.ContentDisposition.FileName);
Trace.WriteLine("Server file path: " + file.LocalFileName);
}
return Request.CreateResponse(HttpStatusCode.OK);
});
return task;
}
But this code always ends up in continueWith where t.IsFaulted == true. The exception reads:
Unexpected end of MIME multipart stream. MIME multipart message is not
complete.
Here is my client form. NOthing fancy, I want to do jquery form pluging for ajax upload, but I can't even get this way to work.
<form name="uploadForm" method="post" enctype="multipart/form-data" action="api/upload" >
<input type="file" />
<input type="submit" value="Upload" />
</form>
I've read that it is caused by the parser expecting /CR /LF at the end of each message, and that bug has been fixed in June.
What I cannot figure out is, if it was really fixed, why isn't it included this version of MVC 4? Why do so many examples on the internet tout that this code works when it does not in this version of MVC 4?
You are missing a name attribute on your file input.
<form name="uploadForm" method="post" enctype="multipart/form-data" action="api/upload" >
<input name="myFile" type="file" />
<input type="submit" value="Upload" />
</form>
Inputs without it will not get submitted by the browser. So your formdata is empty resulting in IsFaulted being asserted.