Ruby : uploaded files suddenly become not found within hours in heroku - java

I have the following post code for Ruby Sinatra to upload image files :
post "/upload" do
File.open("public/uploads/" + params["image"][:filename], "wb") do |f|
f.write(params["image"][:tempfile].read)
end
end
And the following Java codes to upload the image file to example.com/upload :
private static String boundary;
private static final String LINE_FEED = "\r\n";
private static HttpURLConnection httpConn;
private static OutputStream outputStream;
private static PrintWriter writer;
public static void upload(String requestURL, String fieldName, File
uploadFile) throws IOException {
boundary = "===" + System.currentTimeMillis() + "===";
URL url = new URL(requestURL);
httpConn = (HttpURLConnection) url.openConnection();
httpConn.setUseCaches(false);
httpConn.setDoOutput(true);
httpConn.setDoInput(true);
httpConn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
outputStream = httpConn.getOutputStream();
writer = new PrintWriter(new OutputStreamWriter(outputStream, "UTF-8"), true);
String fileName = uploadFile.getName();
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).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("--" + boundary + "--").append(LINE_FEED);
writer.close();
httpConn.getInputStream();
httpConn.disconnect();
}
File uploadFile = new File("C:/myimage.png");
upload("http://www.example.com/upload", "image", uploadFile);
And my website is hosted at heroku .
After calling upload(), the image file is successfully uploaded, and i can access to it in example.com/upload/myimage.png
But the problem is : After some hours, when i check the url to see myimage.png, i got "Not Found" error ( 404 error in heroku logs )
Any ideas ?
Sorry for my bad english :|

You should not store files to heroku's local file system. From their docs:
Ephemeral filesystem
Each dyno gets its own ephemeral filesystem, with
a fresh copy of the most recently deployed code. During the dyno’s
lifetime its running processes can use the filesystem as a temporary
scratchpad, but no files that are written are visible to processes in
any other dyno and any files written will be discarded the moment the
dyno is stopped or restarted.
Instead of storing files locally it is recommended to upload files to AWS S3 or other cloud storage systems.

Related

Invalid image POST request JAVA

I try to upload an image file with POST request and get the following response from server:
Notice: Undefined index: width in /home/api.webbankir.com/methods/photo.php on line 32
Notice: Undefined index: width in /home/api.webbankir.com/methods/photo.php on line 37
Notice: Undefined index: height in /home/api.webbankir.com/methods/photo.php on line 32
Notice: Undefined index: height in /home/api.webbankir.com/methods/photo.php on line 37
Fatal error: Uncaught exception 'Exception' with message 'Invalid image:
/home/api.webbankir.com/tmp/d9864480da25e440ff4d591498881e79.jpg' in
/home/api.webbankir.com/include/Simpleimage.php:1081
Stack trace:#0 /home/api.webbankir.com/include/Simpleimage.php(512): SimpleImage->get_meta_data()
#1/home/api.webbankir.com/methods/photo.php(97): SimpleImage-
>load('/home/api.webba...')
#2 /home/api.webbankir.com/methods/photo.php(411): Photo->load(Array)
#3 {main}thrown in /home/api.webbankir.com/include/Simpleimage.php on line 1081
Here is my JAVA code:
HttpURLConnection connection = null;
DataOutputStream outputStream = null;
String lineEnd = "\r\n";
String twoHyphens = "--";
String boundary = "*****";
int bytesAvailable, bufferSize;
byte[] buffer;
int maxBufferSize = 1024 * 1024;
try {
connection = null;
URL url = new URL(url_link);
connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setUseCaches(false);
connection.setRequestMethod("POST");
connection.setRequestProperty("Connection", "Keep-Alive");
connection.setRequestProperty("ENCTYPE", "multipart/form-data");
connection.setRequestProperty("Content-Type", "multipart/form-data;boundary="+boundary);
connection.setRequestProperty("file", "img_webbankir.jpeg");
outputStream = new DataOutputStream( connection.getOutputStream() );
outputStream.writeBytes(twoHyphens + boundary + lineEnd);
outputStream.writeBytes("Content-Disposition: form-data; name=\"file\"; filename=\"" + "img_webbankir.jpeg" +"\"" + lineEnd); /* img_webbankir.jpeg */
outputStream.writeBytes(lineEnd);
bufferSize = Math.min(bytesAvailable, maxBufferSize);
buffer = new byte[bufferSize];
int dimension = Math.min(bitmap.getWidth(), bitmap.getHeight());
bitmap = ThumbnailUtils.extractThumbnail(bitmap, dimension, dimension);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
b = baos.toByteArray();
imageEncoded = Base64.encodeToString(b, Base64.DEFAULT);
outputStream.writeBytes(imageEncoded);
outputStream.writeBytes(lineEnd);
outputStream.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
// Responses from the server (code and message)
int serverResponseCode = connection.getResponseCode();
String serverResponseMessage = connection.getResponseMessage();
Log.e("log", "response code = " + serverResponseCode);
Log.e("log", "response message = " + serverResponseMessage);
outputStream.flush();
outputStream.close();
Log.e("log", "out put stream closed");
BufferedReader bufferedReader = new BufferedReader(new
InputStreamReader(connection.getInputStream()));
String line = "";
StringBuilder stringBuilder = new StringBuilder();
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line).append("\n");
}
bufferedReader.close();
response = stringBuilder.toString();
connection.disconnect();
} catch (IOException e) {
e.printStackTrace();
Log.e("Log", "error " + e);
}
I've tried the same request using OkHttp but got the same response...
I've also tried different ways of encoding the bitmap...
Will be grateful for help
Your client is in Java but error messages are from PHP. Therefore, it is server issue. Or you are not using server API properly. Are you integrating with 3-rd party, documented API or with your own PHP server?
If with your own server, you can debug the issue.
If we 3rd party API you should check their documentation if you are using API properly.
PS
for java rest client there are better, higher level tools than HttpURLConnection. Consider using https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html from spring.
https://github.com/square/okhttp or http://square.github.io/retrofit/ are also good choices. Your client code will be much shorter (2-5 lines, not 70), you will work on higher level of abstraction.
To reproduce the problem, please reproduce same post request with tools like Postman. https://www.getpostman.com/
That will rule out posibility of bug in your java code.

Missing bytes when uploading zip file with multipart/form-data using java

I'm having an issue with uploading a .zip file to a remote server in that some bytes are missing from the file after the upload. Upon redownloading the file, the .zip archive is unopenable, which leads me to believe that I need those bytes to perform the upload successfully.
I am using a multipart/form-data POST request to upload the file. The utility helper class I use to do this is given in the below code:
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
public class MultipartFormDataUtil {
private final String boundary;
private static final String lineReturn = "\r\n";
private HttpURLConnection conn;
private DataOutputStream dos;
int bytesRead, bytesAvail, bufferSize;
byte[] buffer;
int maxBufferSize = 1*1024*1024;
List<String> response;
public MultipartFormDataUtil(String postUrl, LinkedHashMap<String, String> params, File file) throws IOException {
boundary = "=-=" + System.currentTimeMillis() + "=-=";
URL url = new URL(postUrl);
conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
dos = new DataOutputStream(conn.getOutputStream());
for (String key : params.keySet()) {
addFormPart(key, params.get(key));
}
addFilePart(file);
finish();
}
private void addFormPart(String name, String value) throws IOException {
dos.writeBytes("--" + boundary + lineReturn);
dos.writeBytes("Content-Disposition: form-data; name=\"" + name + "\"" + lineReturn);
dos.writeBytes("Content-Type: text/plain" + lineReturn + lineReturn);
dos.writeBytes(value + lineReturn);
dos.flush();
}
private void addFilePart(File file) throws IOException {
FileInputStream fileInputStream = new FileInputStream(file);
dos.writeBytes("--" + boundary + lineReturn);
dos.writeBytes("Content-Disposition: form-data; name=\"file\"; filename=\"" + file.getName() + "\"" + lineReturn);
dos.writeBytes("Content-Type: " + URLConnection.guessContentTypeFromName(file.getName()) + lineReturn);
dos.writeBytes("Content-Transfer-Encoding: binary" + lineReturn + lineReturn);
bytesAvail = fileInputStream.available();
bufferSize = Math.min(bytesAvail, maxBufferSize);
buffer = new byte[bufferSize];
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0) {
dos.write(buffer, 0, bufferSize);
bytesAvail = fileInputStream.available();
bufferSize = Math.min(bytesAvail, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
dos.flush();
dos.writeBytes(lineReturn);
dos.flush();
fileInputStream.close();
}
private void finish() throws IOException {
response = new ArrayList<String>();
dos.writeBytes("--" + boundary + "--" + lineReturn);
dos.flush();
dos.close();
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
response.add(line);
}
reader.close();
conn.disconnect();
}
public List<String> getResponse() {
return response;
}
To give credit where credit is due, this utility is based off of examples from Peter's Notes and CodeJava.net. This util is called with the following code:
protected static void postFile(String url, LinkedHashMap<String, String> params, File file) throws Exception {
try {
MultipartFormDataUtil multipartRequest = new MultipartFormDataUtil(url, params, file);
List<String> response = multipartRequest.getResponse();
for (String line : response) {
System.out.println(line);
}
} catch (IOException ioe) {
log.warn("There was an error posting the file and form data", ioe);
}
}
The upload url in this case is to an Amazon S3 bucket, which passes it on to the destination system. It is at this final destination that I can see that the process that is supposed to be running on the .zip file has failed (note: the process is run by a Rails app and gives the error "Error identifying package type: can't dup NilClass"). Upon downloading the file, I see that the file size is 3,110,416 bytes instead of 3,110,466 bytes. I can no longer extract the archive to see what is in it; the mac archive utility responds with "Error 2 - No such file or directory".
I lack the conceptual background in this area to get a feel for where in the process things may be going wrong. I am hoping that someone will be able to tell me that I made an error in the utility class, or let me know that something else is the problem.
Thank you for any insight you can provide, and let me know if I can post anything else that would be of help.
EDIT: Some additional information I gathered about different sizes of file uploads (in bytes):
Original----------Uploaded----------Difference
10,167,389______10,167,238______151
3,110,466_______3,110,416_______50
156,885_________156,885_________0
95,639,352______95,637,925______1,427
For the 3 files that had bytes missing following the upload, the % of total data lost was around (but not exactly) 0.0015% for each one, but not equal to each other.
Upon some further research, we found that the error did not have anything to do with the multipart/form-data utility as shown in this question. Instead, it had to do with our own file downloading client in here. We were not setting the FileTransfer client to download the file as binary, which is necessary for a .zip file.
Feel free to use the code included in the original question for your multipart/form-data purposes in java - it works great assuming there are no problems with your original file.

Parse upload to a class using REST java

I want to upload file to a class myclass in parse.com .Now, when I use the URL as https://api.parse.com/1/files/hello, I get the response message Created and the location of the file in the header. But, when I try to upload it to the class, I get the response message :- Bad Request and the header says that it is a 400 request. What am I doing wrong?
String name = "file.txt";
URL url = new URL("https://api.parse.com/1/classes/myclass/hello");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setDoOutput(true);
httpConn.setRequestMethod("POST");
httpConn.setRequestProperty("X-Parse-Application-Id", "App_Id");
httpConn.setRequestProperty("X-Parse-REST-API-Key", "APp_KeY");
httpConn.setRequestProperty("Content-type", "text/plain");
OutputStream outputStream = httpConn.getOutputStream();
File uploadFile = new File("F:\\file.txt");
InputStream inputStream = new FileInputStream(uploadFile);
byte[] buffer = new byte[4096];
int bytesRead = -1;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
outputStream.close();
inputStream.close();
System.out.println("Response message : " + httpConn.getResponseMessage());
You can't upload using your class name I guess. What I do is first upload the file and then insert it into the class. I will be using Java since you have used java. So, first upload your file using https://api.parse.com/1/files/hello. Then you will get the location of the file in the header received. You can get it using httpConn.getResponseHeader("Location");. Now that will give you the entire url of the file. But you need only the name. You can extract it by this code:-
String ar[] = location.split("[/]");
String name = ar[ar.length - 1];
Now, insert it into your class. But before inserting, you have to make sure that you have a column that has data type of File in your class. Now, insert it into your class using this code :-
httpConn.setDoOutput(true);
httpConn.setRequestMethod("POST");
httpConn.setRequestProperty("X-Parse-Application-Id", "App_Id");
httpConn.setRequestProperty("X-Parse-REST-API-Key", "APp_KeY");
httpConn.setRequestProperty("Content-type", "application/json");
String json = "{\"myclass\":"
+ "{ "
+ "\"name\":\"" + name + "\","
+ "\"__type\": \"File\""
+ "}"
+ "}";
httpConn.getOutputStream().write(json.getBytes());
So, you have to make 2 requests in total.

No Response on Google App Engine Java Blobstore Upload from Android

I'm attempting to upload an image to the blobstore from Android but when my server servlet is called upon completion, the Blobstore fails to hand off any BlobKeys. And when I check the actual blobstore, no image has been uploaded. There is no error code, no warnings, no errors, nothing. Now I know the server stuff works because the upload works in iOS. And the Android code works just fine on the local development server but it's not working in production. I'm hoping that maybe someone can spot an error in my code.
Thanks in advance.
HttpURLConnection connection = null;
try {
Log.d(LOG_TAG, "Starting multipart POST request to: " +fullUrlValue);
URL fullUrl = new URL(fullUrlValue);
//make server call
connection = getClient().getConnection(fullUrl, RequestMethod.POST);
connection.setConnectTimeout(60000); //60 seconds to complete an upload
connection.setUseCaches(false);
connection.setDoInput(true);
connection.setDoOutput(true);
//see if we are streaming the upload
if(requestOptions == null || requestOptions.isChunckedStreamingMode())
{
connection.setChunkedStreamingMode(2048);
}
String boundry = "z6fQbdm2TTgLwPQj9u1HjAM25z9AJuGSx7WG9dnD";
connection.setRequestProperty("Connection", "Keep-Alive");
connection.setRequestProperty("Cache-Control", "no-cache");
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundry);
//attach post objects
DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream());
//add form fields
if(additionalParameters != null && additionalParameters.keySet().size() > 0)
{
Iterator<String> it = additionalParameters.keySet().iterator();
while(it.hasNext())
{
String fieldName = it.next();
if(fieldName != null)
{
String value = additionalParameters.get(fieldName);
if(value != null)
{
//add form field to upload form
outputStream.writeBytes("--" + boundry + "\r\n" + "Content-Disposition: form-data; name=\"" + fieldName + "\"\r\nContent-Type: text/plain; charset=UTF-8\r\n\r\n"+value+"\r\n");
}
}
}
}
//attach file
if(postObjectBytes != null)
{
//build the request body
outputStream.writeBytes("--" + boundry + "\r\n" + "Content-Disposition: form-data; name=\"" + formElementName + "\";filename=\"" + fileName + "\"\r\n\r\n");
//object upload content size
long totalUploadSize = postObjectBytes.length;
//we have to manually process the stream in order to correctly update the progress listener
byte[] buffer = new byte[2048];
long totalBytes = 0;
int bytesRead = 0;
InputStream inputStream = new ByteArrayInputStream(postObjectBytes);
while ((bytesRead = inputStream.read(buffer)) > -1) {
totalBytes += bytesRead;
outputStream.write(buffer, 0, bytesRead);
if(progressListener != null){
progressListener.transferred(totalBytes, totalUploadSize);
}
}
outputStream.writeBytes("\r\n--" + boundry + "--\r\n");
}
outputStream.flush();
outputStream.close();
Well, I found the answer thanks to AppEngine BlobStore upload failing with a request that works in the Development Environment .
Apparently I was missing a space between the semi-colon and the start of "filename". That's just insane.
formElementName + "\";filename

Image writing over URLConnection

I am trying to write an image over an HttpURLConnection.
I know how to write text but I am having real problems trying
to write an image
I have succeeded in writing to the local HD using ImageIO:
But I am trying to write Image by ImageIO on url and failed
URL url = new URL(uploadURL);
connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setDoInput(true);
connection.setUseCaches(false);
connection.setRequestProperty("Content-Type", "multipart/form-data;
boundary=" + boundary);
output = new DataOutputStream(connection.getOutputStream());
output.writeBytes("--" + boundary + "\r\n");
output.writeBytes("Content-Disposition: form-data; name=\"" + FIELD_NAME + "\";
filename=\"" + fileName + "\"\r\n");
output.writeBytes("Content-Type: " + dataMimeType + "\r\n");
output.writeBytes("Content-Transfer-Encoding: binary\r\n\r\n");
ImageIO.write(image, imageType, output);
the uploadURL is the url to an asp page on the server which will upload the image with the file name given in "content-Disposition: part.
now when I send this then asp page find the request and find the name of file. but does not find the file to be uploaded.
The problem is that when writing by ImageIO on URL what will the name of the file on which the ImageIO is writing,
So please help me how ImageIO will write an image on URLConnection and how can I know the name of the file which I have to use in the asp page to upload the file
Thanks for taking the time to read this post
Dilip Agarwal
First I believe that you should call io.flush() and then io.close() after writing image.
Second content type seems strange for me. It seems that you are trying to submit form while it is actually image. I do not know what does your asp expect but typically when I write code that should transfer file over HTTP I send appropriate content type, e.g. image/jpeg.
Here is for example code snippet I extracted from one small utility that I wrote and I am using during my current work:
URL url = new URL("http://localhost:8080/handler");
HttpURLConnection con = (HttpURLConnection)url.openConnection();
con.setDoInput(true);
con.setDoOutput(true);
con.setUseCaches(false);
con.setRequestProperty("Content-Type", "image/jpeg");
con.setRequestMethod("POST");
InputStream in = new FileInputStream("c:/temp/poc/img/mytest2.jpg");
OutputStream out = con.getOutputStream();
copy(in, con.getOutputStream());
out.flush();
out.close();
BufferedReader r = new BufferedReader(new InputStreamReader(con.getInputStream()));
// obviously it is not required to print the response. But you have
// to call con.getInputStream(). The connection is really established only
// when getInputStream() is called.
System.out.println("Output:");
for (String line = r.readLine(); line != null; line = r.readLine()) {
System.out.println(line);
}
I used here method copy() that I took from Jakarta IO utils. Here is the code for reference:
protected static long copy(InputStream input, OutputStream output)
throws IOException {
byte[] buffer = new byte[12288]; // 12K
long count = 0L;
int n = 0;
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
count += n;
}
return count;
}
Obviously the server side must be ready to read the image content directly from POST body.
I hope this helps.
The OP seems lost into oblivion but for the benefit of Mister Kite :
// main method
URL url = new URL(uploadURL);
connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true); // triggers "POST"
// connection.setDoInput(true); // only if needed
connection.setUseCaches(false); // dunno
final String boundary = Long.toHexString(System.currentTimeMillis());
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary="
+ boundary);
output = new DataOutputStream(connection.getOutputStream());
try {
// image must be a File instance
flushMultiPartData(image, output, boundary);
} catch (IOException e) {
System.out.println("IOException in flushMultiPartData : " + e);
return;
}
// ...
private void flushMultiPartData(File file, OutputStream serverOutputStream,
String boundary) throws FileNotFoundException, IOException {
// SEE https://stackoverflow.com/a/2793153/281545
PrintWriter writer = null;
try {
// true = autoFlush, important!
writer = new PrintWriter(new OutputStreamWriter(serverOutputStream,
charsetForMultipartHeaders), true);
appendBinary(file, boundary, writer, serverOutputStream);
// End of multipart/form-data.
writer.append("--" + boundary + "--").append(CRLF);
} finally {
if (writer != null) writer.close();
}
}
private void appendBinary(File file, String boundary, PrintWriter writer,
OutputStream output) throws FileNotFoundException, IOException {
// Send binary file.
writer.append("--" + boundary).append(CRLF);
writer.append(
"Content-Disposition: form-data; name=\"binaryFile\"; filename=\""
+ file.getName() + "\"").append(CRLF);
writer.append("Content-Type: "
+ URLConnection.guessContentTypeFromName(file.getName()))
.append(CRLF);
writer.append("Content-Transfer-Encoding: binary").append(CRLF);
writer.append(CRLF).flush();
InputStream input = null;
try {
input = new FileInputStream(file);
byte[] buffer = new byte[1024];
for (int length = 0; (length = input.read(buffer)) > 0;) {
output.write(buffer, 0, length);
}
output.flush(); // Important! Output cannot be closed. Close of
// writer will close output as well.
} finally {
if (input != null) try {
input.close();
} catch (IOException logOrIgnore) {}
}
writer.append(CRLF).flush(); // CRLF is important! It indicates end of
// binary boundary.
}
You may want to add Gzip compression - see file corrupted when I post it to the servlet using GZIPOutputStream for a working class with or without Gzip. The ImageIO has no place here - just write the bytes past the wire and use ImageIO to your heart's content on the server. Based on #BalusC answer

Categories