Angular FormData filename encoding - angularjs

I'm having problems with angular file upload filename ecoding.
Example: uploading file žžž.txt. Result: žžž.txt
Relevent Html form parts:
<form id="fileupload"
action="/filestore/services/process/upload"
method="POST"
enctype="multipart/form-data"
data-ng-app="MyApp"
data-ng-controller="DemoFileUploadController"
data-file-upload="options"
<input type="file" name="files[]" multiple ng-disabled="disabled" file-change="uploadFile($event, files)">
File controller:
$scope.uploadFile = function($event, files) {
var file = files[0];
var data = new FormData();
console.log(file);
console.log(data);
data.append('file-0', file);
$.ajax({
url: uploadUrl,
data: data,
cache: false,
contentType: false,
processData: false,
type: 'post',
success: function(data) {
$scope.reload();
}
});
};
File object (printed by console.log(file)):
lastModified 1467975647307
lastModifiedDate Date {Fri Jul 08 2016 14:00:47 GMT+0300 (FLE Standard Time)}
name "žžž.txt"
size 7
type "text/plain"
Post request data body:
Source
-----------------------------2159279631001
Content-Disposition: form-data; name="file-0"; filename="žžž.txt"
Content-Type: text/plain
-----------------------------2159279631001--
As you can see from data/code, FormData is forming data object with incorrect filename, while File object itself is correct...any ideas why is that? How should I solve this?
Edit:
Request headers:
Content-Type multipart/form-data; boundary=---------------------------9275749615024
User-Agent Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0
X-Requested-Wit XMLHttpRequest
Response headers:
Content-Length 337
Content-Type application/json;charset=UTF-8
Server Apache-Coyote/1.1

You should set the contentType and encoding on your ajax request.
$.ajax({
url: uploadUrl,
data: data,
cache: false,
contentType: "application/x-www-form-urlencoded;charset=UTF-8",
processData: false,
type: 'post',
success: function(data) {
$scope.reload();
}
});
note that you should change charset
To the specific charset you are using and wich contains ž
Also if you are using a backend. Make sure it uses the correct character encoding as well
UTF-8 should do the trick

Related

I am trying to upload a file to Django server using angularjs 1.6.5. I am not able to upload file using $http.patch method

Using Angularjs 1.6.5 I am trying to upload a file to the Django server. When I try to upload the file I am not sure what type of 'Content-Type' header should be passed with the $http.patch method. Here is the following my Angular apps config:-
var app = angular.module("edit_modules", []);
app.config(function($httpProvider) {
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
$httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
$httpProvider.defaults.headers.common['Content-Type'] = 'application/json; charset=utf-8';
$httpProvider.defaults.useXDomain = true;
$httpProvider.defaults.headers.common['Accept'] = 'application/json, text/javascript';
});
And this is my patch method:-
$http.patch(url, data, {
headers: {'Content-Type': 'application/json; charset=utf-8' }
}).then(successCallback, errorCallback);
function successCallback(response){
console.log("Success");
console.log(response);
};
function errorCallback(error){
alert("Error Uploading!");
console.log(error);
};
When I pass {'Content-Type': 'application/json; charset=utf-8' } through the Header I get the following error:-
"The submitted data was not a file. Check the encoding type on the form."
Status :- 400
Since its content-type is file I used the following header {'Content-Type': 'multipart/form-data; charset=utf-8'} . But then I got this error:-
Multipart form parse error - Invalid boundary in multipart: None
Status :- 400
As suggested in the link here I tried the following header as well {'Content-Type': undefined} But this as well did not resolve my problem and I got the following error:-
Unsupported media type "text/plain;charset=UTF-8" in request.
Status :- 415
However when I tried with simple text fields the PATCH method worked with the header supplied being {'Content-Type': 'application/json; charset=utf-8' }. I am not sure where the problem is. I even tried to see the console for what data was being set to be patched
data = {
"video": element.files[0]
};
console.log(data);
THIS is what i got on console:-
{video: File(99861)}video: File(99861) {name: "Capture2.PNG", lastModified: 1517491665223, lastModifiedDate: Thu Feb 01 2018 18:57:45 GMT+0530 (India Standard Time), webkitRelativePath: "", size: 99861, …}
any help is much appreciated.
Referring to the answer here I found that you need to attach the File Object to be sent using FormData. Also you need an additional header in config transformRequest: angular.identity,. Here is the successful PATCH method that worked for me.
var fd = new FormData();
fd.append('video', element.files[0]);
$http.patch(url, fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
}).then(successCallback, errorCallback);
function successCallback(response){
console.log("Success");
console.log(response);
};
function errorCallback(error){
alert("Error Uploading!");
console.log(error);
};
In the second line 'video' is the REST API Endpoint's variable where my file will be stored. In order to avoid the error
Multipart form parse error - Invalid boundary in multipart: None
I have left the headers: {'Content-Type': undefined}.

Download a zip file in AngularJS

Trying to have a zip file download in AngularJS I looked at AngularJS: download pdf file from the server and coded my controller as:
RolloutService.export(rollout.id, function(data, status, headers) {
var headers = headers();
var filename = headers['download-filename'] || 'file';
var octetStreamMime = 'application/octet-stream';
var contentType = headers['Content-Type'] || octetStreamMime;
if (navigator.msSaveBlob) {
var blob = new Blob([data], { type: contentType });
navigator.msSaveBlob(blob, filename);
} else {
var urlCreator = window.URL || window.webkitURL || window.mozURL || window.msURL;
if (urlCreator) {
var link = document.createElement("a");
if ("download" in link) {
var blob = new Blob([data], { type: contentType });
var url = urlCreator.createObjectURL(blob);
link.setAttribute("href", url);
link.setAttribute("download", filename);
var event = document.createEvent('MouseEvents');
event.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
link.dispatchEvent(event);
} else {
var blob = new Blob([data], { type: octetStreamMime });
var url = urlCreator.createObjectURL(blob);
window.location = url;
}
}
}
});
But my file comes partly only.
Trying to unzip it gives:
stephane#stephane-ThinkPad-X60:~> unzip -l file
Archive: file
error [file]: missing 96319383 bytes in zipfile
(attempting to process anyway)
error [file]: start of central directory not found;
zipfile corrupt.
Note that if skipping the controller and going for a direct window.open() then the file comes complete and can be unzipped.
On the controller export request, the browser console shows the following headers:
Remote Address:127.0.0.1:8080
Request URL:http://localhost:8080/nitro-project-rest/rollouts/2/export
Request Method:GET
Status Code:200 OK
Request Headersview source
Accept:application/json, text/plain, */*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en
Authorization:Basic bnNuQG5zbi5jb206ZXRvaWxl
Connection:keep-alive
Host:localhost:8080
Origin:http://localhost:9000
Referer:http://localhost:9000/
User-Agent:Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/34.0.1847.116 Chrome/34.0.1847.116 Safari/537.36
Response Headers
Access-Control-Allow-Headers:Accept-Language,Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization
Access-Control-Allow-Methods:POST, PUT, GET, OPTIONS, DELETE
Access-Control-Allow-Origin:http://localhost:9000
Access-Control-Max-Age:3600
Cache-Control:no-store
Cache-Control:no-cache
Content-Disposition:attachment; filename="Orange-rollout-rollout-export.zip"
Content-Length:1960
Content-Type:application/zip
Date:Wed, 05 Nov 2014 20:33:31 GMT
download-filename:Orange-rollout-rollout-export.zip
Expires:Thu, 01 Jan 1970 00:00:00 GMT
Pragma:no-cache
Server:Apache-Coyote/1.1
X-Content-Type-Options:nosniff
X-Frame-Options:DENY
X-XSS-Protection:1; mode=block
My $http service was corrupting the file when sending the request.
I needed to add the following configuration:
responseType: 'arraybuffer'
as in:
factory.rolloutExport = function(rolloutId, successCallback, failureCallback) {
$http({
url: ENV.NITRO_PROJECT_REST_URL + '/rollouts/' + rolloutId + '/export',
method: 'GET',
responseType: 'arraybuffer',
cache: false,
headers: {
'Content-Type': 'application/json; charset=utf-8',
'Authorization': AuthService.getCredentialsHeaders()
}
}).success(successCallback).error(failureCallback);
};
Now the zip file comes back untouched by any encoding converter.

AngularJs Service, File Upload, Laravel

I'm having trouble with an XHR Request, for some reason my server is not receiving my files:
Here is my angular service update algorithm:
var update = function(id, name, file) {
var formData = new FormData();
formData.append('name', name);
formData.append('img', file);
return $http({
method : 'PUT',
url : '/albums/' + id,
data : formData,
headers : {'Content-Type': undefined},
transformRequest : angular.identity
});
};
On my laravel controller I just have:
public function update($id) {
return Response::json(Input::hasFile('img'));
}
The file is obviously there, why can't I retrieve it in my backend?
This is my request info:
Remote Address:[::1]:8000
Request URL:http://localhost:8000/albums/1
Request Method:PUT
Status Code:200 OK
Request Headers
Accept:application/json, text/plain, */*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8,es;q=0.6
Cache-Control:no-cache
Connection:keep-alive
Content-Length:13811
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryJ46EVSBw57RaVu7x
Cookie:_token=eyJpdiI6IkkzSXVmdnhubFFlVnlzSnZNWVFzVWk3ZlVKSFRDNFFlNndJWUVsVGNVU2c9IiwidmFsdWUiOiI5OG5PamUrVGZkZGx0ajZONklWajJ2OTM3MWlRd2tGZ2g5S2Jja1RhVjJ4Q1wvYk9xQTB4TlRKUWxkWmdvRm1EcHlzTGRjSEdzN2U5TWNPYWxEYVExVUE9PSIsIm1hYyI6IjA4NTY0ZTlmMjAyNTk3NGQxMmFhODIxMTU3NGNiYjQ4ZDA3OTgxMTA3Yzk1MmVkNmJkMGNkYjUyMmNhMzZkNzQifQ%3D%3D; laravel_session=eyJpdiI6IjRISElnWjd3ZlwvY2k1Z1pvOERWOGxyVHlaQzEwRmlqY1FiV0tNNzZEbEs4PSIsInZhbHVlIjoiYnp4UzVqOFoxMm5MMXhQdzJhVFphSkgrRGh2b2plYXhjdXpTamJ0UjVYdGdxS0puQmpPVXhObEtyb1I3XC9HQnRFdnBMWXV0MzRmWXAybGRySGRvXC9vUT09IiwibWFjIjoiMGQ1NzUyYTBjZmU3NzQ3ZDBkYjg5ZWViOGZmYzg3ZDY1ODg0N2JmNDg1NmQyNmMwZDcxMDE5NzcxZjIxM2MxMiJ9
Host:localhost:8000
Origin:http://localhost:8000
Pragma:no-cache
Referer:http://localhost:8000/Admin/Client
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.104 Safari/537.36
Request Payload
------WebKitFormBoundaryJ46EVSBw57RaVu7x
Content-Disposition: form-data; name="name"
Some Weird Album
------WebKitFormBoundaryJ46EVSBw57RaVu7x
Content-Disposition: form-data; name="img"; filename="derpino.jpg"
Content-Type: image/jpeg
------WebKitFormBoundaryJ46EVSBw57RaVu7x--
Response Headers
Cache-Control:no-cache
Connection:close
Content-Type:application/json
Date:Wed, 29 Oct 2014 12:47:20 GMT
Host:localhost:8000
Set-Cookie:laravel_session=eyJpdiI6IlQ4WlFOaG1keVhXVlA1dlluNWFZZGlMcmRQNGM3bThCRjZ6cnh4ZlorcWs9IiwidmFsdWUiOiJOZkJXNXBJQTVSTGZzWHJ4alg1SXBoN0Q2ekR6UVpnWThKQ0c4MXZOQlc1RUhNMUUraUZSTlpPYTlPTFdLQXpiYTJONkRvb29WN1djVlZkSGdaWStjQT09IiwibWFjIjoiOWI5MzEwODE2YTZlM2EzODMwZDE1YzI4YmE4M2NiYWJjMTRjMDEzOGI3YjA4NmRlMGU5NDBlZWEyMzI4MGQ3MCJ9; path=/; httponly
X-Frame-Options:SAMEORIGIN
X-Powered-By:PHP/5.5.11
I found the error! Apparently I can not send a file with the PUT method, I changed the method to POST and It works. In both the service and the laravel route
var update = function(id, name, file) {
var formData = new FormData();
formData.append('name', name);
formData.append('img', file);
return $http({
method : 'PUT',
url : '/albums/' + id,
data : formData,
headers : {'Content-Type': undefined},
transformRequest : angular.identity
});
};

$http response returns the entire index.html

I have site.com.
Each request is redirected here (so 'site.com/book', 'site.com/settings' ecc.. point to 'site.com')
Then I have site.com/api/ where 'site.com/api/user', 'site.com/api/library/' ecc... are redirected.
I'm trying to use $http of AngularJS to request a JSON object to site.com/api.
On success, I receive status 200 but the response is the text/html of 'site.com/index.html'.
The headers sent with the request are:
Accept: "application/json, text/plain, /"
Content-Type: application/json;charset=utf-8
I tried to debug site.com/api/ with the app postman and it works as expected since I receive the correct JSON object.
I don't know if it is a problem of some .htaccess rule or the $routeProvider of AngularJS...
(I have a .htaccess file in 'site.com' and another one in 'site.com/api').
But I could be completely off the road. Maybe someone can help? Thanks.
var config = {method: 'POST', url: 'site.com/api/', data: $scope.data};
$scope.login = function(){
$http(config)
.success(function(resp, status, headers, config){
console.log(resp);
})
.error(function(resp, status, headers, config){
console.log(status);
});
};
Ok I tried again with a clearer mind this morning.
It seems that I was missing the http part of the url site.com/api/.
So it can work both with
var config = {method: 'POST', url: 'http://example.com/api/', data: $scope.data};
or
var config = {method: 'POST', url: '/api/', data: $scope.data};

Unable to see uploaded images on Azure Blob

I am new to azure blob storage and I am trying to upload image to blob storage. I am using angular at client end and uploaded image with following headers :
'Content-type'
'x-ms-blob-type'
'Content-Length'
my blob is saved and i can see it in Azure Portal. But I am not able to see images. I am unable to understand the reason.
Link of my client is http://educms.azurewebsites.net/#/pages/results
There is no button. as soon as you select an image file, it will get uploaded. You can see the uploaded file at https://hobcity.blob.core.windows.net/images2/filename.extension
Upload Code of AngularJs
$scope.uploadFile = function(files) {
var fd = new FormData();
//Take the first selected file
fd.append("file", files[0]);
var size = files[0].size;
var name = files[0].name;
var type = files[0].type;
var postData = {"name" : name};
postData.containerName = 'images2';
DataService.save('/tables/results/', postData).then(function(data){
var header = {
'Access-Control-Allow-Origin': '*',
'Content-type' : type,
'x-ms-blob-type' : 'BlockBlob',
'Content-Length' : size
}
var url = data.imageUri
var queryString = data.sasQueryString
var uploadUrl = url+ '/' + name + '/?'+queryString
$http.put(uploadUrl, fd, {
headers: header,
transformRequest: angular.identity
}).success(function(data){
console.log(data)
}).error(function(err){
console.error(err);
});
});
}
HTML :
code can be seen live at http://educms.azurewebsites.net/scripts/controllers/results.js
Anyone know what's wrong ?
So I uploaded a simple text file and traced the request through Fiddler. Here's what I saw:
PUT http://hobcity.blob.core.windows.net/images2/simpletextfile.txt/?se=2014-08-11T17%3A13%3A52Z&sr=c&sp=w&sig=SlY7wURwfSjM72Hw22507OHpnaCC1Ky6POk6hhR6fbU%3D HTTP/1.1
Accept: application/json, text/plain, */*
Access-Control-Allow-Origin: *
Content-Type: text/plain, multipart/form-data; boundary=---------------------------7de26921205a0
x-ms-blob-type: BlockBlob
Referer: http://educms.azurewebsites.net/#/pages/results
Accept-Language: en-US
Origin: http://educms.azurewebsites.net
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko
Host: hobcity.blob.core.windows.net
Content-Length: 254
DNT: 1
Connection: Keep-Alive
Pragma: no-cache
-----------------------------7de26921205a0
Content-Disposition: form-data; name="file"; filename="simpletextfile.txt"
Content-Type: text/plain
https://hobcity.blob.core.windows.net/images2/Add-Item.png
-----------------------------7de26921205a0--
I believe the reason you're running into the issue is because you're uploading the file as is (see your Content-Type is multipart/form-data) and this is corrupting the data. What you would need to do is read the file contents into a byte array and then upload that byte array. If you search for HTML 5 File API, you will find examples of how to read a file using JavaScript. Also I wrote a blog post about uploading files in Azure Blob Storage using JavaScript which you may find useful: http://gauravmantri.com/2013/12/01/windows-azure-storage-and-cors-lets-have-some-fun/ (though this post make use of jQuery instead of Angular but should give you some idea).

Resources