I have a java code to call a REST API which returns a JWT token as a response. I send a GET call to the API and it will return a JWT token as a response. The token is being returned fine. However, I've noticed somehow the token is being trimmed.
I tried everything online and nothing seems to be working for me. Below is my code :
try {
URL url = new URL(proxyService.getProperty("proxy.url") + "/" + sessionToken);
log.logText("Connection URL: " + url, logLevel);
String readLine = null;
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/json");
int responseCode = conn.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
InputStream in = ((URLConnection)conn).getInputStream();
int length = 0;
StringBuffer response = new StringBuffer();
byte[] data1 = new byte[1024];
while (-1 != (length = in.read(data1))) {
response.append(new String(data1, 0, length));
}
log.logText("JSON String Result: " + response.toString(), logLevel);
}
conn.disconnect();
} catch(MalformedURLException e) {
e.printStackTrace();
} catch(IOException e) {
e.printStackTrace();
}
oauthToken = oauthToken.replaceAll("^\"|\"$", "");
log.logText("OAuth2 Token: " + oauthToken, logLevel);
return oauthToken;
Regards,
Learnmore
As #markspace mentioned, please specify the data type for oauthToken (I believe it is of type String). Print the total String and then the length before replaceALL and after replaceALL. compare whats replace adds to the total length if yes then there is no issue of string getting trimmed.
You are not assigning response value to anything. I assume you should be assigning it to oauthToken variable.
Also please close the InputStream instance in finally clause, otherwise you will cause resource leakage.
I think you have to close InputStream first, to flush internal buffer.
public static String getOauthToken() throws IOException {
URL url = new URL(proxyService.getProperty("proxy.url") + "/" + sessionToken);
log.logText("Connection URL: " + url, logLevel);
String oauthToken = readInputString(url);
oauthToken = oauthToken.replaceAll("^\"|\"$", "");
log.logText("OAuth2 Token: " + oauthToken, logLevel);
return oauthToken;
}
private static String readInputString(URL url) throws IOException {
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/json");
if (conn.getResponseCode() != HttpURLConnection.HTTP_OK)
throw new RuntimeException("Not expected response code");
try (InputStream in = conn.getInputStream()) {
StringBuffer buf = new StringBuffer();
byte[] b = new byte[1024];
while (true) {
int readBytes = in.read(b);
if (readBytes == -1)
break;
buf.append(new String(b, 0, readBytes));
}
log.logText("JSON String Result: " + buf, logLevel);
return buf.toString();
}
}
It looks like the actual application that I'm calling from is cutting off the response value. I shortened the length of the JWT token and it's not cutting it off. The application must have a limit for a maximum number of characters allowed in a string could be for performance reasons.
Related
I am trying to uploading chunks of 256 KB in Google Drive using REST API v3. I can successfully get the upload ID but when I use this upload ID to upload a chunk, I get a 400 Bad Request instead of 308. I am posting the code below. The method getUploadID() initiates a resumable upload session and the method putFileWithUploadID() should upload a chunk of the file but there seems to be a problem in it. I have written the code according to the official guide.
String mUploadID;
private String getUploadID(Uri fileUri, String token) {
String upload_id = "";
java.io.File fileContent = new java.io.File(fileUri.getPath());
String fileName = fileContent.getName();
String mimeType = "audio/mpeg";
try {
String url = "https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable";
URL obj = new URL(url);
HttpsURLConnection con = (HttpsURLConnection) obj.openConnection();
con.setRequestMethod("POST");
con.setDoInput(true);
con.setDoOutput(true);
con.setRequestProperty("Authorization", "Bearer " + token);
con.setRequestProperty("X-Upload-Content-Type", mimeType);
con.setRequestProperty("X-Upload-Content-Length", String.format(Locale.ENGLISH, "%d", fileContent.length()));
con.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
String body = "{\"name\": \"" + fileName + "\", \"parents\": [\"" + "0B7ypsm4HGZhCS3FXcldPZnFPNkE" + "\"]}";
con.setRequestProperty("Content-Length", String.format(Locale.ENGLISH, "%d", body.getBytes().length));
OutputStream outputStream = con.getOutputStream();
outputStream.write(body.getBytes());
outputStream.close();
con.connect();
String location = con.getHeaderField("Location");
if (location.contains("upload_id")) {
String[] uploadParameters = location.split("upload_id");
upload_id = uploadParameters[1].replace("=", "");
}
} catch (Exception e) {
e.printStackTrace();
}
return upload_id;
}
private void putFileWithUploadID(Uri fileUri, String token, long range) {
java.io.File fileContent = new java.io.File(fileUri.getPath());
String fileName = fileContent.getName();
String contentLength = String.valueOf(fileContent.length());
String mimeType = "audio/mpeg";
long totalBytesFromDataInputStream = 0;
long uploadedBytes = 0;
long chunkStart = 0;
long chunkSize = 262144;
do {
try {
String url = "https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable&upload_id=" + mUploadID;
URL obj = new URL(url);
HttpsURLConnection con = (HttpsURLConnection) obj.openConnection();
con.setRequestMethod("PUT");
con.setDoOutput(true);
con.setConnectTimeout(10000);
con.setRequestProperty("Content-Type", mimeType);
uploadedBytes = chunkSize;
if (chunkStart + uploadedBytes > fileContent.length()) {
uploadedBytes = (int) fileContent.length() - chunkStart;
}
con.setRequestProperty("Content-Length", String.format(Locale.ENGLISH, "%d", uploadedBytes));
con.setRequestProperty("Content-Range", "bytes " + chunkStart + "-" + (chunkStart + uploadedBytes - 1) + "/" + fileContent.length());
byte[] buffer = new byte[(int) uploadedBytes];
FileInputStream fileInputStream = new FileInputStream(fileContent);
fileInputStream.getChannel().position(chunkStart);
if (fileInputStream.read(buffer, 0, (int) uploadedBytes) == -1) {
break;
}
fileInputStream.close();
OutputStream outputStream = con.getOutputStream();
outputStream.write(buffer);
outputStream.close();
con.connect();
int responseCode = con.getResponseCode();
String rangeHeader = con.getHeaderField("Range");
if (rangeHeader!=null) {
chunkStart = Long.parseLong(rangeHeader.substring(rangeHeader.lastIndexOf("-") + 1, rangeHeader.length())) + 1;
}
} catch (Exception e) {
e.printStackTrace();
}
} while ((chunkStart+chunkSize)<fileContent.length());
}
Basically, 400: Bad Request means that a required field or parameter has not been provided, the value supplied is invalid, or the combination of provided fields is invalid.
This error can be thrown when trying to add a duplicate parent to a Drive item. It can also be thrown when trying to add a parent that would create a cycle in the directory graph.
You may also check this related SO post which suggested to properly use the Android-specific API to do resumable upload. See creating files.
I am not an pro developing android. I wanted to download a JSON object from my server, but only code I could find was this:
private String downloadUrl(String myurl) throws IOException {
InputStream is = null;
// Only display the first 500 characters of the retrieved
// web page content.
int len = 500;
try {
URL url = new URL(myurl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000 /* milliseconds */);
conn.setConnectTimeout(15000 /* milliseconds */);
conn.setRequestMethod("GET");
conn.setDoInput(true);
// Starts the query
conn.connect();
int response = conn.getResponseCode();
Log.d("ServerConnection", "The response is: " + response);
is = conn.getInputStream();;
//is.
// Convert the InputStream into a string
String contentAsString = readIt(is, len);
return contentAsString;
// Makes sure that the InputStream is closed after the app is
// finished using it.
} catch (MalformedURLException e) {
//
return "error";
} catch (IOException e) {
//
return "error";
} finally {
if (is != null) {
is.close();
}
}
}
And it works fine, I cant understand. But it has a int len = 500, and my returned json is cropped to 500 chars. I tried changing to a great number, but it puts spaces at the end. How can I know the size in chars of the String contained by the InputSteam?
Thanks
You can check the Content-Length header value of your response:
Map<String, List<String>> headers = connection.getHeaderFields();
for (Entry<String, List<String>> header : headers.entrySet()) {
if(header.getKey().equals("Content-Legth")){
len=Integer.parseInt(header.getValue());
}
}
or you can your response in a buffered reader like this:
InputStream is = connection.getInputStream();
InputStreamReader reader = new InputStreamReader(is);
StringBuilder builder = new StringBuilder();
int c = 0;
while ((c = reader.read()) != -1) {
builder.append((char) c);
}
Yout can use Apache Commons IO IOUtils.toString to convert InputStream to String or use Gson to read object from input stream directly:
return gson.fromJson(new InputStreamReader(inputStream), YourType.class);
I'm trying to send png to server using http get request. I'm using code below to to so.
String encoding (on client):
byte[] bytes = Files.readAllBytes(Paths.get(chosenFile.getPath()));
String image = new String(bytes, "ISO-8859-1");
Then I send http get request to server with String image.
Server receive it but I get image that is not the same as one I sent (I can't open one I received). I'm using URLEncoder.encode(image, "ISO-8859-1") to encode url for http get request. When I use URLEncoder.encode(image, "UTF-8"), the same happens.
Why this doesn't work?
Is there any better way of doing this kind of stuff?
UPD #0
Code for sending an image:
private void jMenuItem5ActionPerformed(java.awt.event.ActionEvent evt) {
JFileChooser chooser= new JFileChooser();
int choice = chooser.showOpenDialog(this);
if (choice != JFileChooser.APPROVE_OPTION) return;
File chosenFile = chooser.getSelectedFile();
try {
byte[] bytes = Files.readAllBytes(Paths.get(chosenFile.getPath()));
String image = new String(bytes, "ISO-8859-1");
if(image != null){
boolean allsent = false;
long k = 0;
String query = "0";
while(!allsent){
String s = image;
String send = "";
long q;
if(k+400>image.length()){
q=image.length();
allsent=true;
}
else q = k+400;
for(long i=k;i<q;i++)
send+=s.charAt((int) i);
System.out.println(send);
String response = new HTTP().GET(Constants.ADDRESS_ADDIMAGE
+ "?" + Constants.USERNAME + "=" + URLEncoder.encode(user, "UTF-8")
+ "&" + Constants.IMAGE + "=" + URLEncoder.encode(send, "ISO-8859-1")
+ "&" + Constants.QUERY + "=" + URLEncoder.encode(query, "UTF-8"));
k+=400;
query="1";
}
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
Note:
HTTP().GET() invokes standard http get.
UPD #1
Server code
#GET
#Path("/addimage")
#Produces(MediaType.APPLICATION_JSON)
public String addImage(#QueryParam("username") String uname, #QueryParam("image") String image, #QueryParam("query") String query) {
if(query.equals("0")){
String s = image;
JDBC.addImage("ABase", "MarketLogin", "image", uname, s);
}
else{
String s = JDBC.selectDB("ABase", "MarketLogin", "image", uname, "username") + image;
JDBC.addImage("ABase", "MarketLogin", "image", uname, s);
}
return "1";
}
Note:
JDBC is class for updating mysql DB. Server is expecting String encoded by ISO-8859-1.
How about using a HttpURLConnection and sending bytes instead of strings.
HttpURLConnection connection;
ByteArrayOutputStream baos;
try {
URL url = new URL("http://www.somewebsite.com");
connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "image/jpeg");
connection.setRequestMethod("POST");
baos = new ByteArrayOutputStream();
baos.write(bytes); // your bytes here
baos.writeTo(connection.getOutputStream());
}
finally {
if(baos != null)
baos.close();
if(osw != null)
osw.close();
if(connection != null)
connection.disconnect();
}
I've been hacking at this one for a while, but I can't find a good reason for the following behavior:
I have an Android app from which I send a multipart/form-data http post. The request has the following form:
private final String delimiter = "--";
private final String boundary = "SwA"
+ Long.toString(System.currentTimeMillis()) + "SwA";
private final String charset = "UTF-8";
private final String lineSpace = "\r\n";
private final String domain = (domain);
private HttpURLConnection configureConnectionForMultipart(String url)
throws MalformedURLException, IOException {
HttpURLConnection con = (HttpURLConnection) (new URL(url))
.openConnection();
con.setRequestMethod("POST");
con.setDoInput(true);
con.setDoOutput(true);
con.setRequestProperty("Connection", "Keep-Alive");
con.setRequestProperty("Content-Type", "multipart/form-data;boundary="
+ boundary);
return con;
}
private void addFormPart(String paramName, String value, DataOutputStream os)
throws IOException {
os.writeBytes(lineSpace + delimiter + boundary + lineSpace);
os.writeBytes("Content-Disposition: form-data; name=\"" + paramName
+ "\"" + lineSpace);
os.writeBytes("Content-Type: text/plain; charset=" + charset + lineSpace);
os.writeBytes(lineSpace + value + lineSpace);
os.flush();
}
private void addFilePart(String paramName, File data, DataOutputStream os)
throws IOException {
os.writeBytes(lineSpace + delimiter + boundary + lineSpace);
os.writeBytes("Content-Disposition: form-data; name=\"" + paramName
+ "\"" + lineSpace);
os.writeBytes("Content-Type: application/octet-stream\r\n");
os.writeBytes("Content-Transfer-Encoding: binary" + lineSpace);
os.writeBytes(lineSpace);
os.flush();
FileInputStream fis = new FileInputStream(data);
byte[] buffer = new byte[4096];
int bytesRead = -1;
while ((bytesRead = fis.read(buffer)) != -1) {
os.write(buffer, 0, bytesRead);
}
os.writeBytes(lineSpace);
os.flush();
fis.close();
}
private void finishMultipart(DataOutputStream os) throws IOException {
os.writeBytes(lineSpace);
os.flush();
os.writeBytes(delimiter + boundary + delimiter + lineSpace);
os.close();
}
private String getResponse(HttpURLConnection con) throws IOException {
String response = "";
int status = con.getResponseCode();
if (status == HttpURLConnection.HTTP_OK) {
BufferedReader reader = new BufferedReader(new InputStreamReader(
con.getInputStream()));
String line = "";
while ((line = reader.readLine()) != null) {
response += line;
}
reader.close();
} else {
BufferedReader reader = new BufferedReader(new InputStreamReader(con.getErrorStream()));
String line = "";
while ((line = reader.readLine()) != null) {
response += line;
}
reader.close();
throw new IOException("Server returned non-OK status: " + status+", "+response);
}
return response;
}
public SearchQueryRunnable initSearchQueryRunnable(String query) {
return new SearchQueryRunnable(query);
}
private class SearchQueryRunnable implements Runnable {
private final String _query;
private final String _url = domain + "search_query.php";
public SearchQueryRunnable(String query) {
_query = query;
}
#Override
public void run() {
try {
HttpURLConnection con = configureConnectionForMultipart(_url);
DataOutputStream os = new DataOutputStream(
con.getOutputStream());
addFormPart("tag", _query, os);
finishMultipart(os);
String result = getResponse(con);
Log.i("SearchQuery", result);
con.disconnect();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
In search_query.php, I have the following:
include 'hashtags_table_api.php';
$tag = $_POST["tag"];
$res = queryHashTagsTable($tag);
In hashtags_table_api.php, there is:
include 'connect.php';
function queryHashTagsTable($hashtag) {
global $pdo;
$sql = "SELECT * FROM `tbl_hashtags` WHERE hashtag = :hashtag";
$stmt = $pdo->prepare ( $sql );
echo $hashtag;
$stmt->bindValue(':hashtag', $hashtag);
if ($stmt->execute()) {
$result = $stmt->fetchAll();
echo count($result);
}
}
connect.php is (omitted important variables):
try {
$pdo = new PDO ( "mysql:host=$host;dbname=$dbname;charset=utf8", $username, $password );
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo 'Connected to database';
} catch(PDOException $e) {
echo $e->getMessage();
}
When I run this code and pass the value "hash" to initSearchQueryRunnable, I get a result of 0, even though I have a row with the value "hash" in the column hashtag. What's weird is that when I hardcode the following in search_query.php:
include 'hashtags_table_api.php';
$tag = 'hash';
$res = queryHashTagsTable($tag);
I get the desired result of 1 from my query. I double checked and the $_POST["tag"] is passing the value 'hash' to my server, but for some reason my SQL query will not recognize this as being equal to the value in my DB, even though the exact same hardcoded value is recognized as being equal.
Any clue what else I need to do in order to have my dynamically-passed parameter recognized as an equal value to my MySQL data?
EDIT
After some testing, I realized that the $_POST["tag"] is coming through with quotes, and thus strlen[$tag] = 6. I think this might be the reason why the SQL isn't matching the query string up with what's in the db. Sure enough strlen['hash'] = 4, which the SQL successfully matches up with my query. How can I effectively remove the quotation marks from the value of of $tag, so that my query works? FYI, my server is running PHP 5.4.24, if that's relevant.
I solved my own problem here. It turns out that the text being sent through my http post had two extra invisible whitespaces that I could only detect by some tests using strlen and using a for statement to see where the spaces were being appended. My solution was to use the trim() function (http://php.net/manual/en/function.trim.php) and just simply add $tag = trim($tag) to search_query.php before running queryHashTagsTable($tag). I hope this helps someone else that doesn't realize their http post request is being sent with extra invisible characters and needs the exact string for an sql query.
I am new to Java. I wrote an applet with a gui that sends results (int w and int p) to a server, and I get the "411 Length Required" error. What am I doing wrong? How do you set a Content-Length?
This is the method that communicates with the server:
public void sendPoints1(int w, int p){
try {
String url = "http://somename.com:309/api/Results";
String charset = "UTF-8";
String query = String.format("?key=%s&value=%s",
URLEncoder.encode(String.valueOf(w), charset),
URLEncoder.encode(String.valueOf(p), charset));
String length = String.valueOf((url + query).getBytes("UTF-8").length);
HttpURLConnection connection = (HttpURLConnection) new URL(url + query).openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Length", length);
connection.connect();
System.out.println("Responce Code: " + connection.getResponseCode());
System.out.println("Responce Message: " + connection.getResponseMessage());
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
I'm not 100% sure why you're getting a 411 error code, but it probably has to do with the fact that you are not sending any content with your POST. The content-length header should be the length in bytes of the body of the request. You are setting it to the length of the url!
Either change the request to a GET or put the query into the body of the request instead of into the url itself. If you do the latter, set the content-length to the length of the body only.
public void sendPoints1(int w, int p){
try {
String url = "http://somename.com:309/api/Results";
String charset = "UTF-8";
String query = String.format("key=%s&value=%s",
URLEncoder.encode(String.valueOf(w), charset),
URLEncoder.encode(String.valueOf(p), charset));
byte[] queryBytes = query.getBytes("UTF-8");
String length = String.valueOf((url + query).getBytes("UTF-8").length);
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Length", length);
OutputStream os = connection.getOutputStream();
os.write(queryBytes);
os.flush();
connection.connect();
System.out.println("Responce Code: " + connection.getResponseCode());
System.out.println("Responce Message: " + connection.getResponseMessage());
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
Request uri includes query , can use GET method.
connection.setRequestMethod("POST"); // modify to GET
connection.setRequestProperty("Content-Length", length); //remove the line
if use POST method, include 'content-length' heade, must send data.
for example:
public void sendPoints1(int w, int p){
try {
String url = "http://somename.com:309/api/Results";
//value type is int ,don't need URLEncoder.
byte[] data = ("key="+w+"&value="+p).getBytes("UTF-8");
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Length", data.length);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); //URLencode...
OuptputStream out = connection.getOutputStream();
out.write(data);
out.flush();
InputStream in = connnection.getInputStream();
//read .....
System.out.println("Responce Code: " + connection.getResponseCode());
System.out.println("Responce Message: " + connection.getResponseMessage());
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
Since all information is passed as query string which is a part of URL, you need not setRequestMethod as POST. But if you still want to set it to POST as part of your logic, then setRequestProperty("Content-Length", "0") as Http Server expect Length to be read when POST method is called. In your case nothing is written as POST information so better set it to ZERO, even thought default value is ZERO at times server may give response errorCode as 411, response Message: Required Length