I'm trying to build a small Java app for connecting to an application called CampFire and am running into trouble trying to upload files to the system. The Java code I'm using to upload a file is as follows:
public static String postFile(String requestUri, File f)
{
debug("Running postFile.");
logIn();
debug("Sending File: " + f.getAbsolutePath() + " to " + campFireURL + requestUri);
URL url;
URLConnection conn;
String linebreak = "\r\n";
String boundary = "**********xxx**********";
String twoHyphens = "--";
String result = "";
String request = twoHyphens + boundary + linebreak +
"Content-Disposition: form-data; name=\"upload\"; filename=\"" + f.getName() + "\"" + linebreak +
linebreak +
"";
debug("Request: " + request);
try
{
FileInputStream in = new FileInputStream(f);
auth.resetTries();
Authenticator.setDefault(auth);
// Send data
url = new URL(campFireURL + requestUri);
conn = url.openConnection();
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
wr.writeBytes(request);
int i;
while((i = in.read()) != -1)
{
wr.write(i);
}
wr.writeBytes(linebreak + twoHyphens + boundary + twoHyphens + linebreak);
wr.flush();
wr.close();
in.close();
result = readFromConnection(conn);
}
catch (Exception e)
{
debug(e);
JOptionPane.showMessageDialog(null, "Error running postData: " + e.getMessage(), "HTTP POST Error", JOptionPane.ERROR_MESSAGE);
die();
}
return(result);
}
When I run this with a real file though, I get the following errors...
Running postFile.
Sending File: /home/myuser/Desktop/blah.png to https://blah.campfirenow.com/room/blah/uploads.xml
Request: --**********xxx**********
Content-Disposition: form-data; name="upload"; filename="blah.png"
Server returned HTTP response code: 422 for URL: blah blah
java.io.IOException: Server returned HTTP response code: 422 for URL: blah blah
Any idea's what I'm doing wrong here? I'm fairly new at Java and am wondering if maybe I missed something obvious?
HTTP error 422 means "Unprocessable Entity". After a quick glance I can spot one mistake: a PNG file is a binary file. You've to add Content-Transfer-Encoding: binary to the header of the part.
If it still doesn't work, then you may find the example in the Uploading files section at the bottom of this answer useful.
Related
I am new to using HTTP and I have questions about writing a file and another value to an HTTP Post request in Java. I am using an public API provided by a company called Mojang to write what is known as a "skin" (a png file) to the game Minecraft for player character modles. Here is the documentation of how to use this public API for reference:https://wiki.vg/Mojang_API#Upload_Skin
Here is the code I have written. When ran I get the 415 HTTP Response code (which I assume is "unsupported media type"). Any suggestions on what I am doing wrong and how I can fix this? I found other stack overflow issues for uploading files but I need to also add a value called "variant={classic or slim}". I am a little lost on how to make all of this work. Any help is much appreciated.
(I could not get the code to properally format in the code sample using ' ', it is in a javascript snippet)
public static void uploadSkin(String accessToken, String variant, File file) throws IOException {
URL url = new URL("https://api.minecraftservices.com/minecraft/profile/skins");
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setDoOutput(true);
con.setRequestMethod("POST");
con.setRequestProperty("Authorization", "Bearer " + accessToken); // The access token is provided after an
// authentication request has been send, I
// have done this sucessfully in another
// method and am passing it in here
con.addRequestProperty("variant", variant);
OutputStream outputStream = con.getOutputStream();
PrintWriter writer = new PrintWriter(new OutputStreamWriter(con.getOutputStream(), "utf-8"), true);
String boundary = "===" + System.currentTimeMillis() + "===";
String fileName = file.getName();
String LINE_FEED = "\r\n";
String fieldName = "file";
writer.append("--" + boundary).append(LINE_FEED);
writer.append("Content-Disposition: form-data; name=\"" + fieldName + "\"; filename=\"" + fileName + "\"")
.append(LINE_FEED);
writer.append("Content-Type: " + URLConnection.guessContentTypeFromName(fileName)).append(LINE_FEED);
writer.append("Content-Transfer-Encoding: binary").append(LINE_FEED);
writer.append(LINE_FEED);
writer.flush();
FileInputStream inputStream = new FileInputStream(file);
byte[] buffer = new byte[4096];
int bytesRead = -1;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
outputStream.flush();
inputStream.close();
writer.append(LINE_FEED);
writer.flush();
}
Alright, found a solution to the problem. Using this maven dependency:
<!-- https://mvnrepository.com/artifact/org.jodd/jodd-http -->
<dependency>
<groupId>org.jodd</groupId>
<artifactId>jodd-http</artifactId>
<version>5.0.2</version>
</dependency>
And then this:
HttpResponse response = HttpRequest.post("https://api.minecraftservices.com/minecraft/profile/skins")
.header("Authorization", "Bearer " + accessToken).header("Content-Type", "multipart/form-data")
.form("variant", variant).form("file", file).send();
I was able to get it to work. Hope this is helpful to anyone that needs to upload a Skin Png file to Minecraft.
I am trying to upload two images along with some parameters to a server through my android application. After having searched online and following the instructions from here and here, as well as other sources, I have the following code:
String boundary = "***" + System.currentTimeMillis() + "***";
String twoHyphens = "--";
String crlf = "\r\n";
String output = "";
try {
HttpURLConnection httpUrlConnection = null;
URL url = new URL(myUrl);
httpUrlConnection = (HttpURLConnection) url.openConnection();
httpUrlConnection.setUseCaches(false);
httpUrlConnection.setDoInput(true);
httpUrlConnection.setDoOutput(true);
httpUrlConnection.setRequestMethod("POST");
httpUrlConnection.setRequestProperty("Connection", "Keep-Alive");
httpUrlConnection.setRequestProperty("Cache-Control", "no-cache");
httpUrlConnection.setRequestProperty("ENCTYPE", "multipart/form-data");
httpUrlConnection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
DataOutputStream request = new DataOutputStream(httpUrlConnection.getOutputStream());
request.writeBytes(twoHyphens + boundary + crlf);
// Convert and add first image
ByteArrayOutputStream bao1 = new ByteArrayOutputStream();
params[0].compress(Bitmap.CompressFormat.JPEG, 100, bao1);
byte[] ba1 = bao1.toByteArray();
request.writeBytes("Content-Disposition: form-data; name=\"image1\";filename=\"image1\"" + crlf);
request.writeBytes(crlf);
request.write(ba1);
request.writeBytes(crlf);
request.writeBytes(twoHyphens + boundary + crlf);
// Convert and add second image
ByteArrayOutputStream bao2 = new ByteArrayOutputStream();
params[1].compress(Bitmap.CompressFormat.JPEG, 100, bao2);
byte[] ba2 = bao2.toByteArray();
request.writeBytes("Content-Disposition: form-data; name=\"image2\";filename=\"image2\"" + crlf);
request.writeBytes(crlf);
request.write(ba2);
request.writeBytes(crlf);
request.writeBytes(twoHyphens + boundary + crlf);
request.writeBytes("Content-Disposition: form-data; name=\"username\"" + crlf);
request.writeBytes(crlf);
request.writeBytes(username);
request.writeBytes(crlf);
request.writeBytes(twoHyphens + boundary + twoHyphens);
request.writeBytes("Content-Disposition: form-data; name=\"datestr\"" + crlf);
request.writeBytes(crlf);
request.writeBytes(timeStampString);
request.writeBytes(crlf);
request.writeBytes(twoHyphens + boundary + twoHyphens);
request.flush();
request.close();
int responseCode = httpUrlConnection.getResponseCode();
if (responseCode == HttpsURLConnection.HTTP_OK) {
InputStream responseStream = new BufferedInputStream(httpUrlConnection.getInputStream());
BufferedReader responseStreamReader = new BufferedReader(new InputStreamReader(responseStream, Charset.forName("UTF-8")));
String line;
while ((line = responseStreamReader.readLine()) != null) {
output = line;
Log.d(TAG, line);
}
responseStreamReader.close();
}
httpUrlConnection.disconnect();
if (output == "") {
httpResultsReturned = false;
} else {
httpResultsReturned = true;
}
} catch (ProtocolException e) {
e.printStackTrace();
return "failed";
} catch (MalformedURLException e) {
e.printStackTrace();
return "failed";
} catch (IOException e) {
e.printStackTrace();
return "failed";
}
On the server side I try to access the data as follows:
<?php
if($_SERVER['REQUEST_METHOD'] === 'POST'){
$image1 = $_FILES['image1']['name'];
$image2 = $_FILES['image2']['name'];
$datestr= $_POST['datestr'];
$username= $_POST['username'];
}
?>
Eventually, both images are successfully transmitted, however I cannot send/receive the extra parameters. I receive the responses correctly, but throughout all the php code (there are parts that I omitted in this question), it seems like none of the parameters are sent/received.
In this question, AndroSco shared the solution that worked for him, but in his php file it looks like he only accesses the image and not the parameter...
Since I don't have a lot of experience on this field, I believe that there is probably something very obvious that I do incorrectly/don't do at all!
Any suggestions will be appreciated!
Thanks!
After much frustration, I found the bug in my code. After having imported the two images in the transmitted message and when I wanted to import the other parameters, I wrote the boundary incorrectly. Instead of adding this:
request.writeBytes(twoHyphens + boundary + crlf);
having a new line at the end, I wrote this:
request.writeBytes(twoHyphens + boundary + twoHyphens);
adding two hyphens at the end of the line.
After replacing the twoHyphens with crlf, everything worked nicely!
I've got a Node.js API that uses multer to handle multipart POST requests.
I am able to create a simple HTML form and POST images from there successfully.
I can also use postman to get the request to go through, but the req.file is always undefined on the server when I try to use my java method (below).
Called Method
public static void testPostImage() throws Exception {
String charset = "UTF-8";
String requestURL = "http://localhost:3000/accounts/2/details";
try {
File outputfile = new File(Util.getWorkingDirectory() + "/details");
MultipartUtility multipart = new MultipartUtility(requestURL, charset);
multipart.addFilePart("details", new File(outputfile.getAbsolutePath()));
List<String> response = multipart.finish();
General.println("SERVER REPLIED:");
for (String line : response) {
General.println(line);
}
} catch (IOException ex) {
General.println(ex);
}
}
The MultipartUtility class comes from this tutorial.
The contents of the constructor and 'addFilePart'...
Constructor
public MultipartUtility(String requestURL, String charset)
throws IOException {
this.charset = charset;
// creates a unique boundary based on time stamp
boundary = "===" + System.currentTimeMillis() + "===";
URL url = new URL(requestURL);
httpConn = (HttpURLConnection) url.openConnection();
httpConn.setUseCaches(false);
httpConn.setDoOutput(true); // indicates POST method
httpConn.setDoInput(true);
httpConn.setRequestProperty("Content-Type",
"multipart/form-data; boundary=" + boundary);
httpConn.setRequestProperty("User-Agent", "CodeJava Agent");
httpConn.setRequestProperty("Test", "Bonjour");
outputStream = httpConn.getOutputStream();
writer = new PrintWriter(new OutputStreamWriter(outputStream, charset),
true);
}
addFilePart
private static final String LINE_FEED = "\r\n";
public void addFilePart(String fieldName, File uploadFile)
throws IOException {
General.println("Sending to " + fieldName + ": " + uploadFile.getAbsolutePath());
// Add boundary
writer.append("--" + boundary).append(LINE_FEED);
// Add form data
writer.append("Content-Disposition: form-data;"
+ "name=\"myFile\";"
+ "filename=\"" + fieldName + "\""
+ "\nContent-Type: text/plain\n\n").append(LINE_FEED);
writer.append("Content-Type: " + "multipart/form-data").append(LINE_FEED);
writer.append("Content-Transfer-Encoding: binary").append(LINE_FEED);
writer.append(LINE_FEED);
writer.flush();
FileInputStream inputStream = new FileInputStream(uploadFile);
byte[] buffer = new byte[4096];
int bytesRead = -1;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
outputStream.flush();
inputStream.close();
writer.append(LINE_FEED);
writer.flush();
}
Their might be more to it but you don't have the right line ending between your Content-disposition and Content-type header:
// Add form data
writer.append("Content-Disposition: form-data;"
+ "name=\"myFile\";"
+ "filename=\"" + fieldName + "\"").append(LINE_FEED);
writer.append("Content-Type: text/plain").append(LINE_FEED).append(LINE_FEED); // need 2 line feeds
Also you are mixing the order/type of headers
writer.append("Content-Type: " + "multipart/form-data").append(LINE_FEED);
writer.append("Content-Transfer-Encoding: binary").append(LINE_FEED);
Should come before your encoded data.
See examples here
I made a andoid application in which I am getting response from php server, requesting in POST format. I am using below code for http connection:
// random string as boundary for multi-part http post
String strBoundary = "3i2ndDfv2rTHiSisAbouNdArYfORhtTPEefj3q2f";
String endLine = "\r\n";
OutputStream os;
String url = encodeUrl(methodType, graphURL, params);
Log.d("url - ",url);
Log.d("Method Type - ", methodType + " URL - " + url);
HttpURLConnection conn = (HttpURLConnection) new URL(url)
.openConnection();
conn.setConnectTimeout(60000);
conn.setReadTimeout(30000);
conn.setRequestProperty("User-Agent", System.getProperties()
.getProperty("http.agent"));
if (!methodType.equals("GET")) {
Bundle dataparams = new Bundle();
for (String key : params.keySet()) {
if (params.getByteArray(key) != null) {
dataparams.putByteArray(key, params.getByteArray(key));
}
}
// use method override
if (!params.containsKey("method")) {
params.putString("method", methodType);
}
if (params.containsKey("access_token")) {
#SuppressWarnings("deprecation")
String decoded_token = URLDecoder.decode(params
.getString("access_token"));
params.putString("access_token", decoded_token);
}
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type",
"multipart/form-data;boundary=" + strBoundary);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setRequestProperty("Connection", "Keep-Alive");
conn.connect();
os = new BufferedOutputStream(conn.getOutputStream());
os.write(("--" + strBoundary + endLine).getBytes());
os.write((encodePostBody(params, strBoundary)).getBytes());
os.write((endLine + "--" + strBoundary + endLine).getBytes());
if (!dataparams.isEmpty()) {
for (String key : dataparams.keySet()) {
os.write(("Content-Disposition: form-data; filename=\""
+ key + "\"" + endLine).getBytes());
os
.write(("Content-Type: content/unknown" + endLine + endLine)
.getBytes());
os.write(dataparams.getByteArray(key));
os.write((endLine + "--" + strBoundary + endLine)
.getBytes());
}
}
os.flush();
}
String response = "";
try {
response = parseXmlSvn(conn.getInputStream());
} catch (FileNotFoundException e) {
// Error Stream contains JSON that we can parse to a FB error
//response = read(conn.getErrorStream());
Log.i("RESPONSE",""+response);
}
Log.i("RESPONSE", ""+response);
return response;
Everything is working fine on my demo server, I uploaded my PHP service to clients server. I am getting proper response from his server also.
But when client access app in 3G or 4G in some other country in his android devices, he is getting Blank response while the same service of same server can be accessible in iOS code easily by him. Is it some packet loss while getting response or any other problem?
I would really appreciate any help you can give me.
Thanks
I would like to capture an image from the camera on Android, and send it to Google App Engine, which will store the image in the blob store. Sounds simple enough, and I can get the multi-part POST to GAE happening, but storing to the Blob store requires the servlet return an HTTP redirect (302). So, I need a connection that can follow redirects after doing an HTTP POST. Here is the code I WISH would work:
public static String sendPhoto(String myUrl, byte[] imageData) {
HttpURLConnection connection = null;
DataOutputStream outputStream = null;
String pathToOurFile = "/data/file_to_send.jpg";
String urlServer = myUrl;
String lineEnd = "\r\n";
String twoHyphens = "--";
String boundary = "*****";
// Please follow redirects
HttpURLConnection.setFollowRedirects(true);
BufferedReader rd = null;
StringBuilder sb = null;
String line = null;
try {
URL url = new URL(urlServer);
connection = (HttpURLConnection) url.openConnection();
// Allow Inputs & Outputs
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setUseCaches(false);
// I really want you to follow redirects
connection.setInstanceFollowRedirects(true);
connection.setConnectTimeout(10000); // 10 sec
connection.setReadTimeout(10000); // 10 sec
// Enable POST method
connection.setRequestMethod("POST");
connection.setRequestProperty("Connection", "Keep-Alive");
connection.setRequestProperty("Content-Type",
"multipart/form-data;boundary=" + boundary);
connection.connect();
outputStream = new DataOutputStream(connection.getOutputStream());
outputStream.writeBytes(twoHyphens + boundary + lineEnd);
outputStream
.writeBytes("Content-Disposition: form-data; name="
+ "\"file1\";filename=\""
+ pathToOurFile + "\"" + lineEnd);
outputStream.writeBytes(lineEnd);
outputStream.write(imageData);
outputStream.writeBytes(lineEnd);
outputStream.writeBytes(twoHyphens + boundary + twoHyphens
+ lineEnd);
outputStream.flush();
outputStream.close();
rd = new BufferedReader(new InputStreamReader(
connection.getInputStream()));
sb = new StringBuilder();
while ((line = rd.readLine()) != null) {
sb.append(line + '\n');
}
Log.i("Response: ", sb.toString());
// Responses from the server (code and message)
int serverResponseCode = connection.getResponseCode();
String serverResponseMessage = connection.getResponseMessage();
Log.i("Response: serverResponseCode:",
String.valueOf(serverResponseCode));
Log.i("Response: serverResponseMessage:", serverResponseMessage);
} catch (Exception ex) {
ex.printStackTrace();
}
}
As much as I try, this code will not follow redirects. The input steam is always empty, and the response is always 302. The image is uploaded nicely though. If someone could tell me what I can do to make it follow the redirect so I can read the response, I would really appreciate it.
Alternatively, if there is a better approach, I would love to hear it. I know there are libraries out there like Apache HTTP Client, but it requires so many dependencies that is seems like too much bloat for a simple task.
Thanks
A few months ago I was trying to do the exact same thing!
Basically, don't use HttpURLConnection. Instead, use HttpClient and HttpGet in the org.apache.http package which are part of the Android SDK.
Unfortunately I don't have my source code to provide an example, but hopefully that'll set you in the right direction.
not sure what went wrong, but you can follow redirect yourself. take the Location header out and make a new connection to it.