How to upload binary file using URLConnection - java

In order to upload a binary file to an URL, I have been advised to use this guide. However, the file is not in a directory, but is stored in a BLOB field in MySql db. The BLOB field is mapped as a byte[] property in JPA:
byte[] binaryFile;
I have slightly modified the code taken from the guide, in this way:
HttpURLConnection connection = (HttpURLConnection ) new URL(url).openConnection();
// set some connection properties
OutputStream output = connection.getOutputStream();
PrintWriter writer = new PrintWriter(new OutputStreamWriter(output, CHARSET), true);
// set some headers with writer
InputStream file = new ByteArrayInputStream(myEntity.getBinaryFile());
System.out.println("Size: " + file.available());
try {
byte[] buffer = new byte[4096];
int length;
while ((length = file.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
output.flush();
writer.append(CRLF).flush();
writer.append("--" + boundary + "--").append(CRLF).flush();
}
// catch and close streams
I am not using chunked streaming. The headers used are:
username and password
Content-Disposition: form-data; name=\"file\"; filename=\"myFileName\"\r\nContent-Type: application/octet-stream"
Content-Transfer-Encoding: binary
All the headers are received correctly by the host. It also receives the uploaded file, but unfortunately complains that the file is not readable, and asserts that the size of the received file is 37 bytes larger than the size outputed by my code.
My knowledge of streams, connections and byte[] is too limited for grasping the way to fix this. Any hints appreciated.
EDIT
As suggested by the commenter, I have tried also to write the byte[] directly, without using the ByteArrayInputStream:
output.write(myEntity.getBinaryFile());
Unfortunately the host gives exactly the same answer as the other way.

My code was correct.
The host was giving an error because it didn't expect the Content-Transfer-Encoding header. After removing it, everything went fine.

Related

How send the http post request with DataOutPutStream properly so server can handle it

I wish somebody tell me what is the different of just write a file and a file with another kind of bytes.
server using, python3 flask
I think maybe the android retrofit etc useful, but I would like to try with the classic method, HTTPUrlConnection
So i successfully sending just one or multi-parameter of string to the server.
I also successfully just by sending a file to the server.
- my file will just 5-second audio or video mp4 that creates from real android.
When i tried just two, param and a list of byte, len(list) = 2, i can get back my sent file, but the concat style of the bytes just could not acheive it.
but when I combine both of it, i found out that when the file is chopped as multi-part, the file just could not recover.
I know delimeter is useful, I tried with a string of "--------------" to split it in server-side.
list= request.data.split(b"------------------------------")
newList= list[1:]
data = b""
for part in newList:
data += part
how i recover the file (python)
def createAudioFromDataReceived(fileName, data):
with open(fileName, 'wb') as wfile:
wfile.write(data)
the basic code write to dataOutPutStream
public void writeFilesParamToDataOutputStream(HttpURLConnection conn, File file, String action) throws IOException {
byte[] buffer;
FileInputStream fileInputStream = new FileInputStream(file);
DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
buffer = new byte[1024 * 1024];
int length = 0;
while ( ( length = fileInputStream.read( buffer ) ) > 0 ) {
dos.write(buffer, 0, length);
}
dos.flush();
fileInputStream.close();
dos.close();
}
to add extra line to the dataOutputStream
//Bytes
byte[] bytes = "toSend".getBytes();
dos.write(bytes);
dos.write("------------------------------");
ops, reference are seen before
roughly this kind How to send data from server to Android?
i could not imagine the byte got alot of "-" and need "/r/n" ...
delimiter should be some thing like
String delimiter = "--aaWEdFXvDF--" + "\r\n";

Is there a way to combine a outputstream and printwriter in one request?

I have to do a file transfer, in my case a pdf, through socket in java for my homework. Usually I requested text and got text back, but this time I have to send a file through socket. In my investigation I discovered that file transfers are made with Fileinput(output)streams. My problem is that the request to the server has to look something like this:
File file = new File(pathToFile);
Pirntwriter out = new PrintWriter(Socket s.getOutputStream());
Outputstream outFile = s.getOutputStream();
int count
out.write("user file\r\n"
+ file.getName()+"\r\n"
+ file.length()+"\r\n"
+ "body\r\n");
// send file but im not sure how
byte[] buffer = new buffer with size of file.length()
while ((count = in.read(buffer)) > 0){
outFile.write(buffer, 0, count);
}
out.flush
outFile.flush
Unfortunately this doesn't work for me. In this way the server counts the requests as two different outputs. Is there a way to combine both Outputstreams or write the request in one single Outputstream?

gzip/deflate compression with Server Sent Events on tomcat servlet

I am using server sent events for streaming responses (text/event-stream). We want to compress the response using gzip or deflate compression, but the browser shows : ERR_CONTENT_DECODING_FAILED.
Code for the same -
response.setContentType("text/event-stream; charset=UTF-8");
response.addHeader("Connection", "keep-alive");
response.addHeader("Cache-Control", "no-cache, must-revalidate");
response.addHeader("Content-Encoding", "deflate");
PrintWriter writer = response.getWriter();
number = 10;
time = 100;
for (int i = 0; i < number; i++) {
String resp = "data: " + "Some Response" + "\r\n";
Deflater deflater = new Deflater(Deflater.DEFLATED);
byte[] input = resp.getBytes("UTF-8");
deflater.setInput(input);
deflater.finish();
byte[] output = new byte[1024];
deflater.deflate(output);
deflater.end();
writer.write(new String(output, "UTF-8"));
writer.flush();
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
String resp = "data: close\r\n";
Deflater deflater = new Deflater(Deflater.DEFLATED);
byte[] input = resp.getBytes("UTF-8");
deflater.setInput(input);
deflater.finish();
byte[] output = new byte[1024];
deflater.deflate(output);
deflater.end();
writer.write(new String(output, "UTF-8"));
writer.flush();
Compressed stream is binary data. It must not be printed with response.getWriter(). Use response.getOutputStream() instead.
UPDATE
Shiva Bhalla: Using the response.getOutputStream() with text/event-stream isn't doing proper streaming after the 1st chunk of response is displayed, the request is being failed at the browser.
You have to compress the whole stream using a single Deflater instance.
In your code you compress each fragment separately. This is equivalent to the following:
You take a series of text files (01.txt, 02.txt, ...).
You compress each of them into a gzip archive. (01.txt.gz, 02.txt.gz, ...)
You concatenate the archives into a single file.
The above produces an incorrect archive. Gzip files cannot be concatenated like that. The correct code should do the following:
You take a series of text files (01.txt, 02.txt, ...).
You concatenate the text files into a single file (text.txt).
You compress the file into a gzip archive. (text.txt.gz)
I recommend you to use a java.util.zip.DeflaterOutputStream (1) instead of direct use of a Deflater. E.g.
new DeflaterOutputStream(response.getOutputStream(), true);
Beware of introducing a BREACH vulnerability.
Adding "text/event-stream;charset=UTF-8,ms-stream;charset=UTF-8" as "compressableMimeType" in connector properties did the job!

Extracting image from a request body results with a corrupted image (Spring MVC)

I have a problem that has been bugging me a whole week and I have come to a dead end.
This is the scenario: I have a method in a Java Spring Controller that handles a HTTP POST request. The POST request contains a picture. The twist is that the picture is not sent as multipart request, it is sent in the RequestBody (note for the answers saying to change the way of sending the picture: I have no access or possibility of doing this, I have to do with what I have).
So i extract the picture by using the input stream from the request. Then I open an Output stream and then write to the file, while I am reading from the input stream.
InputStream is = request.getInputStream();
OutputStream os = new FileOutputStream(new File("D:\\M\\" + request.getHeader("Content-Location").toString()));
int x;
while ((x = is.read()) != -1) {
os.write(x);
os.flush();
}
os.close();
Nothing fancy, just plain old write as you read, byte by byte.
The problem is that the picture is shown as jpeg (as to be expected), but you can not open it (I have tried multiple viewers and got the same result):
name_of_pic.jpg Decode error! Not a JPEG file: Starts with 0xbd 0xef
Then I said okay lets try another way or output stream for writing the picture. All of the following code got me the same result.
//alternative way1
DataInputStream dis = new DataInputStream(is);
DataOutputStream dos = new DataOutputStream(new FileOutputStream(new File("D:\\M\\" + request.getHeader("Content-Location").toString())));
while(dis.available()>0){
int b = dis.read();//also tried with readByte, readUnsignedByte.. got 0kb file
dos.write(b);
dos.flush();
}
dos.close();
//alternative way2
IOUtils.copy(is, os);
//alternative way3
int len = 0;
byte[] buffer = new byte[8 * 1024];
while ((len = is.read(buffer, 0, buffer.length)) > 0) {
for (int i = 0; i < buffer.length; i++) {
System.out.print(buffer[i]);
}
System.out.println();
os.write(buffer, 0, len);
}
os.flush();
os.close();
So I looked at the requestBody in the debugger and compared it to what I have in the picture. There is a difference in the values that are stored in the requestBody and the values stored in the picture (after I write it on the filesystem).
This picture shows the few first values in the requestBody: http://prntscr.com/7cuiw5
And this is how the picture looks like in hex value (using irfanview hex editor):
http://prntscr.com/7culcn
Clearly there is a difference to what I get to what I write down.
The question is where does it go wrong? Is it a problem with the output stream that reads int? Or maybe its the conversion from hex to int/byte?
Anyway I am really stuck with this one. Any help at all would be really appreciated. I am sorry that I cant post the pictures directly (not so much reputation).
When you will open the image in notepad,you'll see some extra code at the top and the bottom.
-----------------------------119202331112770
Content-Disposition: form-data; name="file"; filename="..gif"
Content-Type: image/gif
This code has to be removed if you wanna see your images.
these codes are present in the body of post method.

how to decompress http response?

Can any one of you solve this problem !
Problem Description:
i have received content-encoding: gzip header from http web-server.
now i want to decode the content but when i use GZIP classes from jdk 1.6.12, it gives null.
does it means that contents are not in gzip format ? or are there some another classes for decompress http response content?
Sample Code:
System.out.println("Reading InputStream");
InputStream in = httpuc.getInputStream();// httpuc is an object of httpurlconnection<br>
System.out.println("Before reading GZIP inputstream");
System.out.println(in);
GZIPInputStream gin = new GZIPInputStream(in));
System.out.println("After reading GZIP inputstream");
Output:
Reading InputStream
Before reading GZIP inputstream
sun.net.www.protocol.http.HttpURLConnection$HttpInputStream#8acf6e
null
I have found one error in code, but don't able to understand it properly. what does it indicates.
Error ! java.io.EOFException
Thanks
I think you should have a look at HTTPClient, which will handle a lot of the HTTP issues for you. In particular, it allows access to the response body, which may be gzipped, and then you simply feed that through a GZIPInputStream
e.g.
Header hce = postMethod.getResponseHeader("Content-Encoding");
InputStream in = null;
if(null != hce)
{
if(hce.getValue().equals(GZIP)) {
in = new GZIPInputStream(postMethod.getResponseBodyAsStream());
}
// etc...
I second Brian's suggestion. Whenever u need to deal with getting/posting stuff via HTTP don't bother with low-level access use the Apache HTTP client.
InputStream is = con.getInputStream();
InputStream bodyStream = new GZIPInputStream(is);
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int length;
while ((length = bodyStream.read(buffer)) > 0) {
outStream.write(buffer, 0, length);
}
String body = new String(outStream.toByteArray(), "UTF-8");

Categories

Resources