JSON callback after file upload - ajax

I have problem trying to upload a file via json/ajax and does not look like the file was uploaded. Only name of the file was displayed in the console output.
My html code as shown below.
<form action="/cgi-bin/upload.cgi" method="post" enctype="multipart/form-data" target="upIFrame">
<input type="file" id="uploadFileName" name="uploadFileName" size="30" >
<input type="button" id="upgradeFile" name="upgradeFile" value="Upload" onclick="ul.load()" />
<iframe id="upIFrame" name="upIFrame" src="#" style="display: none;"></iframe>
</form>
the ul.load() is calling this line below and eventually the transfer.ajax code will call
transfer.ajax({
url:'upload.cgi',
data:{filename: ul.filename},
success: success,
error: error,
async: true
});
ul.filename comes from uploadFileName
and transfer.ajax code shown below
transfer = {
ajax: function(p) {
if (p.url.indexOf('/') == -1) {
p.url = '/cgi-bin/' + p.url;
}
p.type = 'POST';
p.contentType = 'application/json';
p.dataType = 'json';
p.cache = false;
if (p.data != undefined) {
p.data = JSON.stringify(p.data);
}
$.ajax(p);
}
};
the result after viewing in Fire Fox is
JSON
filename "file.tgz"
Source
{"filename":"file.tgz"}
Could some tell me what I did wrong or what I missed?
TIA
I modified the code to the following...
var fd = new FormData();
fd.append("filename",ul.filename);
$.ajax({
url: "/cgi-bin/test.cgi",
type: "POST",
data: fd,
processData: false, // tell jQuery not to process the data
contentType: false, // tell jQuery not to set contentType
beforeSend : function(xhr){
xhr.setRequestHeader('Content-Disposition', 'form-data; name=\"uploadFileName\"; filename=\"' + ul.filename + '\"');
},
});
and the Request Headers in Fire Fox are as
Accept-Encoding gzip, deflate
Accept-Language en-US,en;q=0.5
Content-Disposition form-data; name="uploadFileName"; filename="test.tgz"
Content-Length 157
Content-Type multipart/form-data; boundary=---------------------------20025277823050
X-Requested-With XMLHttpRequest
but the "Post" display the following
Source
-----------------------------20025277823050 Content-Disposition: form-data; name="filename"
test.tgz -----------------------------20025277823050--
How would I include filename="test.tgz"? what's missing?
TIA

Can you try this,
var fd = new FormData();
fd.append("filename",ul.filename);`enter code here`
$.ajax({
url: "/cgi-bin/test.cgi",
type: "POST",
data: fd,
processData: false,
contentType: false,
beforeSend : function(xhr){
xhr.setRequestHeader('Content-Disposition', 'form-data; name=\"' + ul.filename + '\"; filename=\"' + ul.filename + '\"');
}
});
I think name attribute should be as the file name.
Thanks :).

Related

Keep input type file in a hidden input for AJAX submit

I have an input to upload an excel file and a hidden input
<input type="file" id="file">
<input type="hidden" id="file_submit">
When I choose file in input type file, I want to set its value to hidden input below and retrieve in AJAX function, then I will reset input file for next upload, prevent ERR_UPLOAD_FILE_CHANGED error.
Here is my code in AJAX:
var formData = new FormData();
formData.append('file', $('#file_submit').val());
$.ajax({
url: "{{ route('admin.handle-import') }}",
headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},
method: "POST",
data: formData,
enctype: 'multipart/form-data',
processData: false,
contentType: false,
success: function(res) {
$('file').val(''); //reset input file
}
});
I tried this code to set value for hidden input:
document.getElementById('file').onchange = function() {
$('#file_submit').val($(this).prop('files'));
};
And in my controller, I get by code $request->file;. But it only return "[object FileList]". I really don't know what I have to do now.
Can you give me a solution for this?
Thank you very much

Image upload with jquery

I am trying to upload an image file from a partial view using AJAX but it is returning a Bad Request(400) error. I have searched SO answers but it is not working. Here is my script :
$("#prodImgUpload").change(function() {
var formData = new FormData();
formData.append("file", $("#prodImgUpload")[0].files[0]);
console.log(formData.get("file"));
addAntiForgeryToken(formData);
$.ajax({
type: "POST",
url: "#Url.Action("UploadImage","Product",new{area="admin"})",
data: formData,
processData: false,
contentType: false,
cache: false,
async: false,
success: function(result) {
alert("Image uploaded successfully");
},
error: function(jqXHR, textStatus, errorMessage) {
alert(errorMessage);
}
});
And here is the HTML :
<div class="upload-button">
<div class="label">Upload image</div>
<input asp-for="FileToUpload" id="prodImgUpload" name="FileToUpload"
type="file" accept="image/jpeg, image/png, image/jpg, image/bmp" />
</div>
It never reaches the controller. And remember it is in partial view.
Here's my controller's action :
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult UploadImage(IFormFile file)
{
if (file == null)
return Json(new { success = false, message = "No file uploaded" });
//do something with file.
}
You're not including the antiforgery token with the AJAX request. Reference the documentation for how to handle AJAX request with antiforgery tokens. Essentially, you need to add a header to your AJAX request:
$.ajax({
...
headers: {
"RequestVerificationToken": $('#RequestVerificationToken').val()
},
The value comes from a hidden input added via:
#inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf
#functions{
public string GetAntiXsrfRequestToken()
{
return Xsrf.GetAndStoreTokens(Context).RequestToken;
}
}
<input type="hidden" id="RequestVerificationToken"
name="RequestVerificationToken" value="#GetAntiXsrfRequestToken()">

Django-ajax: CSRF verification failed. Request aborted

I am working with django server side form to save details in DB.
<form id="form_save_file" enctype="multipart/form-data">
{% csrf_token %}
<label class="control-label col-md-4">File:</label>
<div class="col-md-8">
{{form.fa_file}}
</div>
<label class="control-label col-md-4">Name:</label>
<div class="col-md-8">
{{form.name}}
</div>
</form>
I am using ajax to post request.
$("#form_save_file").submit(function(e) {
$.ajax({
type: "POST",
url: '/url/',
data: $("#form_save_file").serialize(),
contentType: false,
processData: false,
success: function(data){}
});
I have included middleware classes in settings.py
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'request.middleware.RequestMiddleware'
)
When I removed contentType and processData in ajax request, request.FILES is empty in views.py and otherthings are working fine.
contentType option to false is used for multipart/form-data forms that
pass files.
When one sets the contentType option to false, it forces jQuery not to
add a Content-Type header, otherwise, the boundary string will be
missing from it. Also, when submitting files via multi-part/form one
must leave the processData flag set to false, otherwise, jQuery will
try to convert your FormData into a string, which will fail.
To try and fix your issue:
You are using jQuery's .serialize() method which creates a text string
in standard URL-encoded notation.
You need to pass un-encoded data when using "contentType: false".
Try using "new FormData" instead of .serialize():
Source: https://stackoverflow.com/a/20863123/3345051
Revised Code:
$("#form_save_file").submit(function(e) {
e.preventDefault();
var $this = $(this);
var postURL = '/url/';
var formData = new FormData(this);
$.ajax({
type: "POST",
url: postURL,
data: formData,
mimeType: "multipart/form-data",
contentType: false,
cache: false,
processData: false
})
.done(function(response) {
// Do something if POST is successful
})
.fail(function() {
// Do something if POST is unsuccessful
})
})
disabled csrf on particular view with #csrf_exempt decorator and build custom security with a random number/string

Ajax POST with csrfmiddlewaretoken and csrftoken cookie set still gets django 403 Forbidden

I've read that both the csrfmiddlewaretoken and the csrftoken cookie have to be the correct value for a django POST request to succeed (django: csrftoken COOKIE vs. csrfmiddlewaretoken HTML Form value). This is the case for me yet I still get a 403:
In the chrome console:
document.cookie
returns
"csrftoken=Wt9eeJop5Vb3OmeNTvogegckm1pVM5MD"
but
$.get('https://learningdollars.fwd.wf/csrftoken/', function(data){
console.log(data)
token = $.parseHTML(data)[0].value
console.log(token)
$.ajax({
type: "POST",
url: 'https://learningdollars.fwd.wf/confirmemail/',
data: {email: 'gdasu#alumni.stanford.edu', csrfmiddlewaretoken: token},
contentType: "application/json"
})
.done(function(response) {
console.log('done!')
})
.fail(function(error) {
console.log('fail!')
})
})
returns
> Object {readyState: 1, getResponseHeader: function, getAllResponseHeaders: function, setRequestHeader: function, overrideMimeType: function…}
> <input type='hidden' name='csrfmiddlewaretoken' value='Wt9eeJop5Vb3OmeNTvogegckm1pVM5MD' />
> Wt9eeJop5Vb3OmeNTvogegckm1pVM5MD
> POST https://learningdollars.fwd.wf/confirmemail/ 403 (Forbidden)
> fail!
I have
'django.middleware.csrf.CsrfViewMiddleware',
activated in my django middleware.
My root urls.py contains:
url(r'^csrftoken/$', views.get_csrf_token),
url(r'^confirmemail/$', views.confirm_email, name='confirm_email'),
And, my views are:
def get_csrf_token(request):
c = {}
c.update(csrf(request))
print c
return render_to_response('csrf.html', c)
def confirm_email(request):
print 'here'
return JsonResponse({'response': 0})
And by the way, the contents of csrf.html are just the csrftoken (inside an input tag):
{% csrf_token %}
What am I doing wrong?
Well, I found a solution. It was just sending in the data as a URI rather than as json. (I by the way tried specifying dataType: 'json' in the above to no avail.) The following is in the chrome console:
> email = 'gdasu#alumni.stanford.edu'
< "gdasu#alumni.stanford.edu"
> csrftoken = 'L2MxD1XQIF1Xto5NkzUgGUYiHPyyz3K5'
< "L2MxD1XQIF1Xto5NkzUgGUYiHPyyz3K5"
> $.ajax({
type: "POST",
url: 'https://learningdollars.fwd.wf/confirmemail/',
data: "email="+ encodeURI(email) + "&csrfmiddlewaretoken=" + encodeURI(csrftoken),
success: function(data) { console.log(data); }
})
< Object {response: 1}
Still unsure what I was doing wrong on the json side, but the following is what I tried:
$.ajax({
type: "POST",
url: "https://learningdollars.fwd.wf/confirmemail/",
data: JSON.stringify({ email: email, csrfmiddlewaretoken: csrftoken }),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(data){
alert(data);
},
failure: function(errMsg) {
alert(errMsg);
}
});
You can forbid Django CSRF by adding csrf_exempt to tell the view not check csrf token.
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt
def get_csrf_token(request):
c = {}
c.update(csrf(request))
print c
return render_to_response('csrf.html', c)
#csrf_exempt
def confirm_email(request):
print 'here'
return JsonResponse({'response': 0})

Sending files and text with AJAX + multipart form data + UTF-8 encoding

I've been all day trying to make the client send AJAX requests with UTF-8 encoding in FormData() objects. I'm using Sping MVC on the server side, but that doesn't apply in this case, since:
I can POST to the server non-multipart requests, and I can capture the request and see:
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
and I also can see the characters encoded OK (á, é, í, ó, ú).
If I POST using AJAX + file upload + FormData, using the following code:
var data = new FormData();
data.append('body', jq("#sp_body").val());
data.append('signature', jq("#sp_signature").val());
data.append('subject', jq("#sp_subject").val());
data.append('email', jq("#sp_email").val());
data.append("file", jq("#sp_file")[0].files[0]);
jq.ajax({
url: contextPath + "/jobs/" + job + "/sendmail",
data: data,
cache: false,
dataType: 'text',
processData: false,
contentType: false,
mimeType: "multipart/form-data",
type: 'POST',
success: function(result){
data = jq.parseJSON(result);
if (data["statusCode"] == "success") {
jq("#save_status").html("Email sent!").show().delay(5000).fadeOut(200);
} else {
jq("#save_status").html(data["errors"]).show().delay(5000).fadeOut(200);
}
},
error: function (xhr, ajaxOptions, thrownError) {
alert(xhr.status);
alert(thrownError);
}
});
Then I capture the request and I see:
Content-Type: multipart/form-data; boundary=---------------------------279972256522979
But no UTF-8 in the header, and the non-latin characters are garbled.
The question is, how can I POST using FormData (since I want to POST strings and a file at the same time), having UTF-8 encoding set?
I've read UTF-8 text is garbled when form is posted as multipart/form-data but that didn't help me.
In your servlet, you have to set the encoding again:
public void extractRequest(HttpServletRequest request) throws Exception {
if (request != null) {
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (isMultipart) {
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
List<FileItem> items = null;
try {
items = upload.parseRequest(request);
}
catch (FileUploadException e) {
e.printStackTrace();
}
while (itr.hasNext()) {
FileItem item = itr.next();
if (item.isFormField()) {
String name = item.getFieldName();
String value = item.getString("UTF-8");
...
...
In your html:
<form id="formid" action="<yourpath>" enctype="multipart/form-data"
method="POST" accept-charset="utf-8">
And of course, if you are using a database, same thing has to be set there as well
Do let me know if this helps; otherwise we can look at other areas.

Resources