Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Prefer the postMessage version to retrieve the metadata so that we can leave the existing JSON format as-is for backward compatibility with pre-1.424 Jenkins.
(cherry picked from commit f3701da)

Conflicts:

	war/src/main/webapp/scripts/hudson-behavior.js
  • Loading branch information
kohsuke committed Sep 13, 2012
1 parent 682c955 commit ad61369
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 7 deletions.
20 changes: 19 additions & 1 deletion core/src/main/java/hudson/model/DownloadService.java
Expand Up @@ -63,7 +63,8 @@ public class DownloadService extends PageDecorator {
*/
public String generateFragment() {
if (neverUpdate) return "";

if (doesNotSupportPostMessage()) return "";

StringBuilder buf = new StringBuilder();
if(Jenkins.getInstance().hasPermission(Jenkins.READ)) {
long now = System.currentTimeMillis();
Expand All @@ -90,6 +91,23 @@ public String generateFragment() {
return buf.toString();
}

private boolean doesNotSupportPostMessage() {
StaplerRequest req = Stapler.getCurrentRequest();
if (req==null) return false;

String ua = req.getHeader("User-Agent");
if (ua==null) return false;

// according to http://caniuse.com/#feat=x-doc-messaging, IE <=7 doesn't support pstMessage
// see http://www.useragentstring.com/pages/Internet%20Explorer/ for user agents

// we want to err on the cautious side here.
// Because of JENKINS-15105, we can't serve signed metadata from JSON, which means we need to be
// using a modern browser as a vehicle to request these data. This check is here to prevent Jenkins
// from using older browsers that are known not to support postMessage as the vehicle.
return ua.contains("Windows") && (ua.contains(" MSIE 5.") || ua.contains(" MSIE 6.") || ua.contains(" MSIE 7."));
}

private String mapHttps(String url) {
/*
HACKISH:
Expand Down
78 changes: 72 additions & 6 deletions war/src/main/webapp/scripts/hudson-behavior.js
Expand Up @@ -2571,12 +2571,69 @@ function loadScript(href,callback) {
head.insertBefore( script, head.firstChild );
}

/**
* Loads a dynamically created invisible IFRAME.
*/
function createIframe(src,callback) {
var iframe = document.createElement("iframe");
iframe.src = src;
iframe.style.display = "none";

var done = false;
iframe.onload = iframe.onreadystatechange = function() {
if ( !done && (!this.readyState ||
this.readyState === "loaded" || this.readyState === "complete") ) {
done = true;
callback();
}
};

document.body.appendChild(iframe);
return iframe;
}

var downloadService = {
continuations: {},

download : function(id,url,info, postBack,completionHandler) {
this.continuations[id] = {postBack:postBack,completionHandler:completionHandler};
loadScript(url+"?"+Hash.toQueryString(info));
var tag = {id:id,postBack:postBack,completionHandler:completionHandler,received:false};
this.continuations[id] = tag;

// use JSONP to download the data
function fallback() {
loadScript(url+"?id="+id+'&'+Hash.toQueryString(info));
}

if (window.postMessage) {
// try downloading the postMessage version of the data,
// if we don't receive postMessage (which probably means the server isn't ready with these new datasets),
// fallback to JSONP
tag.iframe = createIframe(url+".html",function() {
window.setTimeout(function() {
if (!tag.received)
fallback();
},100); // bit of delay in case onload on our side fires first
});
} else {
// this browser doesn't support postMessage
fallback();
}

// NOTE:
// the only reason we even try fallback() is in case our server accepts the submission without a signature
// (which it really shouldn't)
},

/**
* Call back to postMessage
*/
receiveMessage : function(ev) {
var self = this;
Object.values(this.continuations).each(function(tag) {
if (tag.iframe.contentWindow==ev.source) {
self.post(tag.id,JSON.parse(ev.data));
}
})
},

post : function(id,data) {
Expand All @@ -2585,15 +2642,22 @@ var downloadService = {
data = id;
id = data.id;
}
var o = this.continuations[id];
var tag = this.continuations[id];
if (tag==undefined) {
console.log("Submission from update center that we don't know: "+id);
console.log("Likely mismatch between the registered ID vs ID in JSON");
return;
}
tag.received = true;

// send the payload back in the body. We used to send this in as a form submission, but that hits the form size check in Jetty.
new Ajax.Request(o.postBack, {
new Ajax.Request(tag.postBack, {
contentType:"application/json",
encoding:"UTF-8",
postBody:Object.toJSON(data),
onSuccess: function() {
if(o.completionHandler!=null)
o.completionHandler();
if(tag.completionHandler!=null)
tag.completionHandler();
else if(downloadService.completionHandler!=null)
downloadService.completionHandler();
}
Expand All @@ -2604,6 +2668,8 @@ var downloadService = {
// update center service. to remain compatible with earlier version of Jenkins, aliased.
var updateCenter = downloadService;

YAHOO.util.Event.addListener(window, "message", function(ev) { downloadService.receiveMessage(ev); })

/*
redirects to a page once the page is ready.
Expand Down

0 comments on commit ad61369

Please sign in to comment.