Android - obtain url redirect - android

I currently have a mediaplayer and am trying to get the redirect address from my source path. Since the media player does not support redirect handling, I am trying to get the redirected url path by creating a httpurlconnection etc. However, I'm not sure if I am doing it right. Any help would be appreciated. Thanks.
Code:
Log.d(TAG, "create url - test");
URL testUrl = new URL(path);
HttpURLConnection conn = (HttpURLConnection)testUrl.openConnection();
String test = conn.getURL().toString();
String test1 = conn.getHeaderField(2);
String test2 = conn.toString();
Log.d(TAG, "normal stuff test is: " + test);
Log.d(TAG, "header field test is: " + test1);
Log.d(TAG, "url to string is: " + test2);

The code below follows one hop of URL redirects. By using a HTTP HEAD request rather than GET it consumes radically less bandwith. It should be fairly straight forward to extend this method to handle multiple hops.
public URI followRedirects(URI original) throws ClientProtocolException, IOException, URISyntaxException
{
HttpHead headRequest = new HttpHead(original);
HttpResponse response = client.execute(headRequest);
final int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY ||
statusCode == HttpStatus.SC_MOVED_TEMPORARILY)
{
String location = response.getHeaders("Location")[0].toString();
String redirecturl = location.replace("Location: ", "");
return new URI(redirecturl);
}
return original;
}
It assumes you have already set up an HttpClient stored in the field client.
Also see this question.

Related

Android: HttpUrlConnection object returns error 301 after connection

I'm trying to connect to a web API using a URL. However, I get a 301 error from the server (Moved Permanently), although the provided URL works very well with no errors when I try it in my browser.
Here is the code that builds the URL:
public Loader<List<Earthquake>> onCreateLoader(int i, Bundle bundle) {
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
String minMagnitude = sharedPrefs.getString(
getString(R.string.settings_min_magnitude_key),
getString(R.string.settings_min_magnitude_default));
String orderBy = sharedPrefs.getString(
getString(R.string.settings_order_by_key),
getString(R.string.settings_order_by_default)
);
Uri baseUri = Uri.parse(USGS_REQUEST_URL);
Uri.Builder uriBuilder = baseUri.buildUpon();
uriBuilder.appendQueryParameter("format", "geojson");
uriBuilder.appendQueryParameter("limit", "10");
uriBuilder.appendQueryParameter("minmag", minMagnitude);
uriBuilder.appendQueryParameter("orderby", orderBy);
Log.i ("the uri is ", uriBuilder.toString());
return new EarthquakeLoader(this, uriBuilder.toString());
}
Here is the code that tries to connect to the resource represented by the URL:
private static String makeHttpRequest(URL url) throws IOException {
String jsonResponse = "";
// If the URL is null, then return early.
if (url == null) {
return jsonResponse;
}
Log.i("The received url is " , url +"");
HttpURLConnection urlConnection = null;
InputStream inputStream = null;
try {
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setReadTimeout(10000 /* milliseconds */);
urlConnection.setConnectTimeout(15000 /* milliseconds */);
urlConnection.setRequestMethod("GET");
urlConnection.connect();
// If the request was successful (response code 200),
// then read the input stream and parse the response.
if (urlConnection.getResponseCode() == 200) {
inputStream = urlConnection.getInputStream();
jsonResponse = readFromStream(inputStream);
} else {
Log.e(LOG_TAG, "Error response code: " + urlConnection.getResponseCode()); //this log returns 301
}
} catch (IOException e) {
Log.e(LOG_TAG, "Problem retrieving the earthquake JSON results.", e);
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if (inputStream != null) {
// Closing the input stream could throw an IOException, which is why
// the makeHttpRequest(URL url) method signature specifies than an IOException
// could be thrown.
inputStream.close();
}
}
return jsonResponse;
}
I could know that the connection returns status code of 301 from the log provided in the case when the status code is not 200. I have also logged the generated URL, I copied it from the logcat and tried it in my browser and it worked well. Here is the built URL: http://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&limit=10&minmag=6&orderby=magnitude
I checked this question: Android HttpURLConnection receives HTTP 301 response code but it wasn't clear to me what is the solution for the problem.
Can you please help me identify and solve the problem?
UPDATE: As greenapps indicated in his comment, the connection is done through https. That comment identified the problem and helped me fix the code.
In my code, the string I used to build the basic URL, had the protocol value as http not https, it was:
private static final String USGS_REQUEST_URL =
"http://earthquake.usgs.gov/fdsnws/event/1/query";
After reading greenapps comment, I just changed the protocol part in the string to https, so it became:
private static final String USGS_REQUEST_URL =
"https://earthquake.usgs.gov/fdsnws/event/1/query";
That solved the problem.
Thanks.
If you click your http link here you will see that the browser shows a https page. You better use that url directly as there is redirection now.
This is because the address http to https transferred.
To avoid this, you need to convert the request address to https.

HttpURLConnection in Android SDK 23 to ASP page, giving a cookie correctly to re-use session

I have an Android app that communicates with an internal web server here.
So far I have a login activity and another activity that helps do repetitive work.
I can login fine and I can store the Session ID cookie into a string. I've verified that the string is passed correctly through intent to the next activity. I have also verified that the cookie is received in the next activity.
However when I try to give this cookie to the web server via a setRequestProperty, the server doesn't seem to use it. When my app reads the requested URL, it just gets a login page, meaning it was redirected and the cookie didn't work. I receive zero errors.
I've talked to the website creator, and he says that he does no custom handling of HTTP headers, and that all of his scripts utilize session variables, and that ASP manages the session on its own. He wasn't aware that the web site was setting a session ID and value via cookies, and we then figured out that ASP was doing it automatically. This site has been functional via a web browser for years, I'm just trying to port a specific feature from it to an app.
I don't know what I'm doing wrong. Here is the chunk of code that reads the URL and sets the cookie and other HTTP header fields:
private class GetURLContent extends AsyncTask<URL, Integer, String> {
#Override
protected void onPostExecute(String result) {
setData(result);
}
protected String doInBackground(URL... url) {
String pageText = "";
String charset = "UTF-8";
String SessionCookie = "No SessionCookie passed.";
Bundle extras = getIntent().getExtras();
if (extras != null) {
SessionCookie = extras.getString("SessionCookie");
}
try {
URL ThisURL = new URL(url[0].toString());
HttpURLConnection ThisConnection = (HttpURLConnection) ThisURL.openConnection();
ThisConnection.setRequestMethod("GET");
ThisConnection.setRequestProperty("Host","technology.fergflor.k12.mo.us");
ThisConnection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36");
ThisConnection.setRequestProperty("Connection","keep-alive");
ThisConnection.setRequestProperty("Cookie",SessionCookie);
ThisConnection.connect();
// wrap the urlconnection in a bufferedreader
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(ThisConnection.getInputStream()));
String line;
//read from the urlconnection via the bufferedreader
while ((line = bufferedReader.readLine()) != null)
{
pageText = pageText + line + "\n";
}
bufferedReader.close();
pageText = SessionCookie + "\n" + pageText;
} catch (MalformedURLException e) {
pageText = "MalformedURLException Error Message=\"" + e.getMessage() + "\" " + pageText;
} catch (IOException e2) {
pageText = "IOException Error Message=\"" + e2.getMessage() + "\" " + pageText;
} catch (NullPointerException e3) {
pageText = "NullPointerException Error Message=\"" + e3.getMessage() + "\" " + pageText;
}
return pageText;
}
}
All of the set-request properties here are identical to the ones used in the previous activities login class. I am using HttpURLConnection in both activities.
The goal is to use this class to give a cookie to re-use the session established from the previous login activity, and to retrieve a web page. I'm not sure what's going wrong.
I had a very similar problem with code that worked fine with API < 23. With API 23 it was redirected to the login page. The solution was to add this code line:
ThisConnection.setInstanceFollowRedirects(false);

How to put image attachment to CouchDB in Android?

I am use HttpClient and mime to put the image file from Android client to CouchDB.
But there are some error message like this
D/FormReviewer(4733): {"error":"bad_request","reason":"invalid UTF-8 JSON: <<45,45,103,75,66,70,69,104,121,102,121,106,72,66,101,80,\n
here is my code
final String ProfileBasicID = UUID.randomUUID().toString();
Data.postImage(IconFile, "http://spark.iriscouch.com/driver/"+ProfileBasicID,new Callback<String>())
public static void postImage(File image,String url, Callback<String> success ) throws IOException {
HttpClient httpclient = new DefaultHttpClient();
HttpPut method = new HttpPut(url);
try {
MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
entity.addPart("type", new StringBody("photo"));
entity.addPart("form_file", new FileBody(image, "image/jpeg"));
method.setEntity(entity);
HttpResponse resp = httpclient.execute(method);
Log.d("httpPost", "Login form get: " + resp.getStatusLine());
StatusLine statusLine = resp.getStatusLine();
Log.d(tag, statusLine.toString());
if (entity != null) {
entity.consumeContent();
}
switch(resp.getStatusLine().getStatusCode()){
case HttpStatus.SC_CREATED:
success.call(EntityUtils.toString(resp.getEntity()));
break;
default:
throw new ClientProtocolException(statusLine.toString() +"\n"+ EntityUtils.toString(resp.getEntity()));
}
} catch (Exception ex) {
Log.d("FormReviewer", "Upload failed: " + ex.getMessage() +
" Stacktrace: " + ex.getStackTrace());
} finally {
// mDebugHandler.post(mFinishUpload);
httpclient.getConnectionManager().shutdown();
}
}
Please give me a hand,Thanks
RIGHT, forget what I posted here previously.
This is NOT as straightforward as we thought.
Some links I suggest you read:
CouchDB Document API
(Draft) Core API
Ok.
First decision is if you want "Standalone" or "inline attachments". Currently I don't know what the Pro's and Con's are, BUT based on your code, and what I did, we will go for "Standalone".
Firstly, you need the rev (revision) number of the document you want to attach your image to. As per the above link, do this by doing a Head request on that doc:
private String getParentRevision(String uuid, HttpClient httpClient) {
String rev = "";
try {
HttpHead head = new HttpHead("http://192.168.56.101/testforms/" + uuid + "/");
HttpResponse resp = httpClient.execute(head);
Header[] headers = resp.getAllHeaders();
getLog().debug("Dumping headers from head request");;
for (Header header : headers) {
getLog().debug(header.getName() + "=" + header.getValue());
if ("Etag".equals(header.getName())) {
StringBuilder arg = new StringBuilder(header.getValue());
if (arg.charAt(0) == '"') {
arg.delete(0, 1);
}
if (arg.charAt(arg.length()-1) == '"'){
arg.delete(arg.length()-1, arg.length());
}
rev = arg.toString();
break;
}
}
} catch (Exception ex) {
getLog().error("Failed to obtain DOC REV!", ex);
}
return rev;
}
I appologise for the hardcoding etc, I'm learning and experimenting here ;)
The "uuid" parameter is the UUID of the target document.
Note the removal of the wrapping '"' characters when we got the Etag (yes, the Etag header is the revision number).
THEN, when we got that, we can actually send the image:
String serveURL = "http://192.168.56.101/testforms/" + data.getString(PARENT_UUID) + "/" + imgUuid;
if (docRev != null && !docRev.trim().isEmpty()) {
//This is dumb...
serveURL += "?rev=" + docRev + "&_rev=" + docRev;
}
HttpPut post = new HttpPut(serveURL);
ByteArrayEntity entity = new ByteArrayEntity(imageData);
entity.setContentType(data.getString(MIME_TYPE));;
post.setEntity(entity);
HttpResponse formServResp = httpClient.execute(post);
With this, I was able to attache images to my docs ;)
As mentioned, please be aware that I'm also new to CouchDB, so there might be simpler ways to do this!
Something I just discovered now (but should have spotted earlier) is that there is the potential of a race condition here, if, for example, multiple clients are trying to attach images to the same document simultaneously. The reason is that the rev value changes with each change to the document.
In such a case, you will get a reply from the server like
{"error":"conflict","reason":"Document update conflict."}
Easiest solution is to just retry in such a case, until it works, or until a self imposed error limit is hit...
Cheers!

SEARCH GAL on the Exchange server

I need to get the Contacts of GAL from exchange server..
I have a method that searches the GAL on the Exchange server
for that there is
query string : The name to search the GAL for....
the code is given as follows....
public int searchGAL(
String query,
StringBuffer result) throws Exception
{
// Create the request
String uri = mUri + "Search";
String xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<Search xmlns=\"Search:\">\n" +
"\t<Store>\n"
+ "\t\t<Name>GAL</Name>\n"
+ "\t\t<Query>" + query + "</Query>\n"
+ "\t\t<Options>\n"
+ "\t\t\t<Range>0-99</Range>\n"
+ "\t\t</Options>\n"
+ "\t</Store>\n"
+ "</Search>";
// Send it to the server
HttpResponse response = sendPostRequest(createHttpPost(uri,xml,true));
// Check the response code to see if the result was 200
// Only then try to decode the content
int statusCode = response.getStatusLine().getStatusCode();
if(statusCode == 200)
{
// Decode the XML content
result.append(decodeContent(response.getEntity()));
}
// parse and return the results
return statusCode;
}
How to get the the all contacts in the server,.. how to query that ??
when i give space.. the query will search the names starting with space.. but i need to return all contacts when i pass space as query string.
http://msdn.microsoft.com/en-us/library/ff631384(v=exchg.80).aspx

HttpClient and MultipartEntity vs. Jersey Multipart and Android

I have a rest webservice that takes a POST metod with multipart message:
#Path("transferFile")
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(MediaType.APPLICATION_XML)
public String multipartTest(com.sun.jersey.multipart.MultiPart data) {
try {
// get first body part (index 0)
BodyPart bp = multiPart.getBodyParts().get(0);
etc..
Now I am trying to write a java client for that. I started with a simple jersey client:
view plaincopy to clipboardprint?
MultiPart multiPart = new MultiPart();
multiPart.bodyPart( new BodyPart(wavestream,MediaType.APPLICATION_OCTET_STREAM_TYPE));
Client c = Client.create();
WebResource r = c.resource("http://127.0.0.1:8080/webapp:);
response=r.path("transferFile").type(MediaType.MULTIPART_FORM_DATA).accept(MediaType.APPLICATION_XML).post(String.class, multiPart);
This works great - everything is ok. However I need this client working on Android and I have trouble with using jersey on that platform. So I used the normal way to send multipart message on android:
HttpClient client = new DefaultHttpClient();
client.getParams().setParameter("http.socket.timeout", new Integer(90000)); // 90 second
HttpPost httpPost = new HttpPost("http://127.0.0.1:8080/webapp/transferFile");
httpPost.setHeader("Content-Type", MediaType.MULTIPART_FORM_DATA );
//tried with and without base64
byte [] encodedWavestream = Base64.encodeBytesToBytes(wavestream);
InputStream ins = new ByteArrayInputStream(encodedWavestream);
InputStreamBody body = new InputStreamBody(ins, "test" );
int send = ins.available();
MultipartEntity requestContent = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE );
requestContent.addPart("stream", body);
httpPost.setEntity(requestContent);
HttpResponse Response = client.execute(httpPost);
An this gives an annoying response from the server :
HTTP Status 400 - Bad Request
The request sent by the client was syntactically incorrect (Bad Request).
I check the server log files but there is nothing there. So I don't know what's the origin of this error. I have wrote a simple html page with a post formula and 'multipart/form-data' content-type and it also works! An auto-generated request from soapUI also works! Why my client does not work? Can anybody help?
There is bug in Jersey. See Chunked encoding problem.
This problem appears only for few clients (iOS, Android).
If you set the Content-Type to application/octet-stream, then the Jersey MessageWriter for the application/octet-stream will set the Content-Length and
not send as chunked transport method.
There is solution for Jersey Client:
ClientConfig config = new DefaultClientConfig();
config.getProperties().put(ClientConfig.PROPERTY_CHUNKED_ENCODING_SIZE, 32 * 1024);
But it doesn't work for the iOS's or Android's client.
So I tested Apache File Upload. Threre was another bug: "Stream ended unexpectedly".
Only Oreilly upload can upload file correct for all clients.
This is my code:
public Object[] getParametersAndFiles(HttpServletRequest request) throws IOException {
log.debug("OreillyUpload");
Properties params = new Properties();
LinkedHashMap files = new LinkedHashMap();
File tempDirectory = new File(System.getProperty("java.io.tmpdir"));
MultipartParser mp = new MultipartParser(request, 1*1024*1024); // 10MB
Part part;
while ((part = mp.readNextPart()) != null) {
String name = part.getName();
if (part.isParam()) {
// it's a parameter part
ParamPart paramPart = (ParamPart) part;
String value = paramPart.getStringValue();
params.put(name, value);
log.debug("param; name=" + name + ", value=" + value);
}
else if (part.isFile()) {
// it's a file part
FilePart filePart = (FilePart) part;
String fileName = filePart.getFileName();
if (fileName != null) {
// the part actually contained a file
File file = new File(tempDirectory,fileName);
long size = filePart.writeTo(file);
files.put(name, file);
log.debug("file; name=" + name + "; filename=" + fileName +
", filePath=" + filePart.getFilePath() +
", content type=" + filePart.getContentType() +
", size=" + size);
}
else {
// the field did not contain a file
log.debug("file; name=" + name + "; EMPTY");
}
}
}
return new Object[] {params, files};
}
And this is Jersey Server code (warning all Jersey Upload anotations (like as "#FormDataParam") should be removed):
#POST
#Path("uploadMarkup")
#Produces(MediaType.APPLICATION_JSON)
// #Consumes(MediaType.MULTIPART_FORM_DATA)
//// public void uploadMarkup(
// public JSONWithPadding uploadMarkup(
// #FormDataParam("markupFile") InputStream markupFile,
// #FormDataParam("markupFile") FormDataContentDisposition details,
// #FormDataParam("slideNum") int slideNum) {
public JSONWithPadding uploadMarkup(#Context HttpServletRequest request) {
Object[] data = uploadService.getParametersAndFiles(request);
...
}

Categories

Resources