Permalink
Browse files

[maven-release-plugin] copy for tag shindig-project-2.5.0-beta2

  • Loading branch information...
2 parents a693c2a + 4905a18 commit f18ed806661c9a53615e44e27b9a8fe9c8e7d41a @ryanjbaxter ryanjbaxter committed Jun 19, 2012
View
2 config/container.js
@@ -287,7 +287,7 @@
"streamFaviconUrl", "streamSourceUrl", "streamTitle", "streamUrl", "templateParams", "title",
"url", "userId"],
"activityEntry" : ["actor", "content", "generator", "icon", "id", "object", "published", "provider", "target",
- "title", "updated", "url", "verb"],
+ "title", "updated", "url", "verb", "openSocial", "extensions"],
"album" : ["id", "thumbnailUrl", "title", "description", "location", "ownerId"],
"mediaItem" : ["album_id", "created", "description", "duration", "file_size", "id", "language", "last_updated",
"location", "mime_type", "num_comments", "num_views", "num_votes", "rating", "start_time",
View
9 features/src/main/javascript/features/container.util/constant.js
@@ -332,7 +332,14 @@ osapi.container.ContainerConfig = {
* var token, ttl, error = false;
* // Do work to set token and ttl values
* if (error) {
- * result();
+ * var undef;
+ * if (error.isFatal()) {
+ * // Run all callbacks and let them know there was a horrible error.
+ * // The container token is not valid, and probably won't be any time soon.
+ * result(undef, 30, 'There was an error!'); // Try again for a miracle in 30 seconds.
+ * } else {
+ * result(undef, 15); // Call me again in 15 seconds, please
+ * }
* } else {
* result(token, ttl);
* }
View
29 features/src/main/javascript/features/container/container.js
@@ -519,8 +519,11 @@ osapi.container.Container.prototype.getSiteById = function(siteId) {
* unless the token is specified in the optional parameter, in which case the token will be
* updated with the provided value immediately.
*
- * @param {function=} callback Function to run when container token is valid.
- * @param {String=} token The containers new security token.
+ * @param {function(error)=} callback Function to run when refresh completes or is cancelled.
+ * error will be undefined if there is no error.
+ * @param {String=|boolean} tokenOrWait
+ * token The container's new security token.
+ * wait If the callback should not trigger a token fetch.
* @param {number=} ttl The token's ttl in seconds. If token is specified and ttl is 0,
* token refresh will be disabled.
* @see osapi.container.ContainerConfig.GET_CONTAINER_TOKEN (constants.js)
@@ -539,14 +542,20 @@ osapi.container.Container.prototype.scheduleRefreshTokens_ = function(tokenTTL)
oldInterval = this.tokenRefreshInterval_,
newInterval = tokenTTL ? this.setRefreshTokenInterval_(tokenTTL * 1000) : oldInterval,
refresh = function() {
- self.updateContainerSecurityToken(function() {
- self.lastRefresh_ = osapi.container.util.getCurrentTimeMs();
- // Schedule the next refresh.
- self.tokenRefreshTimer_ = setTimeout(refresh, newInterval);
-
- // Do this last so that if it ever errors, we maintain the refresh schedule.
- self.refreshTokens_();
- });
+ function callback(error) {
+ if (error) {
+ // try again, but don't force a refresh.
+ setTimeout(gadgets.util.makeClosure(self, self.updateContainerSecurityToken, callback, true), 1);
+ } else {
+ self.lastRefresh_ = osapi.container.util.getCurrentTimeMs();
+ // Schedule the next refresh.
+ self.tokenRefreshTimer_ = setTimeout(refresh, newInterval);
+
+ // Do this last so that if it ever errors, we maintain the refresh schedule.
+ self.refreshTokens_();
+ }
+ }
+ self.updateContainerSecurityToken(callback);
};
// If enabled, check to see if we no schedule or if the two intervals are different and update the schedule.
View
125 features/src/main/javascript/features/container/service.js
@@ -125,28 +125,36 @@ osapi.container.Service.prototype.getGadgetMetadata = function(request, opt_call
request['ids'] = uncachedUrls;
request['language'] = this.getLanguage();
request['country'] = this.getCountry();
- this.updateContainerSecurityToken(function() {
- osapi['gadgets']['metadata'](request).execute(function(response) {
- // If response entirely fails, augment individual errors.
- if (response['error']) {
- for (var i = 0; i < request['ids'].length; i++) {
- var id = request['ids'][i];
- finalResponse[id] = { 'error' : response['error'] };
- }
-
- // Otherwise, cache response. Augment final response with server response.
- } else {
- var currentTimeMs = osapi.container.util.getCurrentTimeMs();
- for (var id in response) {
- var resp = response[id];
- self.updateResponse_(resp, id, currentTimeMs);
- self.cachedMetadatas_[id] = resp;
- finalResponse[id] = resp;
- }
+ this.updateContainerSecurityToken(function(error) {
+ if (error) {
+ for (var i = 0; i < request['ids'].length; i++) {
+ var id = request['ids'][i];
+ finalResponse[id] = { 'error' : error };
}
-
callback(finalResponse);
- });
+ } else {
+ osapi['gadgets']['metadata'](request).execute(function(response) {
+ // If response entirely fails, augment individual errors.
+ if (response['error']) {
+ for (var i = 0; i < request['ids'].length; i++) {
+ var id = request['ids'][i];
+ finalResponse[id] = { 'error' : response['error'] };
+ }
+
+ // Otherwise, cache response. Augment final response with server response.
+ } else {
+ var currentTimeMs = osapi.container.util.getCurrentTimeMs();
+ for (var id in response) {
+ var resp = response[id];
+ self.updateResponse_(resp, id, currentTimeMs);
+ self.cachedMetadatas_[id] = resp;
+ finalResponse[id] = resp;
+ }
+ }
+
+ callback(finalResponse);
+ });
+ }
});
}
};
@@ -243,11 +251,15 @@ osapi.container.Service.prototype.getGadgetToken = function(request, opt_callbac
};
// If we have a custom token fetch function, call it -- otherwise use the default
- self.updateContainerSecurityToken(function() {
- if (self.config_[osapi.container.ContainerConfig.GET_GADGET_TOKEN]) {
- self.config_[osapi.container.ContainerConfig.GET_GADGET_TOKEN](request, tokenResponseCallback);
+ self.updateContainerSecurityToken(function(error) {
+ if (error) {
+ tokenResponseCallback({'error': error});
} else {
- osapi['gadgets']['token'](request).execute(tokenResponseCallback);
+ if (self.config_[osapi.container.ContainerConfig.GET_GADGET_TOKEN]) {
+ self.config_[osapi.container.ContainerConfig.GET_GADGET_TOKEN](request, tokenResponseCallback);
+ } else {
+ osapi['gadgets']['token'](request).execute(tokenResponseCallback);
+ }
}
});
};
@@ -410,41 +422,45 @@ osapi.container.Service.prototype.getCountry = function() {
callbacks = [];
- function runCallbacks(callbacks) {
+ function runCallbacks(callbacks, error) {
while (callbacks.length) {
- callbacks.shift().call(null); // Window context
+ callbacks.shift().call(null, error); // Window context
}
}
function refresh(fetch_once) {
- fetching = true;
+ var self = this;
if (containerTimeout) {
clearTimeout(containerTimeout);
containerTimeout = 0;
}
var fetch = fetch_once || this.config_[osapi.container.ContainerConfig.GET_CONTAINER_TOKEN];
if (fetch) {
- var self = this;
- fetch(function(token, ttl) { // token and ttl may be undefined in the case of an error
- fetching = false;
-
- // Use last known ttl if there was an error
- containerTokenTTL = token ? (ttl * 1000 * 0.8) : containerTokenTTL;
- if (containerTokenTTL) {
- // Refresh again in 80% of the reported ttl
- // Pass null in to closure because FF behaves un-expectedly when that param is not explicitly provided.
- containerTimeout = setTimeout(gadgets.util.makeClosure(self, refresh, null), containerTokenTTL);
- }
+ if (!fetching) {
+ fetching = true;
+ fetch(function(token, ttl, error) { // token and ttl may be undefined in the case of an error
+ fetching = false;
+
+ // Use last known ttl if there was an error
+ containerTokenTTL = typeof(ttl) == 'number' ? (ttl * 1000 * 0.8) : containerTokenTTL;
+ if (containerTokenTTL) {
+ // Refresh again in 80% of the reported ttl
+ // Pass null in to closure because FF behaves un-expectedly when that param is not explicitly provided.
+ containerTimeout = setTimeout(gadgets.util.makeClosure(self, refresh, null), containerTokenTTL);
+ }
- if (token) {
- // Looks like everything worked out... let's update the token.
- shindig.auth.updateSecurityToken(token);
- lastRefresh = osapi.container.util.getCurrentTimeMs();
- // And then run all the callbacks waiting for this.
- runCallbacks(callbacks);
- }
- });
+ if (token) {
+ // Looks like everything worked out... let's update the token.
+ shindig.auth.updateSecurityToken(token);
+ lastRefresh = osapi.container.util.getCurrentTimeMs();
+ // And then run all the callbacks waiting for this.
+ runCallbacks(callbacks);
+ } else if (error) {
+ runCallbacks(callbacks, error);
+ }
+ });
+ }
} else {
fetching = false;
// Fail gracefully, container supplied no fetch function. Do not hold on to callbacks.
@@ -455,8 +471,11 @@ osapi.container.Service.prototype.getCountry = function() {
/**
* @see osapi.container.Container.prototype.updateContainerSecurityToken
*/
- osapi.container.Service.prototype.updateContainerSecurityToken = function(callback, token, ttl) {
- var now = osapi.container.util.getCurrentTimeMs(),
+ osapi.container.Service.prototype.updateContainerSecurityToken = function(callback, tokenOrWait, ttl) {
+ var undef,
+ now = osapi.container.util.getCurrentTimeMs(),
+ token = typeof(tokenOrWait) != 'boolean' && tokenOrWait || undef,
+ wait = typeof(tokenOrWait) == 'boolean' && tokenOrWait,
needsRefresh = containerTokenTTL &&
(fetching || token || !lastRefresh || now > lastRefresh + containerTokenTTL);
if (needsRefresh) {
@@ -478,8 +497,14 @@ osapi.container.Service.prototype.getCountry = function() {
refresh.call(this, function(result) {
result(token, ttl);
});
- } else if (!fetching) {
- // There's no fetch going on right now. We need to start one because the token needs a refresh
+ } else if (!fetching && !wait) {
+ // There's no fetch going on right now. Unless wait is true, we need to start one right away
+ // because the token needs a refresh.
+
+ // If wait is true, the callback really just wants a valid token. It may be called with an
+ // error for informational purposes, but it's likely the callback will simply queue up
+ // immediately if there was an error. To avoid spamming the refresh method, we allow them to
+ // specify `wait` so that it can wait for success without forcing a fetch.
refresh.call(this);
}
} else if (callback) {
View
2 java/common/src/main/java/org/apache/shindig/protocol/JsonRpcServlet.java
@@ -289,7 +289,7 @@ Object getJSONResponse(String key, ResponseItem responseItem) {
map.put("updatedSince", collection.isUpdatedSince());
if (!collection.isSorted())
- map.put("sorted", collection.isUpdatedSince());
+ map.put("sorted", collection.isSorted());
map.put("list", collection.getList());
addResult(result, map);
View
61 java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/BasicOAuth2Request.java
@@ -52,6 +52,8 @@
private static final FilteredLogger LOG = FilteredLogger
.getFilteredLogger(BasicOAuth2Request.LOG_CLASS);
+ private static final short MAX_ATTEMPTS = 3;
+
private OAuth2Accessor internalAccessor;
private OAuth2Arguments arguments;
@@ -82,6 +84,8 @@
private final OAuth2RequestParameterGenerator requestParameterGenerator;
+ private short attemptCounter = 0;
+
/**
* @param fetcherConfig
* configuration options for the fetcher
@@ -175,18 +179,20 @@ public HttpResponse fetch(final HttpRequest request) {
response = this.sendErrorResponse(null, OAuth2Error.FETCH_INIT_PROBLEM,
"accessor is null", "");
} else {
- accessor.setRedirecting(false);
+ synchronized (accessor) {
+ accessor.setRedirecting(false);
- final Map<String, String> requestParams = this.requestParameterGenerator
- .generateParams(this.realRequest);
- accessor.setAdditionalRequestParams(requestParams);
+ final Map<String, String> requestParams = this.requestParameterGenerator
+ .generateParams(this.realRequest);
+ accessor.setAdditionalRequestParams(requestParams);
- HttpResponseBuilder responseBuilder = null;
- if (!accessor.isErrorResponse()) {
- responseBuilder = this.attemptFetch(accessor);
- }
+ HttpResponseBuilder responseBuilder = null;
+ if (!accessor.isErrorResponse()) {
+ responseBuilder = this.attemptFetch(accessor);
+ }
- response = this.processResponse(accessor, responseBuilder);
+ response = this.processResponse(accessor, responseBuilder);
+ }
}
}
} catch (final Throwable t) {
@@ -228,6 +234,12 @@ private HttpResponseBuilder attemptFetch(final OAuth2Accessor accessor) {
new Object[] { accessor });
}
+ this.attemptCounter++;
+
+ if (isLogging) {
+ BasicOAuth2Request.LOG.log("attempt number {0}", this.attemptCounter);
+ }
+
HttpResponseBuilder ret = null;
if (accessor.isErrorResponse()) {
@@ -236,7 +248,8 @@ private HttpResponseBuilder attemptFetch(final OAuth2Accessor accessor) {
} else {
if (BasicOAuth2Request.haveAccessToken(accessor) != null) {
// We have an access_token, use it and stop!
- ret = this.fetchData(accessor);
+ // Don't try more than three times
+ ret = this.fetchData(accessor, this.attemptCounter > BasicOAuth2Request.MAX_ATTEMPTS);
} else {
// We don't have an access token, we need to try and get one.
// First step see if we have a refresh token
@@ -493,7 +506,7 @@ private static boolean checkCanRefresh() {
return true;
}
- private HttpResponseBuilder fetchData(final OAuth2Accessor accessor) {
+ private HttpResponseBuilder fetchData(final OAuth2Accessor accessor, final boolean lastAttempt) {
final boolean isLogging = BasicOAuth2Request.LOG.isLoggable();
if (isLogging) {
BasicOAuth2Request.LOG.entering(BasicOAuth2Request.LOG_CLASS, "fetchData", accessor);
@@ -502,7 +515,7 @@ private HttpResponseBuilder fetchData(final OAuth2Accessor accessor) {
HttpResponseBuilder ret = null;
try {
- final HttpResponse response = this.fetchFromServer(accessor, this.realRequest);
+ final HttpResponse response = this.fetchFromServer(accessor, this.realRequest, lastAttempt);
if (response != null) {
ret = new HttpResponseBuilder(response);
@@ -521,12 +534,12 @@ private HttpResponseBuilder fetchData(final OAuth2Accessor accessor) {
return ret;
}
- private HttpResponse fetchFromServer(final OAuth2Accessor accessor, final HttpRequest request)
- throws OAuth2RequestException {
+ private HttpResponse fetchFromServer(final OAuth2Accessor accessor, final HttpRequest request,
+ final boolean lastAttempt) throws OAuth2RequestException {
final boolean isLogging = BasicOAuth2Request.LOG.isLoggable();
if (isLogging) {
BasicOAuth2Request.LOG.entering(BasicOAuth2Request.LOG_CLASS, "fetchFromServer",
- new Object[] { accessor, "only log request once" });
+ new Object[] { accessor, "only log request once", lastAttempt });
}
HttpResponse ret;
@@ -538,7 +551,6 @@ private HttpResponse fetchFromServer(final OAuth2Accessor accessor, final HttpRe
final long expiresAt = accessToken.getExpiresAt();
if (expiresAt != 0) {
if (currentTime >= expiresAt) {
- accessToken = null;
if (BasicOAuth2Request.LOG.isLoggable()) {
BasicOAuth2Request.LOG.log("accessToken has expired at {0}", expiresAt);
}
@@ -548,8 +560,11 @@ private HttpResponse fetchFromServer(final OAuth2Accessor accessor, final HttpRe
throw new OAuth2RequestException(OAuth2Error.MISSING_SERVER_RESPONSE,
"error removing access_token", null);
}
+ accessToken = null;
accessor.setAccessToken(null);
- return null;
+ if (!lastAttempt) {
+ return null;
+ }
}
}
}
@@ -559,7 +574,6 @@ private HttpResponse fetchFromServer(final OAuth2Accessor accessor, final HttpRe
final long expiresAt = refreshToken.getExpiresAt();
if (expiresAt != 0) {
if (currentTime >= expiresAt) {
- refreshToken = null;
if (BasicOAuth2Request.LOG.isLoggable()) {
BasicOAuth2Request.LOG.log("refreshToken has expired at {0}", expiresAt);
}
@@ -569,8 +583,11 @@ private HttpResponse fetchFromServer(final OAuth2Accessor accessor, final HttpRe
throw new OAuth2RequestException(OAuth2Error.MISSING_SERVER_RESPONSE,
"error removing refresh_token", null);
}
+ refreshToken = null;
accessor.setRefreshToken(null);
- return null;
+ if (!lastAttempt) {
+ return null;
+ }
}
}
}
@@ -629,7 +646,9 @@ private HttpResponse fetchFromServer(final OAuth2Accessor accessor, final HttpRe
accessor.setAccessToken(null);
}
- ret = null;
+ if (!lastAttempt) {
+ ret = null;
+ }
}
if (isLogging) {
@@ -828,7 +847,7 @@ private OAuth2HandlerError refreshToken(final OAuth2Accessor accessor) {
if (ret == null) {
// response is not null..
final int statusCode = response.getHttpStatusCode();
- if (statusCode == HttpResponse.SC_UNAUTHORIZED) {
+ if ((statusCode == HttpResponse.SC_UNAUTHORIZED) || (statusCode == HttpResponse.SC_BAD_REQUEST)) {
try {
this.store.removeToken(accessor.getRefreshToken());
} catch (final GadgetException e) {
View
11 java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/MakeRequestHandler.java
@@ -28,6 +28,7 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shindig.auth.AuthInfoUtil;
import org.apache.shindig.auth.SecurityToken;
@@ -87,6 +88,8 @@
public static final String CORE_IO = "core.io";
public static final String UNPARSEABLE_CRUFT = "unparseableCruft";
public static final int MAX_POST_SIZE_DEFAULT = 5 * 1024 * 1024; // 5 MiB
+ public static final String IFRAME_RESPONSE_PREFIX = "<html><head></head><body><textarea></textarea><script type='text/javascript'>document.getElementsByTagName('TEXTAREA')[0].value='";
+ public static final String IFRAME_RESPONSE_SUFFIX = "';</script></body></html>";
private final Map<String, String> unparseableCruftMsgs;
private final RequestPipeline requestPipeline;
@@ -185,10 +188,10 @@ public boolean getIgnoreCache() {
PrintWriter out = response.getWriter();
if ("1".equals(getParameter(request, MULTI_PART_FORM_POST_IFRAME, null))) {
response.setContentType("text/html");
- out.write("<html><head></head><body><textarea>");
- out.write(this.unparseableCruftMsgs.get(container));
- out.write(output);
- out.write("</textarea></body></html>");
+ out.write(IFRAME_RESPONSE_PREFIX);
+ out.write(StringEscapeUtils.escapeEcmaScript(this.unparseableCruftMsgs.get(container)));
+ out.write(StringEscapeUtils.escapeEcmaScript(output));
+ out.write(IFRAME_RESPONSE_SUFFIX);
} else {
response.setContentType("application/json");
out.write(this.unparseableCruftMsgs.get(container) + output);
View
37 java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/MakeRequestHandlerTest.java
@@ -32,6 +32,8 @@
import javax.servlet.http.HttpServletRequest;
+import org.apache.commons.lang3.StringEscapeUtils;
+import org.apache.commons.lang3.StringUtils;
import org.apache.shindig.auth.AuthInfoUtil;
import org.apache.shindig.auth.SecurityToken;
import org.apache.shindig.common.servlet.HttpUtilTest;
@@ -60,6 +62,7 @@
import org.junit.Before;
import org.junit.Test;
+import com.google.common.base.Strings;
import com.google.common.collect.Lists;
/**
@@ -149,11 +152,14 @@ private void expectPatchAndReturnBody(AuthType authType, String response) throws
}
private JSONObject extractJsonFromResponse() throws JSONException {
- String body = recorder.getResponseAsString();
+ return extractJsonFromResponse(recorder.getResponseAsString());
+ }
+
+ private JSONObject extractJsonFromResponse(String response) throws JSONException {
String defaultCruftMsg = "throw 1; < don't be evil' >";
- assertStartsWith(defaultCruftMsg, body);
- body = body.substring(defaultCruftMsg.length());
- return new JSONObject(body).getJSONObject(REQUEST_URL.toString());
+ assertStartsWith(defaultCruftMsg, response);
+ response = response.substring(defaultCruftMsg.length());
+ return new JSONObject(response).getJSONObject(REQUEST_URL.toString());
}
@Before
@@ -473,6 +479,29 @@ public void testFetchFeedWithParameters() throws Exception {
}
@Test
+ public void testMultiPartFormPostWithSpecialChars() throws Exception {
+ String body = "\u003c!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\"\u003e"
+ + "<html><body>&quot;Hello, world!&quot;</body></html>";
+ expectGetAndReturnBody(body);
+
+ expect(request.getParameter(MakeRequestHandler.CONTENT_TYPE_PARAM)).andReturn("TEXT");
+ expect(request.getParameter(MakeRequestHandler.MULTI_PART_FORM_POST_IFRAME)).andReturn("1");
+ replay();
+
+ handler.fetch(request, recorder);
+ String response = recorder.getResponseAsString();
+ response = StringUtils.removeStart(response, MakeRequestHandler.IFRAME_RESPONSE_PREFIX);
+ response = StringUtils.removeEnd(response, MakeRequestHandler.IFRAME_RESPONSE_SUFFIX);
+ response = StringEscapeUtils.unescapeEcmaScript(response);
+ JSONObject result = extractJsonFromResponse(response);
+ assertEquals(
+ "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">"
+ + "<html><body>&quot;Hello, world!&quot;</body></html>",
+ result.get("body")
+ );
+ }
+
+ @Test
public void testFetchEmptyDocument() throws Exception {
expectGetAndReturnBody("");
replay();
View
3 java/social-api/src/main/java/org/apache/shindig/social/opensocial/model/ActivityEntry.java
@@ -49,7 +49,8 @@
UPDATED("updated"),
URL("url"),
VERB("verb"),
- OPENSOCIAL("openSocial");
+ OPENSOCIAL("openSocial"),
+ EXTENSIONS("extensions");
// The name of the JSON element
private final String jsonString;
View
2 .../java/org/apache/shindig/social/dataservice/integration/RestfulJsonActivityEntryTest.java
@@ -112,7 +112,7 @@ public void testActivityEntryExtensionJson() throws Exception {
@Test
public void testGetActivityEntrySupportedFields() throws Exception {
String resp = getResponse("/activitystreams/@supportedFields", "GET", null, ContentTypes.OUTPUT_JSON_CONTENT_TYPE);
- String expected = TestUtils.loadTestFixture(FIXTURE_LOC + "ActivityStreamsSupportedFields.json");;
+ String expected = TestUtils.loadTestFixture(FIXTURE_LOC + "ActivityStreamsSupportedFields.json");
assertTrue(TestUtils.jsonsEqual(expected, resp));
}
}
View
4 ...pache/shindig/social/dataservice/integration/fixtures/ActivityStreamsSupportedFields.json
@@ -12,6 +12,8 @@
"title",
"updated",
"url",
- "verb"
+ "verb",
+ "openSocial",
+ "extensions"
]
}

0 comments on commit f18ed80

Please sign in to comment.