package com.instructure.canvasapi.api.compatibility_synchronous;
import android.annotation.TargetApi;
import android.content.Context;
import android.util.Log;
import com.instructure.canvasapi.utilities.APIHelpers;
import com.instructure.canvasapi.utilities.Masquerading;
import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.util.EntityUtils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
/**
* Copyright (c) 2015 Instructure. All rights reserved.
*/
public class HttpHelpers {
/**
* httpPut is a bare-bones implementation for writing HTTPPut requests to the CanvasAPI.
* It is used for the old-style synchronous calls that haven't yet been converted.
* @param putURL
* @param context
* @return
*/
public static APIHttpResponse httpPut(String putURL, Context context) {
//Explicit check for null.
if(context == null) {
return new APIHttpResponse();
}
try {
putURL = Masquerading.addMasqueradeId(putURL, context);
//Remove spaces from the URL
putURL = putURL.replace(" ", "%20");
String api_protocol = APIHelpers.loadProtocol(context);
//Make sure the URL begins with https://
if(!putURL.startsWith("https://") && !putURL.startsWith("http://"))
{
putURL = api_protocol + "://"+APIHelpers.getDomain(context)+"/"+putURL;
}
HttpPut get = new HttpPut(putURL);
String token = APIHelpers.getToken(context);
if(token != null)
{
String headerValue = String.format("Bearer %s", token);
get.addHeader("Authorization",headerValue);
}
HttpClient client = getHttpClient(context);
HttpResponse response = client.execute(get);
return parseLinkHeaderResponse(response);
} catch(Exception E) {
return new APIHttpResponse();
}
}
/**
* externalHttpGet is a way to make unauthenticated HTTPRequests to APIs other than the CanvasAPI.
* The ENTIRE url must be specified including domain.
* @param context
* @param getURL
* @return
*/
public static APIHttpResponse externalHttpGet(Context context, String getURL) {
return externalHttpGet(context, getURL, false);
}
/**
* externalHttpGet is a way to make HTTPRequests to APIs other than the CanvasAPI.
* The ENTIRE url must be specified including domain.
* @param context
* @param getURL
* @param includeAuthentication whether or not the should be authenticated using the CanvasToken saved.
* @return
*/
public static APIHttpResponse externalHttpGet(Context context, String getURL, boolean includeAuthentication) {
//Explicit check for null.
if(context == null) {
return new APIHttpResponse();
}
try {
getURL = Masquerading.addMasqueradeId(getURL, context);
//Remove spaces from the URL
getURL = getURL.replace(" ", "%20");
String api_protocol = APIHelpers.loadProtocol(context);
//Make sure the URL begins with https://
if(!getURL.startsWith("https://") && !getURL.startsWith("http://"))
{
getURL = api_protocol + "://"+getURL;
}
final HttpURLConnection urlConnection = (HttpURLConnection) new URL(getURL).openConnection();
urlConnection.setRequestMethod("GET");
if (includeAuthentication) {
String token = APIHelpers.getToken(context);
if(token != null)
{
String headerValue = String.format("Bearer %s", token);
urlConnection.setRequestProperty("Authorization", headerValue);
}
}
return parseLinkHeaderResponse(urlConnection);
} catch(Exception e) {
Log.e(APIHelpers.LOG_TAG, "Error externalHttpGet: " + e.getMessage());
return new APIHttpResponse();
}
}
/**
* httpPost is a bare-bones implementation for writing HTTPPost requests to the CanvasAPI.
* It is used for the old-style synchronous calls that haven't yet been converted.
* @param postURL
* @param postVars
* @param context
* @return
*/
public static APIHttpResponse httpPost(String postURL, List<BasicNameValuePair> postVars, Context context) {
//Explicit check for null.
if(context == null) {
return new APIHttpResponse();
}
try {
postURL = Masquerading.addMasqueradeId(postURL, context);
//Remove spaces from the URL
postURL = postURL.replace(" ", "%20");
String api_protocol = APIHelpers.loadProtocol(context);
//Make sure the URL begins with https://
if(!postURL.startsWith("https://") && !postURL.startsWith("http://"))
{
postURL = api_protocol + "://"+APIHelpers.getDomain(context)+"/"+postURL;
}
HttpPost post = new HttpPost(postURL);
String token = APIHelpers.getToken(context);
if(token != null)
{
String headerValue = String.format("Bearer %s", token);
post.addHeader("Authorization",headerValue);
}
HttpClient client = getHttpClient(context);
if(postVars!=null)
post.setEntity(new UrlEncodedFormEntity(postVars,"UTF-8"));
HttpResponse response = client.execute(post);
return parseLinkHeaderResponse(response);
} catch(Exception E) {
return new APIHttpResponse();
}
}
/**
* getHttpClient is a builder used to inject the user agent into the standard HTTPClient.
* @param context
* @return
*/
private static HttpClient getHttpClient(Context context) {
HttpClient httpclient = new DefaultHttpClient();
httpclient.getParams().setParameter(CoreProtocolPNames.USER_AGENT, APIHelpers.getUserAgent(context));
return httpclient;
}
/**
* redirectURL tries its best to follow http redirects until there are no more.
* @param urlConnection
* @return
*/
@TargetApi(9)
public static HttpURLConnection redirectURL(HttpURLConnection urlConnection) {
HttpURLConnection.setFollowRedirects(true);
try {
urlConnection.connect();
String currentURL = urlConnection.getURL().toString();
do
{
urlConnection.getResponseCode();
currentURL = urlConnection.getURL().toString();
urlConnection = (HttpURLConnection) new URL(currentURL).openConnection();
}
while (!urlConnection.getURL().toString().equals(currentURL));
} catch(Exception E){}
return urlConnection;
}
private static APIHttpResponse parseLinkHeaderResponse(HttpURLConnection urlConnection) {
APIHttpResponse httpResponse = new APIHttpResponse();
InputStream inputStream = null;
try {
httpResponse.responseCode = urlConnection.getResponseCode();
// Check if response is supposed to have a body
if (httpResponse.responseCode != 204) {
inputStream = urlConnection.getInputStream();
InputStreamReader isReader = new InputStreamReader(inputStream );
BufferedReader br = new BufferedReader(isReader );
StringBuilder sb = new StringBuilder();
String inputLine = "";
while ((inputLine = br.readLine()) != null) {
sb.append(inputLine);
}
String response = sb.toString();
httpResponse.responseBody = response;
}
httpResponse.linkHeaders = APIHelpers.parseLinkHeaderResponse(urlConnection.getHeaderField("link"));
} catch (Exception e) {
Log.e(APIHelpers.LOG_TAG, "Failed to get response: " + e.getMessage());
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
Log.e(APIHelpers.LOG_TAG, "Could not close input stream: " + e.getMessage());
}
}
}
return httpResponse;
}
public static String getHtml(String url) throws IOException {
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet(url);
HttpResponse response = client.execute(request);
return EntityUtils.toString(response.getEntity());
}
/**
* parseLinkHeaderResponse is the old way of parsing the pagination URLs out of the response.
* @param response
* @return
*/
private static APIHttpResponse parseLinkHeaderResponse(HttpResponse response) {
APIHttpResponse httpResponse = new APIHttpResponse();
//Get status code.
httpResponse.responseCode = response.getStatusLine().getStatusCode();
// Check if response is supposed to have a body
if (httpResponse.responseCode != 204) {
try
{
httpResponse.responseBody = EntityUtils.toString(response.getEntity());
}
catch(Exception E) {}
}
Header[] linkHeader = response.getHeaders("Link");
for(int j = 0; j < linkHeader.length; j++) {
HeaderElement[] elements = linkHeader[j].getElements();
for(int i = 0; i < elements.length;i ++) {
String first = elements[i].getName();
String last = elements[i].getValue();
//Seems to strip out the equals between name and value
String url = first+"="+last;
if(url.startsWith("<") && url.endsWith(">")) {
url = url.substring(1, url.length()-1);
} else {
continue;
}
for(int k = 0; k < elements[i].getParameterCount(); k++) {
NameValuePair nvp = elements[i].getParameter(k);
if(nvp.getName().equals("rel"))
{
if(nvp.getValue().equals("prev"))
{
httpResponse.prevURL = url;
}
else if(nvp.getValue().equals("next"))
{
httpResponse.nextURL = url;
}
else if(nvp.getValue().equals("first"))
{
httpResponse.firstURL = url;
}
else if(nvp.getValue().equals("last"))
{
httpResponse.lastURL = url;
}
}
}
}
}
return httpResponse;
}
}