Problem with basic access authentication in file downloader - java

I'm having problems with downloading binary file (zip file) in my app from te internet. I have to use basic access authentication to authorize acces to file, but server response is always HTTP/1.0 400 Bad request.
String authentication = this._login+":"+this._pass;
String encoding = Base64.encodeToString(authentication.getBytes(), 0);
String fileName = "data.zip";
URL url = new URL("http://10.0.2.2/androidapp/data.zip");
HttpURLConnection ucon = (HttpURLConnection) url.openConnection();
ucon.setRequestMethod("GET");
ucon.setDoOutput(true);
ucon.setRequestProperty ("Authorization", "Basic " + encoding);
ucon.connect();
/*
* Define InputStreams to read from the URLConnection.
*/
InputStream is = ucon.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
/*
* Read bytes to the Buffer until there is nothing more to read(-1).
*/
ByteArrayBuffer bab = new ByteArrayBuffer(50);
int current = 0;
while ((current = bis.read()) != -1) {
bab.append((byte) current);
}
bis.close();
/* Convert the Bytes read to a String. */
FileOutputStream fos = this._context.openFileOutput(fileName, this._context.MODE_WORLD_READABLE);
fos.write(bab.toByteArray());
fos.close();
Could it be caused by whitespaces in password?

I might be a bit late but I just came across a similar problem.
The problem lies in the following line:
String encoding = Base64.encodeToString(authentication.getBytes(), 0);
If you change that line to look like this it should work:
String encoding = Base64.encodeToString(authentication.getBytes(), Base64.NO_WRAP);
By default the Android Base64 util adds a newline character to the end of the encoded string. This invalidates the HTTP headers and causes the "Bad request".
The Base64.NO_WRAP flag tells the util to create the encoded string without the newline character thus keeping the HTTP headers intact.

Related

What is wrong with my HttpURLConnection request?

I am trying to call a REST API with a PUT Request but I am receiving a 400 Error Code (Bad Request). Can someone spot what I may be doing wrong?
I have successfully called this API with a REST Client, here are the headers and body used:
https://imgur.com/dZVyawn
https://imgur.com/lMtn2JB
String credentials = Base64.getEncoder().encodeToString(("wcadmin:wcadmin").getBytes());
URL url = new URL(getURL());
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("PUT");
connection.setDoOutput(true);
connection.setDoInput(true);
//Set Headers
String fileUrl = "c:\\0000000050.xml";
File fileToUpload = new File(fileUrl);
long length = fileToUpload.length();
String FORM_DATA_BOUNDARY = "------FormBoundary" + System.currentTimeMillis();
connection.setRequestProperty("csrf_nonce", getNonceValue());
connection.setRequestProperty("Accept", "application/xml");
connection.setRequestProperty("Authorization", "Basic " + credentials);
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + FORM_DATA_BOUNDARY);
connection.setRequestProperty("Content-Length", Long.toString(length));
//Setup Request Body Writer
OutputStream requestBodyOutputStream = connection.getOutputStream();
BufferedWriter requestBodyWriter = new BufferedWriter(new OutputStreamWriter(requestBodyOutputStream));
//Write Body
requestBodyWriter.write("\r\n\r\n");
requestBodyWriter.write(FORM_DATA_BOUNDARY);
requestBodyWriter.write("\r\n");
requestBodyWriter.write("Content-Disposition: form-data; name=\"file\"; filename=\"" + fileUrl + "\"");
requestBodyWriter.write("\r\n");
requestBodyWriter.write("Content-Type: text/xml");
requestBodyWriter.write("\r\n\r\n");
requestBodyWriter.flush();
FileInputStream uploadFileStream = new FileInputStream(fileToUpload);
int bytesRead;
byte[] dataBuffer = new byte[1024];
while ((bytesRead = uploadFileStream.read(dataBuffer)) != -1) {
requestBodyOutputStream.write(dataBuffer, 0, bytesRead);
}
requestBodyOutputStream.flush();
requestBodyWriter.write("\r\n");
requestBodyWriter.write(FORM_DATA_BOUNDARY);
requestBodyWriter.flush();
//Close the streams
requestBodyOutputStream.close();
requestBodyWriter.close();
uploadFileStream.close();
//Read Response
String inputLine;
StringBuffer content = new StringBuffer();
InputStream inputStream = connection.getInputStream();
if (inputStream != null) {
BufferedReader responseReader = new BufferedReader(new InputStreamReader(inputStream));
if (responseReader != null) {
while ((inputLine = responseReader.readLine()) != null) {
content.append(inputLine);
}
responseReader.close();
}
}
connection.disconnect();
Error 400 Bad Request response received
First and most important: you cannot write to both an OutputStream, and a OutputStreamWriter which wraps that same OutputStream. They will conflict with each other.
Do not use OutputStreamWriter at all; instead, convert text to bytes yourself:
OutputStream requestBodyOutputStream = connection.getOutputStream();
requestBodyOutputStream.write("\r\n\r\n".getBytes(StandardCharsets.UTF_8));
requestBodyOutputStream.write(FORM_DATA_BOUNDARY.getBytes(StandardCharsets.UTF_8));
// etc.
Second, you are converting between bytes and strings using the system’s default charset, which means exactly what gets written depends on the system where the code is running. Don’t call String.getBytes without specifying an explicit Charset. Usually getBytes(StandardCharsets.UTF_8) is what you want.
Similarly, you need to pass a Charset to your InputStreamReader creation (although this isn’t the cause of your problem, since you aren’t getting a valid response at the moment). Don’t assume a charset; use the charset MIME type parameter from the response’s Content-Type header. If you’re using a version of Java older than 11, you can parse the Content-Type value with the javax.activation.MimeType class, but be aware that the javax.activation package has been removed from Java SE as of Java 11. For Java 11 and later, Java Activation can be downloaded as a stand-alone library. Another option is to use the JavaMail library, specifically its ContentType class, for parsing.
Third, the Content-Length header inside the body part (between the boundaries) should use the file’s length as a Content-Length. The Content-Length of the entire request body must be the length of everything you’ve written: the boundaries, the body part headers, and the file content.
The good news is, I think (though I’m not positive) that URLConnection will set the request’s overall Content-Length automatically, based on the bytes you write, so you probably don’t need to compute the length yourself; you can simply refrain from setting "Content-Length" at all.
When you do pass a correct request, you will find that you are dropping the newlines in the response. If the response is supposed to be human-readable text, those newlines are likely to matter. If you’re using Java 10 or later, you can use Reader.transferTo with a StringWriter:
StringWriter responseBody = new StringWriter();
responseReader.transferTo(responseBody);
String content = responseBody.toString();
If you’re using a version of Java older than 10:
new BufferedReader cannot return null, so checking for null is pointless. In Java, the new operator always, no matter what, returns a new object (unless an exception is thrown, in which case new doesn’t return at all).
You should use StringBuilder, not StringBuffer. They are identical except that StringBuffer is an older class that provides thread safety for every method, creating unnecessary overhead for nearly all use cases.
You are copying your file into the request without any buffering, which is going to be slow and inefficient. Consider using Files.copy(fileToUpload.toPath(), requestBodyOutputStream) instead.

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.

Encoding ignored while reading InputStream

I'm having some encoding problems in a Java application that makes HTTP requests to an IIS server.
Iterating over the headers of the URLConnection object I can see the following (relevant) headers:
Transfer-Encoding: [chunked]
Content-Encoding: [utf-8]
Content-Type: [text/html; charset=utf-8]
The URLConnection.getContentEncoding() method returns utf-8 as the document encoding.
This is how my HTTP request, and stream read is being made:
OutputStreamWriter sw = null;
BufferedReader br = null;
char[] buffer = null;
URL url;
url = new URL(this.URL);
URLConnection connection = url.openConnection();
connection.setDoOutput(true);
sw = new OutputStreamWriter(connection.getOutputStream());
sw.write(postData);
sw.flush();
br = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF8"));
StringBuilder totalResponse = new StringBuilder();
String line;
while((line = br.readLine()) != null) {
totalResponse.append(line);
}
buffer = totalResponse.toString().toCharArray();
if (sw != null)
sw.close();
if (br != null)
br.close();
return buffer;
However the following string sent by the server "ÃÃÃção" is received by the client as "�����o".
What am I doing wrong ?
Based on your comments, you are trying to receive a FIX message from an IIS server and FIX uses ASCII. There are only a small subset of tags which support other encoding and they have to be treated in a special manner (non-ASCII tags in the standard FIX spec are 349,351,353,355,357,359,361,363,365). If such tags are present, you will get a tag 347 with a value specifying the encoding (for example UTF-8) and then each tag, will be preceded by a tag giving you the length of the coming encoded value (for tag 349, you will always get 348 first with an integer value)
In your case, it looks like the server is sending a custom tag 10411 (the 10xxx range) in some other encoding. By convention, the preceding tag 10410 should give you the length of the value in 10411, but it contains "0000" instead, which may have some other meaning.
Note that although FIX message are very readable, they should still be treated as binary data. Tags and values are mostly ASCII characters, but the delimiter (SOH) is 0x01 and as mentioned above, certain tags may be encoded with another encoding. The IIS service should really return the data as application/octet-stream so it can be received properly. Attempting to return it as text/html is asking for trouble :).
If the server really sends a Content-Encoding of "UTF-8" then it is very confused. See http://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7231.html#header.content-encoding
For good order a couple of corrections.
URLConnection connection = url.openConnection();
connection.setDoOutput(true);
connection.connect();
try (Writer sw = new OutputStreamWriter(connection.getOutputStream(),
StandardCharsets.UTF_8)) {
sw.write(postData);
sw.flush();
try (BufferedReader br = new BufferedReader(
new InputStreamReader(connection.getInputStream(),
StandardCharsets.UTF_8))) {
StringBuilder totalResponse = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
totalResponse.append(line).append("\r\n");
}
return totalResponse.toString().toCharArray();
} // Close br.
} // Close sw.
Maybe:
postData = ... + "Accept-Charset: utf-8\r\n" + ...;
Receiving the totalResponse.toString() you should have all read correctly.
But then when displaying again, the String/char is again converted to bytes, and there the encoding fails. For instance System.out.println will not do as probably the Windows encoding is used.
You can test the String by dumping its bytes:
String s = totalResponse.toString();
Logger.getLogger(getClass().getName()).log(Level.INFORMATION, "{0}",
Arrays.toString(s.getBytes(StandardCharsets.UTF_8)));
In some rare cases the font will not contain the special characters.
Can you try by putting the stream as part of request attribute and then printing it out on client side. a request attribute will be received as is withou any encoding issues

Uploading an UTF-8 text file in Blackberry

I am trying to upload an UTF-8 text file to a server in Blackberry. The upload works great but when I check the file in the server it's an ASCII file and what I need is an UTF-8 file.
This is the code that I use when I create the file:
FileConnection fc = (FileConnection)Connector.open(fileName);
if (!fc.exists()){
fc.create();
}
long byteOffset = fc.usedSize();
OutputStream outStream = fc.openOutputStream(byteOffset);
outStream.write(line.getBytes("UTF-8"));
outStream.close();
fc.close();
To send the file I use this:
public void run (){
httpConnection = null;
_connectionURL = null;
String lineEnd = "\r\n";
String twoHyphens = "--";
String boundary = "*****";
int rc = -1;
OutputStream os = null;
try {
_connectionURL = Constants.UPLOAD_URL + getConnectionString();
httpConnection = (HttpConnection)Connector.open(_connectionURL);
byte [] postDataBytes = getData();
httpConnection.setRequestMethod("POST");
httpConnection.setRequestProperty("Connection", "Keep-Alive");
httpConnection.setRequestProperty("User-Agent", "BlackBerry");
httpConnection.setRequestProperty("Content-Type", "multipart/form-data;boundary=*****");
httpConnection.setRequestProperty(HttpProtocolConstants.HEADER_CONTENT_LANGUAGE, "en-US");
httpConnection.setRequestProperty(HttpProtocolConstants.HEADER_CACHE_CONTROL,"no-cache, no-store, no-transform");
os = httpConnection.openOutputStream();
os.write((twoHyphens + boundary + lineEnd).getBytes());
os.write(("Content-Disposition: form-data; name=\"uploadedfile\";filename=\"" + fileName +"\"" + lineEnd).getBytes());
os.write(lineEnd.getBytes());
os.write(postDataBytes);
os.write(lineEnd.getBytes());
os.write((twoHyphens + boundary + twoHyphens + lineEnd).getBytes());
os.flush();
// Response
rc = httpConnection.getResponseCode();
InputStream in = httpConnection.openInputStream();
int ch;
StringBuffer stringBuffer = new StringBuffer();
while( ( ch = in.read() ) != -1 ){
stringBuffer.append( (char)ch );
}
String responseString = stringBuffer.toString();
...
}catch (IOException ioe){
...
}
}
...
private byte[] getData() throws IOException {
int _c;
StringBuffer _stringBuffer = new StringBuffer("UTF-8");
FileConnection fileForUpload = (FileConnection) Connector.open(Constants.FOLDER_FILES+this.fileName, Connector.READ);
this.fileInputStream = fileForUpload.openDataInputStream();
this.postData = new URLEncodedPostData("UTF-8", false);
while( (_c = this.fileInputStream.read()) != -1){
_stringBuffer.append((char)_c);
}
postData.setData(_stringBuffer);
byte [] _postData = postData.getBytes();
fileForUpload.close();
return _postData;
}
I guess there is something wrong in getData() method or in the httpConnection properties, but i don't know what is it.
Thanks for your help
In addition to Jon Skeet's answer.
To read byte array from file you can simply use net.rim.device.api.io.IOUtilities:
FileConnection fileForUpload =
(FileConnection) Connector.open(path, Connector.READ);
InputStream stream = fileForUpload.openInputStream();
byte[] data = IOUtilities.streamToBytes(stream);
Look at this code, which appears twice:
while( ( ch = in.read() ) != -1 ){
stringBuffer.append( (char)ch );
}
That's treating each byte as a separate character, effectively in ISO-8859-1.
If you really want to convert the content to text, you should be using an InputStreamReader with an encoding of UTF-8, then ideally reading blocks of characters (rather than one character at a time).
This isn't helping either:
byte [] _postData = postData.getBytes();
That will be using the platform default encoding to convert a string to bytes - that's almost never what you want.
Given that your getData method is trying to read a file as a byte array, you shouldn't be converting it to text at all, IMO. If you know the file length beforehand, you should just create a byte array of the right size and repeatedly call InputStream.read(byte[], int, int), noting the return value to see how far you've read. If you don't, you can repeatedly read into a smallish buffer, then write the data you've just read into a ByteArrayOutputStream which you can later get the byte array from.
Additionally, you don't appear to ever close any of your streams - which you should do in finally statements, so that the streams are closed even if an exception is thrown.

Read Status code

conn = (HttpURLConnection) connectURL.openConnection();
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.connect();
int code = conn.getResponseCode();
I have successfully established a connection. I am trying to pass the information over the internet.When the url is opened via browser I am getting response as
{"status":"0","responseCode":"1001","response":"Wrong Settings."}
For correct status is returned as 1.
Is there any method where I can get the status only.I have been trying the following methods but every time I am getting code (below is code snippet) as -1 irrespect of status code when I am verifying manually via browser
This is a JSON text. You will need to use a JSON library.
int code = conn.getResponseCode();
this method returns http status code, for http status codes see
http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
while the response code you want to retrieve is actually the response string returned by the server.
To read this use:
try {
InputStream in = new BufferedInputStream(conn.getInputStream());
readStream(in);//method to read characters from stream.
finally {
urlConnection.disconnect();
}
}
You can add below code for get Response string from your connection.
OutputStream connectionOutput = null;
connectionOutput=connection.getOutputStream();
connectionOutput.write(requestJson.toString().getBytes());
connectionOutput.flush();
connectionOutput.close();
inputStream = new BufferedInputStream(connection.getInputStream());
ByteArrayOutputStream dataCache = new ByteArrayOutputStream();
// Fully read data
byte[] buff = new byte[1024];
int len;
while ((len = inputStream.read(buff)) >= 0) {
dataCache.write(buff, 0, len);
}
// Close streams
dataCache.close();
Now get Response string of json like below.
String jsonString = new String(dataCache.toByteArray()).trim();
JSONObject mJsonobject=new JSONObject(jsonString);
You can now parse your key from this mJsonobject Object.

Categories