feat: Add ability to upload a plugin via URL [JENKINS-4814] (#5862)

Co-authored-by: Tim Jacomb <21194782+timja@users.noreply.github.com>
This commit is contained in:
Alex EarlandTim Jacomb authored and GitHub committed 2021-11-08 20:34:28 +00:00
1 parent 3e8a11aa95
commit 57737eec99
26 files changed
+140 -49

No files matched your search

+80 -5
View File
@@ -76,6 +76,7 @@ import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -1734,6 +1735,51 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas
return new HttpRedirect("advanced");
}
interface PluginCopier {
void copy(File target) throws Exception;
void cleanup();
}
class FileUploadPluginCopier implements PluginCopier {
private FileItem fileItem;
FileUploadPluginCopier(FileItem fileItem) {
this.fileItem = fileItem;
}
@Override
public void copy(File target) throws Exception {
fileItem.write(target);
}
@Override
public void cleanup() {
fileItem.delete();
}
}
class UrlPluginCopier implements PluginCopier {
private String url;
UrlPluginCopier(String url) {
this.url = url;
}
@Override
public void copy(File target) throws Exception {
try(InputStream input = ProxyConfiguration.getInputStream(new URL(url))) {
Files.copy(input, target.toPath());
} catch(Exception e) {
throw e;
}
}
@Override
public void cleanup() {
}
}
/**
* Uploads a plugin.
*/
@@ -1742,11 +1788,21 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas
try {
Jenkins.get().checkPermission(Jenkins.ADMINISTER);
String fileName = "";
PluginCopier copier;
ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory());
List<FileItem> items = upload.parseRequest(req);
if(StringUtils.isNotBlank(items.get(1).getString())) {
// this is a URL deployment
fileName = items.get(1).getString();
copier = new UrlPluginCopier(fileName);
} else {
// this is a file upload
FileItem fileItem = items.get(0);
fileName = Util.getFileName(fileItem.getName());
copier = new FileUploadPluginCopier(fileItem);
}
// Parse the request
FileItem fileItem = upload.parseRequest(req).get(0);
String fileName = Util.getFileName(fileItem.getName());
if("".equals(fileName)){
return new HttpRedirect("advanced");
}
@@ -1762,12 +1818,12 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas
// TODO Remove this workaround after FILEUPLOAD-293 is resolved.
t.delete();
fileItem.write(t);
copier.copy(t);
} catch (Exception e) {
// Exception thrown is too generic so at least limit the scope where it can occur
throw new ServletException(e);
}
fileItem.delete();
copier.cleanup();
final String baseName = identifyPluginShortName(t);
@@ -1810,6 +1866,25 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas
}
}
@Restricted(NoExternalUse.class)
@RequirePOST public FormValidation doCheckPluginUrl(StaplerRequest request, @QueryParameter String value) throws IOException {
if(StringUtils.isNotBlank(value)) {
try {
URL url = new URL(value);
if(!url.getProtocol().startsWith("http")) {
return FormValidation.error(Messages.PluginManager_invalidUrl());
}
if(!url.getProtocol().equals("https")) {
return FormValidation.warning(Messages.PluginManager_insecureUrl());
}
} catch(MalformedURLException e) {
return FormValidation.error(e.getMessage());
}
}
return FormValidation.ok();
}
@Restricted(NoExternalUse.class)
@RequirePOST public HttpResponse doCheckUpdatesServer() throws IOException {
Jenkins.get().checkPermission(Jenkins.SYSTEM_READ);