提交 9f1796e3 编写于 作者: K Kohsuke Kawaguchi

[FIXED JENKINS-20128]

CLI hits "/cli", so the server needs to respond to this endpoint.
上级 1b6ba71f
......@@ -55,6 +55,9 @@ Upcoming changes</a>
<!-- Record your changes in the trunk here. -->
<div id="trunk" style="display:none"><!--=TRUNK-BEGIN=-->
<ul class=image>
<li class=bug>
CLI over HTTP was not working since 1.535.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-20128">issue 20128</a>)
<li class=bug>
hudson appears in a the webpage title.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-14380">issue 14380</a>)
......
......@@ -31,10 +31,14 @@ import java.util.UUID;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
import hudson.util.IOException2;
import jenkins.model.Jenkins;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.stapler.HttpResponses.HttpResponseException;
import org.kohsuke.stapler.Stapler;
import org.kohsuke.stapler.StaplerProxy;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
......@@ -44,11 +48,13 @@ import hudson.model.RootAction;
import hudson.remoting.Channel;
/**
* Shows usage of CLI and commands.
*
* @author ogondza
*/
@Extension
@Restricted(NoExternalUse.class)
public class CLIAction implements RootAction {
public class CLIAction implements RootAction, StaplerProxy {
private transient final Map<UUID,FullDuplexHttpChannel> duplexChannels = new HashMap<UUID, FullDuplexHttpChannel>();
......@@ -62,7 +68,6 @@ public class CLIAction implements RootAction {
}
public String getUrlName() {
return "/cli";
}
......@@ -82,42 +87,51 @@ public class CLIAction implements RootAction {
req.getView(this, "command.jelly").forward(req, rsp);
}
/**
* Handles HTTP requests for duplex channels for CLI.
*/
public void doIndex(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, InterruptedException {
final Jenkins jenkins = Jenkins.getInstance();
if (!"POST".equals(req.getMethod())) {
// for GET request, serve _cli.jelly, assuming this is a browser
jenkins.checkPermission(Jenkins.READ);
req.setAttribute("command", CLICommand.clone("help"));
req.getView(this,"index.jelly").forward(req,rsp);
return;
@Override
public Object getTarget() {
StaplerRequest req = Stapler.getCurrentRequest();
if (req.getRestOfPath().length()==0 && "POST".equals(req.getMethod())) {
// CLI connection request
throw new CliEndpointResponse();
} else {
return this;
}
}
// do not require any permission to establish a CLI connection
// the actual authentication for the connecting Channel is done by CLICommand
UUID uuid = UUID.fromString(req.getHeader("Session"));
rsp.setHeader("Hudson-Duplex",""); // set the header so that the client would know
FullDuplexHttpChannel server;
if(req.getHeader("Side").equals("download")) {
duplexChannels.put(uuid,server=new FullDuplexHttpChannel(uuid, !jenkins.hasPermission(Jenkins.ADMINISTER)) {
@Override
protected void main(Channel channel) throws IOException, InterruptedException {
// capture the identity given by the transport, since this can be useful for SecurityRealm.createCliAuthenticator()
channel.setProperty(CLICommand.TRANSPORT_AUTHENTICATION, Jenkins.getAuthentication());
channel.setProperty(CliEntryPoint.class.getName(),new CliManagerImpl(channel));
}
});
/**
* Serves CLI-over-HTTP response.
*/
private class CliEndpointResponse extends HttpResponseException {
@Override
public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException {
try {
server.download(req,rsp);
} finally {
duplexChannels.remove(uuid);
// do not require any permission to establish a CLI connection
// the actual authentication for the connecting Channel is done by CLICommand
UUID uuid = UUID.fromString(req.getHeader("Session"));
rsp.setHeader("Hudson-Duplex",""); // set the header so that the client would know
FullDuplexHttpChannel server;
if(req.getHeader("Side").equals("download")) {
duplexChannels.put(uuid,server=new FullDuplexHttpChannel(uuid, !Jenkins.getInstance().hasPermission(Jenkins.ADMINISTER)) {
@Override
protected void main(Channel channel) throws IOException, InterruptedException {
// capture the identity given by the transport, since this can be useful for SecurityRealm.createCliAuthenticator()
channel.setProperty(CLICommand.TRANSPORT_AUTHENTICATION, Jenkins.getAuthentication());
channel.setProperty(CliEntryPoint.class.getName(),new CliManagerImpl(channel));
}
});
try {
server.download(req,rsp);
} finally {
duplexChannels.remove(uuid);
}
} else {
duplexChannels.get(uuid).upload(req,rsp);
}
} catch (InterruptedException e) {
throw new IOException2(e);
}
} else {
duplexChannels.get(uuid).upload(req,rsp);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册