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
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'm trying to upload image to a image hosting site (fastpic.ru) but I can't get right response as I expected. I used fiddler to check would I send right param and everything seems are fine but I can't get right response. Could you guide me how to upload and get response in proper way?
Right response I mean I should receive something like http://fastpic.ru/session/2012/0425/Y6sEtGjtT1.html but I only receive http://fastpic.ru/index.php
Thank you
This is my code
String urlToConnect = "http://fastpic.ru/uploadmulti";
String boundary = Long.toHexString(System.currentTimeMillis()); // Generate random boundary
URLConnection connection = new URL(urlToConnect).openConnection();
connection.setDoOutput(true); // This sets request method to POST.
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
OutputStream output = null;
PrintWriter writer = null;
try {
output = connection.getOutputStream();
writer = new PrintWriter(new OutputStreamWriter(output, "UTF-8"), true); // true = Autoflush, important!
writer.println("-----------------------------" + boundary);
writer.println("Content-Disposition: form-data; name=\"file[]\"; filename=\"" + fileToUpload.getName() + "\"");
writer.println("Content-Type: image/jpeg");
writer.println();
InputStream input = null;
try {
input = new FileInputStream(fileToUpload);
byte[] buffer = new byte[1024];
for (int length = 0; (length = input.read(buffer)) > 0;) {
output.write(buffer, 0, length);
}
output.flush();
} finally {
if (input != null) {
try {
input.close();
} catch (IOException logOrIgnore) {
}
}
}
writer.println();
writer.println("-----------------------------" + boundary);
writer.println("Content-Disposition: form-data; name=\"submit\"");
writer.println();
writer.println("Загрузить");
writer.println("-----------------------------" + boundary);
writer.println("Content-Disposition: form-data; name=\"uploading\"");
writer.println();
writer.println("1");
writer.println("-----------------------------" + boundary + "--");
} finally {
if (writer != null) {
writer.close();
}
}
BufferedReader in = new BufferedReader(
new InputStreamReader(
connection.getInputStream()));
String decodedString;
while ((decodedString = in.readLine()) != null) {
System.out.println(decodedString);
}
in.close();
If it isn't returning the right output, there is probably something incorrect with the input.
I would recommend using the Apache HTTP components, such as MultipartEntity at http://hc.apache.org/httpcomponents-client-ga/httpmime/apidocs/org/apache/http/entity/mime/MultipartEntity.html for POSTing this kind of data. If you're trying to manually encode your data, it would be quite easy to make a simple mistake that'll stop the entire thing from working. There are a lot of examples using the Apache components, and its pretty simple to use.
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.
I am very new to java and servlet programming.
I am not sure whether it is possible to write a servlet which when passed a URL from the local client machine, uploads the file to the server.
basically on the client machine we have a C# program and on the server side we have Apache-tomcat installed. I need to upload file(s) to the server using C# program on client machine.
Should I provide any more information (?)
Thanks in Advance
Note this code illustrates the general idea and not guaranteed to work without modification.
The C# file upload part
// this code shows you how the browsers wrap the file upload request, you still can fine a way simpler code to do the same thing.
public void PostMultipleFiles(string url, string[] files)
{
string boundary = "----------------------------" + DateTime.Now.Ticks.ToString("x");
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.ContentType = "multipart/form-data; boundary=" + boundary;
httpWebRequest.Method = "POST";
httpWebRequest.KeepAlive = true;
httpWebRequest.Credentials = System.Net.CredentialCache.DefaultCredentials;
Stream memStream = new System.IO.MemoryStream();
byte[] boundarybytes =System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary +"\r\n");
string formdataTemplate = "\r\n--" + boundary + "\r\nContent-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}";
string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n Content-Type: application/octet-stream\r\n\r\n";
memStream.Write(boundarybytes, 0, boundarybytes.Length);
for (int i = 0; i < files.Length; i++)
{
string header = string.Format(headerTemplate, "file" + i, files[i]);
//string header = string.Format(headerTemplate, "uplTheFile", files[i]);
byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
memStream.Write(headerbytes, 0, headerbytes.Length);
FileStream fileStream = new FileStream(files[i], FileMode.Open,
FileAccess.Read);
byte[] buffer = new byte[1024];
int bytesRead = 0;
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
{
memStream.Write(buffer, 0, bytesRead);
}
memStream.Write(boundarybytes, 0, boundarybytes.Length);
fileStream.Close();
}
httpWebRequest.ContentLength = memStream.Length;
Stream requestStream = httpWebRequest.GetRequestStream();
memStream.Position = 0;
byte[] tempBuffer = new byte[memStream.Length];
memStream.Read(tempBuffer, 0, tempBuffer.Length);
memStream.Close();
requestStream.Write(tempBuffer, 0, tempBuffer.Length);
requestStream.Close();
try
{
WebResponse webResponse = httpWebRequest.GetResponse();
Stream stream = webResponse.GetResponseStream();
StreamReader reader = new StreamReader(stream);
string var = reader.ReadToEnd();
}
catch (Exception ex)
{
response.InnerHtml = ex.Message;
}
httpWebRequest = null;
}
and to understand how the above code was written you might wanna take a look at How does HTTP file upload work?
POST /upload?upload_progress_id=12344 HTTP/1.1
Host: localhost:3000
Content-Length: 1325
Origin: http://localhost:3000
... other headers ...
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryePkpFF7tjBAqx29L
------WebKitFormBoundaryePkpFF7tjBAqx29L
Content-Disposition: form-data; name="MAX_FILE_SIZE"
100000
------WebKitFormBoundaryePkpFF7tjBAqx29L
Content-Disposition: form-data; name="uploadedfile"; filename="hello.o"
Content-Type: application/x-object
... contents of file goes here ...
------WebKitFormBoundaryePkpFF7tjBAqx29L--
and finally all you have to do is to implement a servlet that can handle the file upload request, then you do whatever that you want to do with the file, take a look at this file upload tutorial
protected void processRequest(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
// Create path components to save the file
final String path = request.getParameter("destination");
final Part filePart = request.getPart("file");
final String fileName = getFileName(filePart);
OutputStream out = null;
InputStream filecontent = null;
final PrintWriter writer = response.getWriter();
try {
out = new FileOutputStream(new File(path + File.separator
+ fileName));
filecontent = filePart.getInputStream();
int read = 0;
final byte[] bytes = new byte[1024];
while ((read = filecontent.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
writer.println("New file " + fileName + " created at " + path);
LOGGER.log(Level.INFO, "File{0}being uploaded to {1}",
new Object[]{fileName, path});
} catch (FileNotFoundException fne) {
writer.println("You either did not specify a file to upload or are "
+ "trying to upload a file to a protected or nonexistent "
+ "location.");
writer.println("<br/> ERROR: " + fne.getMessage());
LOGGER.log(Level.SEVERE, "Problems during file upload. Error: {0}",
new Object[]{fne.getMessage()});
} finally {
if (out != null) {
out.close();
}
if (filecontent != null) {
filecontent.close();
}
if (writer != null) {
writer.close();
}
}
}
private String getFileName(final Part part) {
final String partHeader = part.getHeader("content-disposition");
LOGGER.log(Level.INFO, "Part Header = {0}", partHeader);
for (String content : part.getHeader("content-disposition").split(";")) {
if (content.trim().startsWith("filename")) {
return content.substring(
content.indexOf('=') + 1).trim().replace("\"", "");
}
}
return null;
}