Sending binary data with HttpURLConnection - java

i want to use google speech api, i've found this https://github.com/gillesdemey/google-speech-v2/ where everything is explained well, but and im trying to rewrite it into java.
File filetosend = new File(path);
byte[] bytearray = Files.readAllBytes(filetosend);
URL url = new URL("https://www.google.com/speech-api/v2/recognize?output="+outputtype+"&lang="+lang+"&key="+key);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//method
conn.setRequestMethod("POST");
//header
conn.setRequestProperty("Content-Type", "audio/x-flac; rate=44100");
now im lost... i guess i need to add the bytearray into the request. in the example its line
--data-binary #audio/good-morning-google.flac \
but httpurlconnection class has no method for attaching binary data.

But it has getOutputStream() to which you can write your data. You may also want to call setDoOutput(true).

The code below works for me. I just used commons-io to simplify, but you can replace that:
URL url = new URL("https://www.google.com/speech-api/v2/recognize?lang=en-US&output=json&key=" + key);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "audio/x-flac; rate=16000");
IOUtils.copy(new FileInputStream(flacAudioFile), conn.getOutputStream());
String res = IOUtils.toString(conn.getInputStream());

Use multipart/form-data encoding for mixed POST content (binary and character data)
//set connection property
connection.setRequestProperty("Content-Type","multipart/form-data; boundary=" + <random-value>);
PrintWriter writer = null;
OutputStream output = connection.getOutputStream();
writer = new PrintWriter(new OutputStreamWriter(output, charset), true);
// Send binary file.
writer.append("--" + boundary).append("\r\n");
writer.append("Content-Disposition: form-data; name=\"binaryFile\"; filename=\"" + binaryFile.getName() + "\"").append("\r\n");
writer.append("Content-Type: " + URLConnection.guessContentTypeFromName(binaryFile.getName()).append("\r\n");
writer.append("Content-Transfer-Encoding: binary").append("\r\n");
writer.append("\r\n").flush();

Related

"grant_type parameter is missing" in login Spotify API

I'm building a little application and i need to use the spoify API, when I try to login I have
400 ERROR:{"error":"unsupported_grant_type","error_description":"grant_type parameter is missing"}
when I make the POST request
String urlString = "https://accounts.spotify.com/api/token?";
URL website = new URL(urlString);
HttpURLConnection connection = (HttpURLConnection) website.openConnection();
connection.setRequestMethod("POST");
// Headers
String toEncode = Test.CLIENT_ID + ":" + Test.CLIEN_SECRET_ID;
String encodedString = Base64.getEncoder().encodeToString(toEncode.getBytes());
connection.setRequestProperty("Authorization", encodedString);//client id + secret
connection.setRequestProperty("Accept", "application/json");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setDoOutput(true);
// Add parameters to the body
String jsonInputString = "{" +
"grant_type: authorization_code,\n" +
"\"redirect_uri\": \"" + Test.REDIRECT_URI + "\",\n" +
"\"code\": \"" + code +
"\"\n}";
System.out.println("json input string " +jsonInputString);
byte[] input = jsonInputString.getBytes(StandardCharsets.UTF_8);
connection.setFixedLengthStreamingMode(input.length);
connection.connect();
try (OutputStream os = connection.getOutputStream()) {
os.write(input);
}
I read a lot about this error but I cannot find who to correct it, I also asked other people to look at my code and check if I did something wrong they don't find it either.
Please tell me you see what's wrong and how I can correct it
As far as I see you are trying to do the authorization with OAuth2.
I recommend, you to read https://datatracker.ietf.org/doc/html/rfc6749, which explains what you are doing.
Besides, if possible use some libraries, which are doing the OAuth2 flows for you.
Furthermore from what I see in your code, you should try to pass the values in your JSON as form parameters. See also https://stackoverflow.com/a/13486223/17832003
List<NameValuePair> formParams = new ArrayList<NameValuePair>();
formParams.add(new BasicNameValuePair("grant_type", "authorization_code"));
formParams.add(new BasicNameValuePair("redirect_uri", Test.REDIRECT_URI));
formParams.add(new BasicNameValuePair("code", code));
OutputStream os = conn.getOutputStream();
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(os, "UTF-8"));
writer.write(getQuery(params));
writer.flush();
writer.close();
os.close();
conn.connect();

[HttpURLConnection]How to send a post request with form-data

I am faced with a problem regarding to the HttpURLConnection. I want to send a POST request with 2 keys in the body (form-data).
URL obj = new URL(url);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("POST");
// add header
con.setRequestProperty("Content-Type", "multipart/form-data");
con.setRequestProperty("cookie", cookies);
con.setDoInput(true);
con.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(con.getOutputStream());
wr.writeBytes(urlParameters);
wr.flush();
wr.close();
How do I add the body (form-data)?
For example, I would to add 2 keys, name: "abc" and password: "abc": Form-Data Image
Use Content-Disposition: form-data; followed by form-data parameters.
String name = "abc";
String password = "abc";
String crlf = "\r\n";
wr.writeBytes("Content-Disposition: form-data; name=\"" + name + "\"; password=\"" + password + "\""+ crlf);

HttpURLConnection doing a get request even after setDoOutput(true), setRequestMethod("POST") setRequestProperty("Content

Here is the code:
String Surl = "http://mysite.com/somefile";
String charset = "UTF-8";
query = String.format("param1=%s&param2=%s",
URLEncoder.encode("param1", charset),
URLEncoder.encode("param2", charset));
HttpURLConnection urlConnection = (HttpURLConnection) new URL(Surl + "?" + query).openConnection();
urlConnection.setRequestMethod("POST");
urlConnection.setDoOutput(true);
urlConnection.setUseCaches(false);
urlConnection.setAllowUserInteraction(false);
urlConnection.setRequestProperty("Accept-Charset", charset);
urlConnection.setRequestProperty("User-Agent","<em>Android</em>");
urlConnection.setRequestProperty("Content-Type","application/x-www-form-urlencoded;charset=" + charset);
urlConnection.connect();
The above still does a GET request. I am using PHP on the server and am able to access the query's 'name=value' params through the $_GET variable and not the $_POST variable
Tested on 2.3.7(device).
What am I missing ?
When you send parameters in the url they are put in the GET variable. You should be posting the parameters in the POST body of the request to achieve what you are looking for. You should add the following just before the connect() call and remove the "?" + query from the url.
urlConnection.setRequestProperty("Content-Length", String.valueOf(query.getBytes().length));
urlConnection.setFixedLengthStreamingMode(query.getBytes().length);
OutputStream output = new BufferedOutputStream(urlConnection.getOutputStream());
output.write(query.getBytes());
output.flush();
output.close();

set methods aren't working for HttpsURLConnection

I'm trying to make a rest request in java. I tested the web service using RestClient in Firefox and it works great.
When i try to modify the HttpsUrlConnection instance in java the values aren't changing and i get a 500 response code.
Here's my code:
public String getAuthToken() throws IOException {
URL url =new URL("https://webserviceurl"); // webservice url is the url of the webservice
String data = URLEncoder.encode("username") + "=" + URLEncoder.encode("myusername","UTF-8");
data+= "&" + URLEncoder.encode("password") + "=" + URLEncoder.encode("pass","UTF-8");
HttpsURLConnection conn =(HttpsURLConnection) url.openConnection();
conn.setUseCaches(false);
conn.setHostnameVerifier(new AllowAllHostnameVerifier()); //this works HostName verifier changes
conn.setRequestMethod("POST"); // this doens't work. requestMethod is still set to GET
conn.setDoOutput(true); // this doesnt work. DoOutput still set on false
conn.setRequestProperty("Content-Type", "application/json"); // doens't work either
OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream(),"UTF-8");
wr.write(data);
wr.flush();
wr.close();
//conn has a 500 response code
if (conn.getResponseCode()==200)
{
InputStream is = conn.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader rd = new BufferedReader(isr);
String token = rd.readLine();
rd.close();
return token;
}
else
return null;
}
I'm stucked at this point and cannot find anything to make this work.
Thank you!
I actually think it's a bug with HttpsURLConnection. As i changed it to a HttpURLConnection object everything works just fine.

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