private dynamic _getJSONFromURL(string url)
{
// ensure url ends with .json or .json?xxx
if (!url.ToLower().EndsWith(".json") &&
!(url.Contains("?") && url.ToLower().Substring(0, url.IndexOf("?")).EndsWith(".json")))
{
throw new ArgumentException("Invalid URL. URLs must end in .json", url);
}
string unique_id_to_hash = (_accessToken.access_token + url.ToLower());
var cacheKey = unique_id_to_hash.CalculateMD5();
try
{
//if in cache, check with server and if not modified then return original results
string cached_results = (string)_cache.Get(cacheKey);
if (cached_results != null)
{
string if_none_match = (string)_cache.Get(cacheKey + "etag");
string if_modified_since = (string)_cache.Get(cacheKey + "lastModified");
System.Net.HttpWebRequest wr = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(url);
wr.Method = "HEAD";
wr.Headers.Add(System.Net.HttpRequestHeader.Authorization, string.Format("Bearer {0}", _accessToken.access_token));
wr.UserAgent = _appNameAndContact;
if (!string.IsNullOrWhiteSpace(if_modified_since))
{
wr.IfModifiedSince = DateTime.Parse(if_modified_since);
}
if (!string.IsNullOrWhiteSpace(if_none_match))
{
wr.Headers["If-None-Match"] = if_none_match;
}
var resp = (System.Net.HttpWebResponse)wr.BetterGetResponse();//use extension to properly handle 304
if (resp.StatusCode == System.Net.HttpStatusCode.NotModified)
{
return Json.Decode(cached_results);
}
}
}
catch
{
//if cache check fails just make the real request to basecamp
}
try
{
System.Net.HttpWebRequest wr = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(url);
wr.Method = "GET";
wr.Headers.Add(System.Net.HttpRequestHeader.Authorization, string.Format("Bearer {0}", _accessToken.access_token));
wr.UserAgent = _appNameAndContact;
var resp = (System.Net.HttpWebResponse)wr.BetterGetResponse();
if (resp.StatusCode == System.Net.HttpStatusCode.OK)
{
using (var sw = new System.IO.StreamReader(resp.GetResponseStream()))
{
var strResp = sw.ReadToEnd();
var json_results = Json.Decode(strResp);
var resp_etag = resp.Headers["ETag"] != null ? resp.Headers["ETag"] : null;
var resp_last_modified = resp.Headers["Last-Modified"] != null ? resp.Headers["Last-Modified"] : null;
if (resp_etag != null || resp_last_modified != null)
{
//cache it
if (!string.IsNullOrWhiteSpace(resp_etag))
{
_cache.Set(cacheKey + "etag", resp_etag);
}
if (!string.IsNullOrWhiteSpace(resp_last_modified))
{
_cache.Set(cacheKey + "lastModified", resp_last_modified);
}
if (!string.IsNullOrWhiteSpace(strResp))
{
_cache.Set(cacheKey, strResp);
}
}
return json_results;
}
}
else if (resp.StatusCode == (System.Net.HttpStatusCode)429)//too many requests
{
throw new Exceptions.RateLimitExceededException(int.Parse(resp.Headers["Retry-After"]));
}
else if (resp.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
if (resp.Headers[System.Net.HttpResponseHeader.WwwAuthenticate] != null)
{
string www_auth = resp.Headers[System.Net.HttpResponseHeader.WwwAuthenticate];
int error_start = www_auth.LastIndexOf("error=\"token_expired\"");
if (error_start > -1)
{ //need to refresh token
throw new Exceptions.TokenExpired();
}
}
//throw an unauthorized exception if you get here
throw new Exceptions.UnauthorizedException();
}
else
{
throw new Exceptions.GeneralAPIException("Try again later. Status code returned was " + (int)resp.StatusCode, (int)resp.StatusCode);
}
}
catch (Exceptions.BaseException)
{
throw;
}
catch
{
return null;
}
}