I want to be able to check for the size of uploaded files.
And if it exceeds a limit, i want to be able to issue my REST API errors.
I have this code:
app.config['MAX_CONTENT_LENGTH'] = 1024 * 1024
If you try to upload a file that is larger than 1MB, the application will now refuse it.
But this does not give me a lot of control, in terms of the REST API message that my app will generate.
So how can i check for max size of uploaded file, and issue my personal message, along with an HTTP status code, whenever that happens?
EDIT:
Now i receive this on my curl terminal (client side)
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>413 Request Entity Too Large</title>
<h1>Request Entity Too Large</h1>
<p>The data value transmitted exceeds the capacity limit.</p>
While i would like to send something like this (server side code):
return make_response(json.dumps({'error_message': 'file size too large'}), 413)
Solved it with this:
#app.errorhandler(413)
def request_entity_too_large(error):
return make_response(json.dumps({'error_message': 'file size too large'}), 413)
Added error handler
Related
I have a Java API endpoint that returns an excel (I am using content-disposition=Content-Disposition","attachment; filename=Audit.Report.xlsx).
I have another Angular-Node JS application that needs to consume this API and when the user clicks on a link, it should pull the excel and display a pop-up asking them the location to save the document. I am at a loss as to how I can do this. I tried doing the following on the server side though,
Server Code:
getAuditReport = function ( req, resp ) {
var numberOfMonths = req.query.numberOfMonths;
console.log('In first method ' + numberOfMonths);
var auditReportPromise = this.getAuditReportXlPromise ( numberOfMonths );
auditReportPromise.then ( function ( data ) {
resp.headers('Content-Disposition: attachment; filename="audit.report_'+ new Date() + '".xls"');
resp.ContentType = "application/vnd.ms-excel";
resp.status ( 200 ).send ( data );
} ).catch ( function ( err ) {
resp.status ( 500 ).send ( err );
} );
}
The getAuditReportXlPromise method returns a promise to invoke the get method of the Java API. On invoking this API via a browser, I get the excel content on the browser rather than a prompt requesting me to save the document somewhere.
Can someone suggest what's wrong here, and what I need to do on the client side for the click functionality to work.
Update 1:
Following is the code from the HTML
<a id='10051' href="{{url}}" target=_blank class="ok-white-text">
Download Report
</a>
Based on the duration the user selects, I'm building the URL - this is getting built correctly.
If your API provides the file using GET then you should be able to download the file in a simple way by just setting a link to that API (i.e. an anchor containing the link like Download).
In this scenario the browser will take over the download process (i.e. locating the folder to download to, if configured to do so).
If you want to process the file on client side, then you need to transfer it in a binary mode as suggested by multiple answer for this question.
To answer how I did manage to get around this,
Client Side:
In the component, I did the following - wrote a method on clicking the button that contains a window.open to the url - something like,
window.open("<path to the java api>", '_blank');
The link like I mentioned above was a java api that was already generating the excel file.
I have a file upload system in sails.js app. I want to process the uploads before saving them in the server. My form on the client side allows multiple file uploads. Now on the server side how do I know how many files were sent?
For example I can find the total bytes to be expected from the upload using the following:
req._fileparser.form.bytesExpected
However, I couldn't find something similar that helps me find the total number of files sent to the server.
Also the above code req._fileparser.form.bytesExpected, is there a better way to get total combined file size of the files sent through the upload form by the client?
In the github repository for Skipper there is a file: index.js
Line 92 from the above file, which appears to deal with multipart file uploads, contains the following:
var hasUpstreams = req._fileparser && req._fileparser.upstreams.length;
You should check the length of upstreams in your code, and see if that contains the number of files you sent.
Another option: send a parameter in your request from the client with the number of files uploaded.
See the skipper ReadMe section about Text Parameters.
Skipper allows you to access the other non-file metadata parameters (e.g "photoCaption" or
"commentId") in the conventional way. That includes url/JSON-encoded HTTP body parameters
(req.body), querystring parameters (req.query), or "route" parameters (req.params); in other words,
all the standard stuff sent in standard AJAX uploads or HTML form submissions. And helper methods
like req.param() and req.allParams() work too.
I've just found a previous question/answer on stackoverflow.
You might try using var upload = req.file('file')._files[0].stream to access and validate, as shown in the above answer.
I know writing business logic in getters and setters is a very bad programming practice, but is there any way to handle exceptions if the response is already committed?
What exactly is the meaning of "Response already committed" and "Headers are already sent to the client"?
There's no nice way to handle exceptions if the response is already committed. The HTTP response exist basically of a header and a body. The headers basically instruct the client (the webbrowser) how exactly it should deal with the response, e.g. the content type, the content length, the character encoding, the body encoding, the cache instructions, etcetera.
You can see the headers in the HTTP traffic monitor of the webbrowser's developer toolset. Press F12 in Chrome/IE9+/Firefox23+ and check the "Network" tab. The below screenshow is what my Chrome shows on your current question:
(note: the "Response" tab shows the response body)
The response body is the actual content, usually in flavor of a bunch of HTML code. The server has usually a fixed size buffer to write the response to. The buffer size depends on server make/version and configuration and is usually 2KB~10KB. If this buffer overflows, then it will be flushed to the other end of the connection, the client. This is the commit of a response. The client has already obtained the first part of the response, usually already representing the whole bunch of headers and maybe a part of the body.
The commit of a response is a point of no return. The server cannot take the already sent bytes back. It's too late to change the response headers (for example, a redirect is basically instructed by a Location header with therein the new URL), let alone the response body. Best what you can do is to append the error information to the already written response body. But this may end up in some weird looking HTML as it's not known which HTML tags needs to be closed at that point. The browser may fail to present it in a proper manner.
Apart from avoiding business logic in getters so that the exceptions are not thrown while rendering the response, another way to avoid an already committed response is to configure the response buffer size to be as large as the largest page which your webapp can serve. How to do that depends on the server make/version. In Tomcat for example, you can configure it as bufferSize attribute of the <Connector> element. Note that this won't prevent from flushing if your own code is (implicitly) calling flush() on the response output stream.
Good exlanation BalusC and I would add that primefaces has an issue in their exception handler. They try to redirect to error page after request was already committed. And as you said the only solution I found is to add some extra content to the response body. I owerride the handler and add this code
if ( extContext.isResponseCommitted() ) {
PartialResponseWriter writer = context.getPartialViewContext().getPartialResponseWriter();
writer.startElement( "script", null );
writer.write( "window.location.href = '" + errorPageUrl + "';" );
writer.endElement( "script" );
writer.getWrapped().endCDATA();
writer.endElement( "update" );
writer.getWrapped().endDocument();
}
else {
extContext.redirect( errorPageUrl );
context.responseComplete();
}
I am using the Tomahawk inputFileUpload component to allow users to upload files to a server. I have implemented a "soft" file size limit by checking the size of the file after it has been uploaded and displaying an error if it is too large. However I would also like a larger "hard" limit, where uploading immediately stops once it has passed the limit. For example if the hard limit is 500MB and the user attempts to upload a 2GB file, uploading will immediately stop once 500MB has been uploaded and an error is displayed.
I had hoped that using the MyFaces ExtensionsFilter and setting uploadMaxFileSize would fix the problem, but the file is completely uploaded before the SizeLimitExceededException is thrown.
Is it possible to do this? Ideally I'd still be able to use Tomahawk but any other solution would be good.
The web server can't abort a HTTP request halfway and then return a HTTP response. The entire HTTP request has to be consumed fully until the last bit before a HTTP response can ever be returned. That's the nature of HTTP and TCP/IP. There's nothing you can do against it with a server side programming language.
Note that the Tomahawk file upload size limit already takes care that the server's memory/disk space won't be polluted with the entire uploaded file whenever the size limit has been hit.
Your best bet is to validate the file length in JavaScript before the upload takes place. This is supported in browsers supporting HTML5 File API. The current versions of Firefox, Chrome, Safari, Opera and Android support it. IE9 doesn't support it yet, it'll be in the future IE10.
<t:inputFileUpload ... onchange="checkFileSize(this)" />
with something like this
function checkFileSize(inputFile) {
var max = 500 * 1024 * 1024; // 500MB
if (inputFile.files && inputFile.files[0].size > max) {
alert("File too large."); // Do your thing to handle the error.
inputFile.value = null; // Clears the field.
}
}
Try this:
<div>
<p:fileUpload id="fileUpload" name="fileUpload" value="#{controller.file}" mode="simple" rendered="true"/>
<input type="button" value="Try it" onclick="checkFileSize('fileUpload')" />
</div>
When user click in the button "Try it", checkFileSize() function is called and the fileUpload primefaces component is validated. If file size is greater than 500MB the file not is uploaded.
<script>
// <![CDATA[
function checkFileSize(name) {
var max = 500 * 1024 * 1024; // 500MB
var inputFile = document.getElementsByName(name)[0];
var inputFiles = inputFile.files;
if (inputFiles.lenght > 0 && inputFiles[0].size > max) {
alert("File too large."); // Do your thing to handle the error.
inputFile.value = null; // Clears the field.
}
}
// ]]>
</script>
The checkFileSize() logic is based on the BalusC answered above.
Versions tested:
primefaces 3.5
jsf 2.1
I had this working on kohana 2, but in kohana 3 it doesn't.
To serve an image stored as BLOB in a database, I did the following:
1- A controller to which I request what image do I want. I connects to the database, using a model of course, and serve the image using a view.
$prod = ORM::factory('product',$idx);
$img = new View('image');
$img->pic = $prod->getImage();
2-The model has a little trick to get this working:
public function getImage()
{
return imagecreatefromstring($this->image);
}
image is the blob column where I store the picture I want to serve.
3- In the view:
I set the content-type header and then serve the image
header('content-type: image/png; charset=UTF-8');
imagepng($pic);
This worked in Kohana 2, but in KO3 it doesn't,
I'm trying to use $response->send_file(), but I'm getting lost
First, you should never send headers with header() unless you're hacking the fw. Ko3.1 nicely separates Request from Response and the latter is the one responsible for response headers / everything else (both of them are written pretty much following the RFC 2616).
Secondly, there is absolutelly no need for a view file in this case, Response::$_body is what the current response object returns.
Response::send_file() returns the response as download, I suppose that's not what you're trying to accomplish?
So, you need something like this (modify to your own needs):
public function action_image($id)
{
$image = ORM::factory('product', $id);
if ( ! $image->loaded()) // ... 404 ?
$this->response
->headers('Content-Type','image/png')
->body($image->image)
->check_cache(NULL, $this->request); // 304 ?
}