How to Handle Error in S3 browser upload via POST - post

I am newbie to S3. Trying to catch errors in S3 http://docs.aws.amazon.com/AmazonS3/2006-03-01/API/ErrorResponses.html
My code sample:
{"expiration": "2007-12-01T12:00:00.000Z",
"conditions": [
{"bucket": "johnsmith"},
["starts-with", "$key", ""],
{"acl": "private"},
{"success_action_redirect": "http://johnsmith.s3.amazonaws.com/successful_upload.html"},
["eq", "$Content-Type", "application/msword,application/pdf"],
["content-length-range", 2048, 20971520 ]
]
}';
<form action="http://johnsmith.s3.amazonaws.com/" method="post" enctype="multipart/form-data">
<input type="hidden" name="key" value="${filename}" /><br />
<input type="hidden" name="acl" value="private" />
<input type="hidden" name="success_action_redirect" value="http://johnsmith.s3.amazonaws.com/successful_upload.html" >
<input type="hidden" name="AWSAccessKeyId " value="15B4D3461F177624206A" />
<input type="hidden" name="Policy" value="eyAiZXhwaXJhdGlvbiI6ICIyMDA3LTEyLTAxVDEyOjAwOjAwLjAwMFoiLAogICJjb25kaXRpb25zIjogWwogICAgeyJidWNrZXQiOiAiam9obnNtaXRoIiB9LAogICAgWyJzdGFydHMtd2l0aCIsICIka2V5IiwgInVzZXIvZXJpYy8iXSwKICAgIHsiYWNsIjogInB1YmxpYy1yZWFkIiB9LAogICAgeyJyZWRpcmVjdCI6ICJodHRwOi8vam9obnNtaXRoLnMzLmFtYXpvbmF3cy5jb20vc3VjY2Vzc2Z1bF91cGxvYWQuaHRtbCIgfSwKICAgIFsic3RhcnRzLXdpdGgiLCAiJENvbnRlbnQtVHlwZSIsICJpbWFnZS8iXSwKICAgIHsieC1hbXotbWV0YS11dWlkIjogIjE0MzY1MTIzNjUxMjc0In0sCiAgICBbInN0YXJ0cy13aXRoIiwgIiR4LWFtei1tZXRhLXRhZyIsICIiXSwKICBdCn0K" />
<input type="hidden" name="Signature" value="2qCp0odXe7A9IYyUVqn0w2adtCA=" />
File: <input type="file" name="file" /> <br />
<input type="submit" name="submit" value="Upload to Amazon S3" />
</form>
Want to catch error if file is failed to upload or expired. To check content type, content length range.
Getting proper success callback variable like bucket, key, etag.
Thanks

using simple ajax form post...
<script>
function uploadFile() {
var file_name = $('#form1 :input[name="file"]').val().split('\\').pop();
if(!file_name || file_name.length === 0) {
alert('please choose file')
return false;
}
$.ajax({
url: "/getS3FormData.php",
cache: false,
type: 'GET',
data: {file_name : file_name} ,
async: false,
success: function (response) {
var s3 = JSON.parse(response);
handleFileUpload(s3);
},
error: function (error) {
alert("Upload FAILED :-( Retry.");
}
});
}
function handleFileUpload(s3) {
var fd = new FormData();
fd.append('key', s3.key);
fd.append('AWSAccessKeyId', s3.AWSAccessKeyId);
fd.append('acl', s3.acl);
fd.append('policy', s3.policy);
fd.append('signature', s3.signature);
fd.append('Content-Type', s3.content_type);
var file = $('#form1').find('input[name=file]')[0].files[0];
fd.append("file", file);
window.onbeforeunload = function () {
return "Upload in progress";
}
$.ajax({
url: s3.url,
data: fd,
cache: false,
contentType: false,
processData: false,
type: 'POST',
success: function(data){
window.onbeforeunload = null;
window.location.href = s3.success_action_redirect;
},
error: function(error) {
window.onbeforeunload = null;
alert('Upload Failed, Please try again');
}
});
}
html form
<form id="form1" method="post" enctype="multipart/form-data">
<input type="file" name="file"></input>
<input type="submit" onclick="uploadFile(); return false;" value="Upload">
</form>

EDIT: My original answer used iframes but I finally got the XMLHttpRequest to work which I think it is a cleaner approach.
I've had the same problem. My requirements were:
I didn't want to use flash
I didn't want the user to see the AWS error XML
There are plenty of solutions scattered all over the internet. I got it to work in two versions:
Using an iFrame to render the POST result and by trying to access the uploaded file (in my case, an image) to check if the upload worked or not: https://gist.github.com/joaoffcosta/5728483
Using XMLHttpRequest to make the request and handle progress, completion and premature failure: https://gist.github.com/joaoffcosta/5729398 (Best solution IMO)
In both solutions, your S3 Bucket should allow 'Everyone' to 'Upload/Delete'.
Additionally, the XMLHttpRequest solution requires you to configure CORS on your bucket. To do it you should go to your bucket 'Permissions', press 'Add CORS Configuration' and add something like this:
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>http://your_website_or_localhost_server/</AllowedOrigin>
<AllowedMethod>POST</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<ExposeHeader>x-amz-server-side-encryption</ExposeHeader>
<ExposeHeader>x-amz-request-id</ExposeHeader>
<ExposeHeader>x-amz-id-2</ExposeHeader>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>

Related

Post to zapier webhook and write to spreadsheet

I am trying to use a zapier webhook to write to a google spreadsheet. Here is the simple html I am using:
<form id="my-form">
<input type="text" id="name" name="name" placeholder="Name" />
<input type="text" id="age" name="age" placeholder="Age" />
<input type="text" id="location" name="location" placeholder="Location" />
<input type="text" id="date" name="date" placeholder="Date" />
<button type="submit">Submit</button>
</form>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
(function($){
function processForm( e ){
$.ajax({
url: 'https://hooks.zapier.com/hooks/catch/2366642/xxx/',
dataType: 'text',
type: 'post',
contentType: 'application/x-www-form-urlencoded',
data: $(this).serialize(),
success: function( data, textStatus, jQxhr ){
$('#response pre').html( data );
console.log(data)
},
error: function( jqXhr, textStatus, errorThrown ){
console.log( errorThrown );
}
});
e.preventDefault();
}
$('#my-form').submit( processForm );
})(jQuery);
</script>
When I hit the submit button I am getting the test data that I entered into the initial zap being written to the spreadsheet each time. I am wanting the name, age, location and date fields to be written to the spreadsheet instead
I used this tutorial to get started so I suspect I am getting the data from the form to the ajax request properly. Any help appreciated.
In case anyone else runs into this, I had not selected the fields in the Action portion of the zap. Here is an image. Hope it helps others out:

Recaptcha image challenge always occurs in Microsoft Edge after form submission (Invisible recaptcha)

I've just implemented invisible recaptcha into a web form. Everything works fine with Chrome. But with Microsoft Edge, the image challenge always occurs with every form submission. Which is embarrassing for the users of the website. An idea?
Thanks a lot for your insights and advice :o)
Laurent
Javascript code:
window.onScriptLoad = function () {
var htmlEl = document.querySelector('.g-recaptcha');
var captchaOptions = {
'sitekey': 'xxxxxxxxxxxxxxxxxxxxxxxxxxx',
'size': 'invisible',
'badge': 'inline',
callback: window.onUserVerified
};
var inheritFromDataAttr = true;
recaptchaId = window.grecaptcha.render(htmlEl, captchaOptions, inheritFromDataAttr);
};
window.onUserVerified = function (token) {
$.ajax({
url: 'process.php',
type: 'post',
dataType: 'json',
data : {
'lastname' : $("#lastnameField").val(),
'firstname' : $("#firstnameField").val(),
'city' : $("#cityField").val(),
'postalCode' : $("#postalcodeField").val(),
'g-recaptcha-response' : token
},
success:function(data) {
// informs user that form has been submitted
// and processed
},
error: function(xhr, textStatus, error){
// informs user that there was a problem
// processing form on server side
}
});
};
function onSubmitBtnClick () {
window.grecaptcha.execute;
}
HTML code:
<html>
<head>
<script src="https://www.google.com/recaptcha/api.js?render=explicit&onload=onScriptLoad" async defer></script>
<script type="text/javascript" src="js/petition.js"></script>
...
</head>
<body>
<form id="petitionForm" onsubmit="return false;">
<input id="lastnameField" type="text" name="lastname" placeholder="Lastname" required value="Doe">
<input id="firstnameField" type="text" name="firstname" placeholder="Firstname" required value="John">
<input id="postalcodeField" type="text" name="postalCode" placeholder="Postal Code" required value="ABCDEF">
<input id="cityField" type="text" name="city" placeholder="City" value="Oslo">
....
<input type="submit" name="login" class="g-2" data-sitekey="xxxxxxxxxxxxxxxxxxxxxxx" id="signButton" data-callback='' value="Signer" onclick="onSubmitBtnClick();">
<div class="g-recaptcha" id="recaptchaElement" style="align-content: center"></div>
</form>
...
</body>
</html>

tornado post request: missing argument

I'm using tornado to build a web server and now I'm creating a login module. Here is the code:
<body>
<form id="uploadForm">
<div class="form-group">
<label for="exampleInputEmail1">Email address</label>
<input name="name" type="email" class="form-control" id="exampleInputEmail1" placeholder="Email">
</div>
<div class="form-group">
<label for="exampleInputPassword1">Password</label>
<input name="password" type="password" class="form-control" id="exampleInputPassword1" placeholder="Password">
</div>
<button id="submit" type="button" class="btn btn-default">Submit</button>
</form>
</body>
<script src="../js/plugins/jquery-3.2.1.min.js?v=c9f5aeeca3"></script>
<script src="../js/common/bootstrap.min.js?v=5869c96cc8"></script>
<script>
$(function(){
$('#submit').on('click',function(){
$.ajax({
url: 'http://www.example.com/login',
method: 'POST',
data: $('#uploadForm').serialize(),
contentType: false,
processData: false,
cache: false,
success: function(data) {
console.log(data);
if( data === 'ERROR'){
alert('login failed')
}else{
location.href = data;
}
},
error: function (jqXHR) {
alert('ERROR');
}
});
});
});
</script>
And the backend part:
class LoginHandler(tornado.web.RequestHandler):
def post(self, path):
try:
print(self.request.body)
name = self.get_body_argument("name")
except Exception as e:
print(e)
When I do a test, I can see that print(self.request.body) gives me the result: b'name=test&password=tttt' but after that I get an exception:
HTTP 400: Bad Request (Missing argument name)
name=test is just in the http body but why it tells me missing argument name?
Tornado only supports "application/x-www-form-urlencoded" and "multipart/form-data" as content type. So when we send a post request to the server, we must send the request with the right contentType. For example,
$.ajax({
url: 'http://www.example.com/login',
method: 'POST',
data: $('#uploadForm').serialize(),
contentType: 'application/x-www-form-urlencoded',
processData: false,
...
Also, we can neglect the contentType in ajax as 'application/x-www-form-urlencoded' is set by default.

React Axios to Rails Knock

I am trying to send a POST request from axios to a Rails API using the following function in the React frontend:
export function registerUser({ name, email, password }) {
var postdata = JSON.stringify({
auth: {
name, email, password
}
});
return function(dispatch) {
axios.post(`${API_URL}/user_token`, postdata )
.then(response => {
cookie.save('token', response.data.token, { path: '/' });
dispatch({ type: AUTH_USER });
window.location.href = CLIENT_ROOT_URL + '/dashboard';
})
.catch((error) => {
errorHandler(dispatch, error.response, AUTH_ERROR)
});
}
}
The Knock gem expects the request in the following format:
{"auth": {"email": "foo#bar.com", "password": "secret"}}
My current function seem to generate the correct format (inspecting the request in the browser devtools), but I'm getting the following error:
Uncaught (in promise) Error: Objects are not valid as a React child
(found: object with keys {data, status, statusText, headers, config,
request}). If you meant to render a collection of children, use an
array instead or wrap the object using createFragment(object) from the
React add-ons. Check the render method of Register.
class Register extends Component {
handleFormSubmit(formProps) {
this.props.registerUser(formProps);
}
renderAlert() {
if(this.props.errorMessage) {
return (
<div>
<span><strong>Error!</strong> {this.props.errorMessage}</span>
</div>
);
}
}
render() {
const { handleSubmit } = this.props;
return (
<form onSubmit={handleSubmit(this.handleFormSubmit.bind(this))}>
{this.renderAlert()}
<div className="row">
<div className="col-md-6">
<label>Name</label>
<Field name="name" className="form-control" component={renderField} type="text" />
</div>
</div>
<div className="row">
<div className="col-md-12">
<label>Email</label>
<Field name="email" className="form-control" component={renderField} type="text" />
</div>
</div>
<div className="row">
<div className="col-md-12">
<label>Password</label>
<Field name="password" className="form-control" component={renderField} type="password" />
</div>
</div>
<button type="submit" className="btn btn-primary">Register</button>
</form>
);
}
}
The error is caused by the following line in your code
errorHandler(dispatch, error.response, AUTH_ERROR)
The exception raised clearly explains that. Instead of setting error.response, try to use the actual data from error.response. E.g error.response.data. Also, you can try replacing the error.response with a string and see how that behaves, then reference the string you need from error.response.data.

How to prevent redirect to new page on form submit

I am trying to upload a form containing multiple files to my server, request is going to correct Action and I am also getting some data but all the files are coming with null values.
var file = function(){
this.submitForm = function () {
$("#addBrtForm").ajaxSubmit(function (response) {
if (response === "Barter Uploaded Successfully") {
alert(response);
$.mobile.changePage("#p-afterUpload");
t.somefunction();
} else {
alert("Try Again!! Barter Not Uploaded");
}
});
};
};
hm.files = new file();
//other thing that I tried
$(function(){
$('#addBrtForm').ajaxForm({
type: 'POST',
beforeSubmit: function () {
return false;
},
success: function (response) {
return false;
if (response === "Barter Uploaded Successfully") {
alert(response);
$.mobile.changePage("#p-barter");
t.setBarterpageTitle('My Barter');
} else {
alert("Try Again!! Barter Not Uploaded");
}
}
});
});
<form method="post" action="http://localhost:xxxx/Mobile/Home/FileUpload" enctype="multipart/form-data" data-ajax="false" id="addBrtForm" name="addBrtForm" >
<input type="text" name="Title" data-role="none" />
<input type="text" name="Description" data-role="none" />
<input type="file" name="files" data-role="none" multiple />
<input type="file" name="files" data-role="none" multiple />
<input type="file" name="files" data-role="none" multiple />
<input type="file" name="files" data-role="none" multiple />
<input type="file" name="files" data-role="none" multiple />
<input type="Submit" name="" value="submit" data-role="none" multiple />
<input type="Button" name="" value="submit" data-role="none" multiple onclick="hm.files.submitForm()"/>
</form>
It is working perfectly without "ajaxSubmit" but page is redirecting to "http://localhost:xxxx/Mobile/Home/FileUpload", I don't want that page to come up, I just wanted to catch my response and do something based on that
My controller
public ActionResult FileUpload(FormCollection fc, List<HttpPostedFileBase> files)
{
//some functionilty to save data working perfectely
return Json(SuccesMessage, JsonRequestBehavior.AllowGet);
}
*Note - as I am using jquery mobile so there is no views in my project
thanks to accepted answer on this post and Stephen Muecke for suggesting me to look on that question.
what I did-
removed action attribute from my form tag
used on click instead of submit
used ajax to post data as given in the reference link.
My edited js is shown below
var formdata = new FormData($('#addBrtForm').get(0));
$.ajax({
url: "http://localhost:xxxx/Mobile/Home/FileUpload",
type: 'POST',
data: formdata,
processData: false,
contentType: false,
dataType: "json",
success: function (response) {
if (response === "File Uploaded Successfully") {
alert(response);
$.mobile.changePage("#p-afterUpload");
t.someFunction();
} else {
alert("Try Again!! File Not Uploaded");
}
},
error: function (e) {
alert("Network error has occurred please try again!");
}
});
changed controller action to this -
public ActionResult FileUpload(UploadModel fm, List<HttpPostedFileBase> files)
{
//some functionilty to save data working perfectely
return Json(SuccesMessage, JsonRequestBehavior.AllowGet);
}
- UploadModel is my model having same Name as I used in my form
Add id to the submit button.
<input type="Button" name="" id="submit" value="submit" data-role="none" multiple/>
Then in the javascript do like this
$(function(){
$('#submit').click(function(e){
Do Your stuf here
e.preventDefault();
});
}

Resources