Can't upload file from android app to wep api - java

I am trying to upload an image file from an android app using java to an aspnet webapi with no success. I always get a response code of 500. Below is the basic code for preparing the sending of data from my android app. This code works when calling a php script but not when I call a web api controller shown below.
FileInputStream fileInputStream = new FileInputStream(sourceFile);
url = new URL("http://www.myserver.com/webapi/api/fileupload/post/thisfile");
connection = (HttpURLConnection) url.openConnection();
// Allow Inputs & Outputs.
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setUseCaches(false);
// Set HTTP method to POST.
connection.setRequestMethod("POST");
connection.setRequestProperty("Connection", "Keep-Alive");
connection.setRequestProperty("Content-Type", "multipart/form-data;boundary="+boundary);
outputStream = new DataOutputStream( connection.getOutputStream() );
outputStream.writeBytes(twoHyphens + boundary + lineEnd);
outputStream.writeBytes("Content-Disposition: form-data; name=\"uploaded_file\";filename=\"" + sourceFile +"\"" + lineEnd);
outputStream.writeBytes(lineEnd);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
buffer = new byte[bufferSize];
// Read file
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0)
{
outputStream.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
outputStream.writeBytes(lineEnd);
outputStream.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
// Responses from the server (code and message)
serverResponseCode = connection.getResponseCode();
Below is the basic web api controller code to do the file upload:
[HttpPost]
[AcceptVerbs("GET", "POST")]
public Task<HttpResponseMessage> Post()
{
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
// return "Unsupported media type";
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = "e:/web/myserver/htdocs/cemetery/pics/";
var provider = new MultipartFormDataStreamProvider(root);
return task;
}
I changed the code above to send back a string and it says that my request does not contain multipart/form-data. Below is my webapiconfig.cs file route for this controller.
config.Routes.MapHttpRoute(
name: "FileUploadApi",
routeTemplate: "api/{controller}/{action}/{name}",
defaults: new { action = "post", name = RouteParameter.Optional }
);
I appreciate any help in determining what is wrong with my code so I can upload a file from an android java app to a webapi controller.

Related

JAVA POST Request MultiFormData with File and Parameters

I am trying to make a POST request using "multipart/form-data" , i need to post a file (Code Below) and 4 parameters(Name,category ...) all Strings.
I can already send the File using code below but never with parameters.
// open a URL connection to the Servlet
FileInputStream fileInputStream = new FileInputStream(sourceFile);
URL url = new URL(upLoadServerUri);
// Open a HTTP connection to the URL
conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true); // Allow Inputs
conn.setDoOutput(true); // Allow Outputs
conn.setUseCaches(false); // Don't use a Cached Copy
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("ENCTYPE", "multipart/form-data");
conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
conn.setRequestProperty("fileToUpload", fileName);
dos = new DataOutputStream(conn.getOutputStream());
dos.writeBytes(twoHyphens + boundary + lineEnd);
dos.writeBytes("Content-Disposition: form-data; name=\"fileToUpload\";filename=" + fileName + "" + lineEnd);
dos.writeBytes(lineEnd);
// create a buffer of maximum size
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
buffer = new byte[bufferSize];
// read file and write it into form...
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0) {
dos.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
// send multipart form data necesssary after file data...
dos.writeBytes(lineEnd);
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
// Responses from the server (code and message)
serverResponseCode = conn.getResponseCode();
String serverResponseMessage = conn.getResponseMessage();
Log.i("uploadFile", "HTTP Response is : " + serverResponseMessage + ": " + serverResponseCode);
if (serverResponseCode == 200) {
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(PerdidosEAchados.this, "File Upload Complete.",
Toast.LENGTH_SHORT).show();
}
});
}
//close the streams //
fileInputStream.close();
dos.flush();
dos.close();
The server Code
<?php
echo $_POST["Name"]) ;
echo $_POST["category "]) ;
?>
I have tryed adding
dos.writeBytes("Content-Disposition: form-data; name=\"Name\";" + lineEnd);
dos.writeBytes(lineEnd);
dos.writeBytes(Variable);
But the server never registers the parameters, how can i solve this?
Maybe you shuold build the POST request like the forrowing demo code? Hope it helps.
### Send a form with the text and file fields
POST https://httpbin.org/post
Content-Type: multipart/form-data; boundary=WebAppBoundary
--WebAppBoundary
Content-Disposition: form-data; name="Name"
myName
--WebAppBoundary
Content-Disposition: form-data; name="category"
myCategory
--WebAppBoundary
Content-Disposition: form-data; name="data"; filename=".gitignore"
Content-Type: application/json
< ./.gitignore
--WebAppBoundary--
<> 2019-09-23T045805.200.json
###

Correct way to upload video to youtube through API from android

i am working on a mobile app that record a video and upload to our Youtube acount so, i have a token and a refresh token, i can refresh the token when it expires, but i am not able to upload a video, here is a sample how i try :
override fun uploadFile(sourceFileUri: String) {
doAsync{
val fileName = sourceFileUri
var conn: HttpURLConnection? = null
var dos: DataOutputStream? = null
var lineEnd = "\r\n"
var twoHyphens = "--"
var upLoadServerUri = "https://www.googleapis.com/upload/youtube/v3/videos"
var boundary = "*****"
var bytesRead: Int
var bytesAvailable: Int
var bufferSize: Int
var buffer: ByteArray
var maxBufferSize = 1 * 1024 * 1024
var sourceFile = File(sourceFileUri)
try {
// open a URL connection to the Servlet
val fileInputStream = FileInputStream(sourceFile)
val url = URL(upLoadServerUri)
// Open a HTTP connection to the URL
conn = url.openConnection() as HttpURLConnection
conn.doInput = true // Allow Inputs
conn.doOutput = true // Allow Outputs
conn.useCaches = false // Don't use a Cached Copy
conn.requestMethod = "POST"
conn.setRequestProperty("Connection", "Keep-Alive")
conn.setRequestProperty("Authorization", "Bearer XXXXXXXXXX")
conn.setRequestProperty("Content-Type", "application/json")
conn.setRequestProperty("X-Upload-Content-Length", sourceFile.readBytes().size.toString())
conn.setRequestProperty("X-Upload-Content-Type", "video/mp4")
conn.setRequestProperty("part", "snippet,status")
conn.setRequestProperty("snippet.categoryId", "22")
conn.setRequestProperty("snippet.defaultLanguage", "")
conn.setRequestProperty("snippet.description", "Video evidencia carservice")
conn.setRequestProperty("snippet.tags[]", "")
conn.setRequestProperty("snippet.title", "Orden: 1500 Frenos")
conn.setRequestProperty("status.embeddable", "")
conn.setRequestProperty("status.license", "")
conn.setRequestProperty("status.privacyStatus", "private")
conn.setRequestProperty("status.publicStatsViewable", "")
dos = DataOutputStream(conn.outputStream);
// dos.writeBytes(twoHyphens + boundary + lineEnd)
// create a buffer of maximum size
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
buffer = ByteArray(bufferSize);
// read file and write it into form...
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0) {
dos.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
var serverResponseCode = conn.responseCode
val serverResponseMessage = conn.responseMessage
Log.i("uploadFile", "HTTP Response is : "
+ serverResponseMessage + ": " + serverResponseCode)
fileInputStream.close();
dos.flush();
dos.close();
} catch (e:Exception) {
e.printStackTrace()
}
}.execute()
}
i am getting: Bad Request: 400
i can't use the java library because these not have an option to upload video to our own acount
well, thanks in advance
i get an example from here
and try to adapt these, but i am not sure if is the correct way to do that
P.S. sorry for my bad english...

Android upload many files / images at once to a servlet with parameters

This can be same and can be seen as duplicate since there are many questions about uploading an image. But I want to know how to upload MANY images at a time to a servlet.That said, if there are 6 images in SD card, all should be uploaded within one request,not one by one. Most of samples over the internet are regarding one image or one file. I want to know if images are stored in a ArrayList, how they can be uploaded ?
In Servlet
List<FileItem> multiparts = new ServletFileUpload(
new DiskFileItemFactory()).parseRequest(request);
for(FileItem item : multiparts){
if(!item.isFormField()){
String name = new File(item.getName()).getName();
item.write( new File(UPLOAD_DIRECTORY + File.separator + name));
}
}
This part works fine as I tested with normal JSP multiplart many images uploads.
In android for one image upload (took from another source):
FileInputStream fileInputStream = new FileInputStream(new File(exsistingFileName) );
URL url = new URL(urlString);
conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
// Allow Outputs
conn.setDoOutput(true);
// Don't use a cached copy.
conn.setUseCaches(false);
// Use a post method.
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Content-Type", "multipart/form-data;boundary="+boundary);
dos = new DataOutputStream( conn.getOutputStream() );
dos.writeBytes(twoHyphens + boundary + lineEnd);
dos.writeBytes("Content-Disposition: form-data; name=\"uploadedfile\";filename=\"" + exsistingFileName +"\"" + lineEnd);
dos.writeBytes(lineEnd);
Log.e("MediaPlayer","Headers are written");
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
buffer = new byte[bufferSize];
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0)
{
dos.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
dos.writeBytes(lineEnd);
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
tv.append(inputLine);
// close streams
Log.e("MediaPlayer","File is written");
fileInputStream.close();
dos.flush();
dos.close();
This uploads only one image. How this can be used to send many with one POST request.? any other sample code or tutorial please.

Uploading files to skydrive using java

As per Skydrive api(http://msdn.microsoft.com/en-us/library/live/hh826531.aspx#uploading_files), I am passing the content of the image in byte[] in the body of the post request.
the file creation happens on the skydrive server, but when i open it in skydrive it says "the file appers to be damaged or corrupted".
body of the post request
--A300x
Content-Disposition: form-data; name="file"; filename="menu-icon.png"
Content-Type: application/octet-stream
[B#11f3043
--A300x--
the response from the server.
<html>
<head>
<script type="text/javascript">
window.location = "http://localtesting.com/mywebapp-1.0-SNAPSHOT#state=000000004C0FA618&result=%7b%22id%22%3a%22file.918bb0fbaf82f760.918BB0FBAF82F760!139%22%2c%22name%22%3a%22menu-icon.png%22%2c%22source%22%3a%22https%3a%2f%2f1m61va.tuk.livefilestore.com%2fy2mhncDTiOhUVFZxp08gi3yAFhp7OQ2-UYuQhnC_Obpoo4q5tG6onLuJz2mLJkJh6lUW5l8Cq2KBxvrLRrZ0bk6V7xmfso47cJWAw1fKE8bFJw%2fmenu-icon.png%3fdownload%26psid%3d1%22%7d";
</script>
</head>
</html>
code for converting the image into byte[]
byte[] image=FileUtils.readFileToByteArray(physicalfile);
Any clue?
EDIT:
Following is the code snippet I use
I'm taking some parts from properties file.
env.properties
part1=--A300x\u000d\u000aContent-Disposition: form-data; name=\"file\"; filename=\"
part2=\"\u000d\u000aContent-Type: application/octet-stream\u000d\u000a\u000d\u000a
part3=\u000d\u000a--A300x--
java file
String part1=bundle.getString("part1");
String part2= fileName+bundle.getString("part2");
String part3=bundle.getString("part3");
byte[] imageByteArray=FileUtils.readFileToByteArray(physicalfile);
PostMethod postMethod= new PostMethod("https://apis.live.net/v5.0/"+folderPath+"/files?state="+getSkydriveClientId()+"&redirect_uri="+baseURL+"&access_token="+getAcessToken());
postMethod.setRequestHeader("Content-Type","multipart/form-data; boundary=A300x");
postMethod.setRequestBody(part1+part2+imageByteArray+part3);
HttpClient httpClient=new HttpClient();
httpClient.executeMethod(postMethod);
You appear to be calling toString() on your byte array - that's what's converting it to [B#11f3043. You haven't shown us any of the code you're using to make the request, but basically you need to avoid calling toString(). I don't know whether the API accepts a byte[], but you should at least try to find a method which takes one, as that would be appropriate for your content.
EDIT: Looking at the sample code, it appears you can pass in an InputStream to LiveConnectClient.uploadAsync - so just wrap your byte[] in a ByteArrayInputStream.
Got it working with the following code snippet,after trimming spaces in client id and baseURL.
String BOUNDARY_STRING="A300x";
String urlString="https://apis.live.net/v5.0/"+folderPath+"/files?state="+getSkydriveClientId()+"&redirect_uri="+baseURL+"&access_token="+getAcessToken();
URL connectURL = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection) connectURL.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type","multipart/form-data; boundary=" + BOUNDARY_STRING);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestProperty("Connection", "Keep-Alive");
conn.connect();
DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
dos.writeBytes("--" + BOUNDARY_STRING + "\r\n");
dos.writeBytes("Content-Disposition: form-data; name=\"file\"; filename=\"" + fileName + "\"\r\n");
dos.writeBytes("Content-Type: application/octet-stream\r\n");
dos.writeBytes("\r\n");
File fileToUpload=Util.getFile(fileName);
FileInputStream fileInputStream = new FileInputStream(fileToUpload);
int fileSize = fileInputStream.available();
int maxBufferSize = 8192;
int bufferSize = Math.min(fileSize, maxBufferSize);
byte[] buffer = new byte[bufferSize];
int bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0) {
dos.write(buffer, 0, bytesRead);
int bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, buffer.length);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
fileInputStream.close();
dos.writeBytes("\r\n");
dos.writeBytes("--" + BOUNDARY_STRING + "--\r\n");
dos.flush();

HTTPURLConnection.getInputStream() Takes a very long time?

I'm uploading an image file using a HttpURLConnection which takes about 3 seconds for a 5MB file with all the headers, but the moment I open an InputStream with .getInputStream(), the method takes about 8+ seconds to return a stream with. Which is an issue because it seems the upload progress bar gives a bad UX if I have multiple images to upload, they have a considerable pause between each upload, so the progress bar just stops for a couple of seconds between uploads. I've done some googling but no one else seems to have an issue with it?
Normally I would assume the server is slow, but seeing as uploading only takes a couple of seconds, downloading the word 'success' or 'fail' shouldn't really be that much of an issue!
Heres some code! Am I setting anything up wrong initially?
Note: This is also within an AsyncTask
ByteArrayInputStream fileInputStream = null;
try {
fileInputStream = new ByteArrayInputStream(dObject.Data);
} catch (Exception e) {
e.printStackTrace();
}
String lineEnd = "\r\n";
String twoHyphens = "--";
String boundary = "*****";
String Tag="3rd";
try
{
//------------------ CLIENT RE QUEST
Log.e(Tag,"Inside second Method");
// Open a HTTP connection to the URL
URL url = new URL(_urlString);
//connectURL is a URL object
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// Allow Inputs
conn.setDoInput(true);
// Allow Outputs
conn.setDoOutput(true);
// Don't use a cached copy.
conn.setUseCaches(false);
// Use a post method.
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Content-Type", "multipart/form-data;boundary="+boundary);
DataOutputStream dos = new DataOutputStream( conn.getOutputStream() );
dos.writeBytes(twoHyphens + boundary + lineEnd);
//dos.writeBytes("Content-Disposition: form-data; name=\"uploadedfile\";filename=\"" + _fileLocation +"\"" + lineEnd);
dos.writeBytes("Content-Disposition: form-data; name=\"file\";filename=\"" + _fileLocation +"\"" + lineEnd);
dos.writeBytes(lineEnd);
Log.e(Tag,"Headers are written");
// create a buffer of maximum size
int bytesAvailable = fileInputStream.available();
int maxBufferSize = 1024;
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
byte[] buffer = new byte[bufferSize];
// read file and write it into form...
int bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0) {
dos.write(buffer, 0, bufferSize);
//int value = (int)(((float)((float)totalRead / (float) fileSize)) * 100);
totalRead += bytesRead;
//Publish the progress out to be displayed
publishProgress(totalRead);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
// send multipart form data necesssary after file data...
dos.writeBytes(lineEnd);
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
// close streams
Log.e(Tag,"File is written");
fileInputStream.close();
dos.flush();
Log.e("TIME", "PRE GETINPUTSTREAM");
InputStream is = conn.getInputStream();
Log.e("TIME", "POST GETINPUTSTREAM");
// retrieve the response from server
int ch;
//Build the respose and log
StringBuilder b =new StringBuilder();
while( ( ch = is.read() ) != -1 ){
b.append( (char)ch );
}
String s=b.toString();
Log.i("Response",s);
dos.close();
return;
}
catch (MalformedURLException ex)
{
ErrorHandler.get().e("3");
}
catch (IOException ioe)
{
ErrorHandler.get().e("2");
}
Normally I would assume the server is slow, but seeing as uploading only takes a couple of seconds, downloading the word 'success' or 'fail' shouldn't really be that much of an issue!
I suspect that it really is that the server is slow or overloaded.
The server could be queueing the HTTP requests and only processing a small number at a time in parallel.
Or it could have a bottleneck in some database activity that is performed before the response containing the file is written to the response.
Or it could be generating the file on the fly into an in-memory buffer (slow) and then streaming (fast) from the buffer to the HTTP response.
Or other explanations like this ...
(It is also theoretically possible that there is something funny going on that slows up the delivery of the request to the server. I would think this was unlikely though.)
Have you tried downloading the same file using a web browser? Do you get the same behaviour there?
In my case I found that getInputStream looks slow because this method initialize the ssl handshake (on a https URL call). After the first call, others calls are OK

Categories