Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWinston Prakash2012-03-21 17:46:45 -0400
committerWinston Prakash2012-03-21 17:46:45 -0400
commitf2175e4f8b1660c1e83f45d91c8b368a04a53aef (patch)
treec39c7f8f09b7dc4035c9fab1163a76164c212c96 /hudson-cli
parentafad51a87a21c358ee6db167bc3e2c319b77b36c (diff)
downloadorg.eclipse.hudson.core-f2175e4f8b1660c1e83f45d91c8b368a04a53aef.tar.gz
org.eclipse.hudson.core-f2175e4f8b1660c1e83f45d91c8b368a04a53aef.tar.xz
org.eclipse.hudson.core-f2175e4f8b1660c1e83f45d91c8b368a04a53aef.zip
Revert to original package name "org.hudsonci" to avoid any backward compatibility issues
Diffstat (limited to 'hudson-cli')
-rw-r--r--hudson-cli/pom.xml2
-rw-r--r--hudson-cli/src/main/java/hudson/cli/CLI.java175
-rw-r--r--hudson-cli/src/main/java/hudson/cli/CliEntryPoint.java33
-rw-r--r--hudson-cli/src/main/java/hudson/cli/FullDuplexHttpStream.java127
-rw-r--r--hudson-cli/src/main/java/hudson/cli/SequenceOutputStream.java (renamed from hudson-cli/src/main/java/org/eclipse/hudson/cli/SequenceOutputStream.java)2
-rw-r--r--hudson-cli/src/main/java/org/eclipse/hudson/cli/CLI.java187
-rw-r--r--hudson-cli/src/main/java/org/eclipse/hudson/cli/CliEntryPoint.java50
-rw-r--r--hudson-cli/src/main/java/org/eclipse/hudson/cli/FullDuplexHttpStream.java142
8 files changed, 315 insertions, 403 deletions
diff --git a/hudson-cli/pom.xml b/hudson-cli/pom.xml
index de8e78e3..b2e39b16 100644
--- a/hudson-cli/pom.xml
+++ b/hudson-cli/pom.xml
@@ -38,7 +38,7 @@
<descriptorId>jar-with-dependencies</descriptorId>
<archive>
<manifest>
- <mainClass>org.eclipse.hudson.cli.CLI</mainClass>
+ <mainClass>hudson.cli.CLI</mainClass>
</manifest>
</archive>
</configuration>
diff --git a/hudson-cli/src/main/java/hudson/cli/CLI.java b/hudson-cli/src/main/java/hudson/cli/CLI.java
index e7cd55ff..f22a40a3 100644
--- a/hudson-cli/src/main/java/hudson/cli/CLI.java
+++ b/hudson-cli/src/main/java/hudson/cli/CLI.java
@@ -1,30 +1,187 @@
/*******************************************************************************
*
- * Copyright (c) 2004-2010 Oracle Corporation.
+ * Copyright (c) 2004-2009, Oracle Corporation
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
- * Contributors:
- *
+ * Contributors:
+ *
+ *
+ *
*
*******************************************************************************/
package hudson.cli;
-import java.io.IOException;
+import hudson.remoting.Channel;
+import hudson.remoting.RemoteInputStream;
+import hudson.remoting.RemoteOutputStream;
+import hudson.remoting.PingThread;
+import hudson.remoting.SocketInputStream;
+import hudson.remoting.SocketOutputStream;
+import hudson.cli.client.Messages;
+
import java.net.URL;
+import java.net.URLConnection;
+import java.net.Socket;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+import java.util.ArrayList;
+import java.util.logging.Logger;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.DataOutputStream;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
/**
- * Exists for backward compatibility
- * @author Winston Prakash
- * @see org.eclipse.hudson.cli.CLI
+ * CLI entry point to Hudson.
+ *
+ * @author Kohsuke Kawaguchi
*/
-public class CLI extends org.eclipse.hudson.cli.CLI {
+public class CLI {
+ private final ExecutorService pool;
+ private final Channel channel;
+ private final CliEntryPoint entryPoint;
+ private final boolean ownsPool;
public CLI(URL hudson) throws IOException, InterruptedException {
- super(hudson);
+ this(hudson,null);
}
+
+ public CLI(URL hudson, ExecutorService exec) throws IOException, InterruptedException {
+ String url = hudson.toExternalForm();
+ if(!url.endsWith("/")) url+='/';
+
+ ownsPool = exec==null;
+ pool = exec!=null ? exec : Executors.newCachedThreadPool();
+
+ int clip = getCliTcpPort(url);
+ if(clip>=0) {
+ // connect via CLI port
+ String host = new URL(url).getHost();
+ LOGGER.fine("Trying to connect directly via TCP/IP to port "+clip+" of "+host);
+ Socket s = new Socket(host,clip);
+ DataOutputStream dos = new DataOutputStream(s.getOutputStream());
+ dos.writeUTF("Protocol:CLI-connect");
+
+ channel = new Channel("CLI connection to "+hudson, pool,
+ new BufferedInputStream(new SocketInputStream(s)),
+ new BufferedOutputStream(new SocketOutputStream(s)));
+ } else {
+ // connect via HTTP
+ LOGGER.fine("Trying to connect to "+url+" via HTTP");
+ url+="cli";
+ hudson = new URL(url);
+
+ FullDuplexHttpStream con = new FullDuplexHttpStream(hudson);
+ channel = new Channel("Chunked connection to "+hudson,
+ pool,con.getInputStream(),con.getOutputStream());
+ new PingThread(channel,30*1000) {
+ protected void onDead() {
+ // noop. the point of ping is to keep the connection alive
+ // as most HTTP servers have a rather short read time out
+ }
+ }.start();
+ }
+
+ // execute the command
+ entryPoint = (CliEntryPoint)channel.waitForRemoteProperty(CliEntryPoint.class.getName());
+
+ if(entryPoint.protocolVersion()!=CliEntryPoint.VERSION)
+ throw new IOException(Messages.CLI_VersionMismatch());
+ }
+
+ /**
+ * If the server advertises CLI port, returns it.
+ */
+ private int getCliTcpPort(String url) throws IOException {
+ URLConnection head = new URL(url).openConnection();
+ try {
+ head.connect();
+ } catch (IOException e) {
+ throw (IOException)new IOException("Failed to connect to "+url).initCause(e);
+ }
+ String p = head.getHeaderField("X-Hudson-CLI-Port");
+ if(p==null) return -1;
+ return Integer.parseInt(p);
+ }
+
+ public void close() throws IOException, InterruptedException {
+ channel.close();
+ channel.join();
+ if(ownsPool)
+ pool.shutdown();
+ }
+
+ public int execute(List<String> args, InputStream stdin, OutputStream stdout, OutputStream stderr) {
+ return entryPoint.main(args,Locale.getDefault(),
+ new RemoteInputStream(stdin),
+ new RemoteOutputStream(stdout),
+ new RemoteOutputStream(stderr));
+ }
+
+ public int execute(List<String> args) {
+ return execute(args,System.in,System.out,System.err);
+ }
+
+ public int execute(String... args) {
+ return execute(Arrays.asList(args));
+ }
+
+ /**
+ * Returns true if the named command exists.
+ */
+ public boolean hasCommand(String name) {
+ return entryPoint.hasCommand(name);
+ }
+
+ public static void main(final String[] _args) throws Exception {
+ List<String> args = Arrays.asList(_args);
+
+ String url = System.getenv("HUDSON_URL");
+
+ while(!args.isEmpty()) {
+ String head = args.get(0);
+ if(head.equals("-s") && args.size()>=2) {
+ url = args.get(1);
+ args = args.subList(2,args.size());
+ continue;
+ }
+ break;
+ }
+
+ if(url==null) {
+ printUsageAndExit(Messages.CLI_NoURL());
+ return;
+ }
+
+ if(args.isEmpty())
+ args = Arrays.asList("help"); // default to help
+
+ CLI cli = new CLI(new URL(url));
+ try {
+ // execute the command
+ // Arrays.asList is not serializable --- see 6835580
+ args = new ArrayList<String>(args);
+ System.exit(cli.execute(args, System.in, System.out, System.err));
+ } finally {
+ cli.close();
+ }
+ }
+
+ private static void printUsageAndExit(String msg) {
+ if(msg!=null) System.out.println(msg);
+ System.err.println(Messages.CLI_Usage());
+ System.exit(-1);
+ }
+
+ private static final Logger LOGGER = Logger.getLogger(CLI.class.getName());
}
diff --git a/hudson-cli/src/main/java/hudson/cli/CliEntryPoint.java b/hudson-cli/src/main/java/hudson/cli/CliEntryPoint.java
index 8ce6b9c4..7d5b6201 100644
--- a/hudson-cli/src/main/java/hudson/cli/CliEntryPoint.java
+++ b/hudson-cli/src/main/java/hudson/cli/CliEntryPoint.java
@@ -16,12 +16,35 @@
package hudson.cli;
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Locale;
/**
- * Exists for backward compatibility
- * @author Winston Prakash
- * @see org.eclipse.hudson.cli.CliEntryPoint
+ * Remotable interface for CLI entry point on the server side.
+ *
+ * @author Kohsuke Kawaguchi
*/
-public interface CliEntryPoint extends org.eclipse.hudson.cli.CliEntryPoint{
-
+public interface CliEntryPoint {
+ /**
+ * Just like the static main method.
+ *
+ * @param locale
+ * Locale of this client.
+ */
+ int main(List<String> args, Locale locale, InputStream stdin, OutputStream stdout, OutputStream stderr);
+
+ /**
+ * Does the named command exist?
+ */
+ boolean hasCommand(String name);
+
+ /**
+ * Returns {@link #VERSION}, so that the client and the server can detect version incompatibility
+ * gracefully.
+ */
+ int protocolVersion();
+
+ int VERSION = 1;
}
diff --git a/hudson-cli/src/main/java/hudson/cli/FullDuplexHttpStream.java b/hudson-cli/src/main/java/hudson/cli/FullDuplexHttpStream.java
index 31ffb0f0..c3ecae8e 100644
--- a/hudson-cli/src/main/java/hudson/cli/FullDuplexHttpStream.java
+++ b/hudson-cli/src/main/java/hudson/cli/FullDuplexHttpStream.java
@@ -14,18 +14,129 @@
package hudson.cli;
+import java.io.BufferedReader;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
import java.net.URL;
+import java.util.UUID;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.commons.codec.binary.Base64;
/**
- * Exists for backward compatibility
- * @author Winston Prakash
- * @see org.eclipse.hudson.cli.FullDuplexHttpStream
+ * Creates a capacity-unlimited bi-directional {@link InputStream}/{@link OutputStream} pair over
+ * HTTP, which is a request/response protocol.
+ *
+ * @author Kohsuke Kawaguchi
*/
-public class FullDuplexHttpStream extends org.eclipse.hudson.cli.FullDuplexHttpStream{
+public class FullDuplexHttpStream {
+ private final URL target;
+
+ private final OutputStream output;
+ private final InputStream input;
+
+ public InputStream getInputStream() {
+ return input;
+ }
+
+ public OutputStream getOutputStream() {
+ return output;
+ }
+
+ public FullDuplexHttpStream(URL target) throws IOException {
+ this.target = target;
+
+ String authorization = null;
+ if (target.getUserInfo() != null) {
+ authorization = new String(Base64.encodeBase64(target.getUserInfo().getBytes()));
+ }
+
+ CrumbData crumbData = new CrumbData();
+
+ UUID uuid = UUID.randomUUID(); // so that the server can correlate those two connections
+
+ // server->client
+ HttpURLConnection con = (HttpURLConnection) target.openConnection();
+ con.setDoOutput(true); // request POST to avoid caching
+ con.setRequestMethod("POST");
+ con.addRequestProperty("Session", uuid.toString());
+ con.addRequestProperty("Side","download");
+ if (authorization != null) {
+ con.addRequestProperty("Authorization", "Basic " + authorization);
+ }
+ if(crumbData.isValid) {
+ con.addRequestProperty(crumbData.crumbName, crumbData.crumb);
+ }
+ con.getOutputStream().close();
+ input = con.getInputStream();
+ // make sure we hit the right URL
+ if(con.getHeaderField("Hudson-Duplex")==null)
+ throw new IOException(target+" doesn't look like Hudson");
+
+ // client->server uses chunked encoded POST for unlimited capacity.
+ con = (HttpURLConnection) target.openConnection();
+ con.setDoOutput(true); // request POST
+ con.setRequestMethod("POST");
+ con.setChunkedStreamingMode(0);
+ con.setRequestProperty("Content-type","application/octet-stream");
+ con.addRequestProperty("Session", uuid.toString());
+ con.addRequestProperty("Side","upload");
+ if (authorization != null) {
+ con.addRequestProperty ("Authorization", "Basic " + authorization);
+ }
+
+ if(crumbData.isValid) {
+ con.addRequestProperty(crumbData.crumbName, crumbData.crumb);
+ }
+ output = con.getOutputStream();
+ }
+
+ static final int BLOCK_SIZE = 1024;
+ static final Logger LOGGER = Logger.getLogger(FullDuplexHttpStream.class.getName());
+
+ private final class CrumbData {
+ String crumbName;
+ String crumb;
+ boolean isValid;
+
+ private CrumbData() {
+ this.crumbName = "";
+ this.crumb = "";
+ this.isValid = false;
+ getData();
+ }
+
+ private void getData() {
+ try {
+ String base = createCrumbUrlBase();
+ crumbName = readData(base+"?xpath=/*/crumbRequestField/text()");
+ crumb = readData(base+"?xpath=/*/crumb/text()");
+ isValid = true;
+ LOGGER.fine("Crumb data: "+crumbName+"="+crumb);
+ } catch (IOException e) {
+ // presumably this Hudson doesn't use crumb
+ LOGGER.log(Level.FINE,"Failed to get crumb data",e);
+ }
+ }
+
+ private String createCrumbUrlBase() {
+ String url = target.toExternalForm();
+ return new StringBuilder(url.substring(0, url.lastIndexOf("/cli"))).append("/crumbIssuer/api/xml/").toString();
+ }
- public FullDuplexHttpStream(URL target) throws IOException {
- super(target);
- }
-
+ private String readData(String dest) throws IOException {
+ HttpURLConnection con = (HttpURLConnection) new URL(dest).openConnection();
+ try {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
+ return reader.readLine();
+ }
+ finally {
+ con.disconnect();
+ }
+ }
+ }
}
diff --git a/hudson-cli/src/main/java/org/eclipse/hudson/cli/SequenceOutputStream.java b/hudson-cli/src/main/java/hudson/cli/SequenceOutputStream.java
index a234018b..94da896d 100644
--- a/hudson-cli/src/main/java/org/eclipse/hudson/cli/SequenceOutputStream.java
+++ b/hudson-cli/src/main/java/hudson/cli/SequenceOutputStream.java
@@ -12,7 +12,7 @@
*
*******************************************************************************/
-package org.eclipse.hudson.cli;
+package hudson.cli;
import java.io.OutputStream;
import java.io.IOException;
diff --git a/hudson-cli/src/main/java/org/eclipse/hudson/cli/CLI.java b/hudson-cli/src/main/java/org/eclipse/hudson/cli/CLI.java
deleted file mode 100644
index 8029a52a..00000000
--- a/hudson-cli/src/main/java/org/eclipse/hudson/cli/CLI.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*******************************************************************************
- *
- * Copyright (c) 2004-2009, Oracle Corporation
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *
- *
- *
- *
- *******************************************************************************/
-
-package org.eclipse.hudson.cli;
-
-import hudson.remoting.Channel;
-import hudson.remoting.RemoteInputStream;
-import hudson.remoting.RemoteOutputStream;
-import hudson.remoting.PingThread;
-import hudson.remoting.SocketInputStream;
-import hudson.remoting.SocketOutputStream;
-import hudson.cli.client.Messages;
-
-import java.net.URL;
-import java.net.URLConnection;
-import java.net.Socket;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Locale;
-import java.util.ArrayList;
-import java.util.logging.Logger;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.DataOutputStream;
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-
-/**
- * CLI entry point to Hudson.
- *
- * @author Kohsuke Kawaguchi
- */
-public class CLI {
- private final ExecutorService pool;
- private final Channel channel;
- private final CliEntryPoint entryPoint;
- private final boolean ownsPool;
-
- public CLI(URL hudson) throws IOException, InterruptedException {
- this(hudson,null);
- }
-
- public CLI(URL hudson, ExecutorService exec) throws IOException, InterruptedException {
- String url = hudson.toExternalForm();
- if(!url.endsWith("/")) url+='/';
-
- ownsPool = exec==null;
- pool = exec!=null ? exec : Executors.newCachedThreadPool();
-
- int clip = getCliTcpPort(url);
- if(clip>=0) {
- // connect via CLI port
- String host = new URL(url).getHost();
- LOGGER.fine("Trying to connect directly via TCP/IP to port "+clip+" of "+host);
- Socket s = new Socket(host,clip);
- DataOutputStream dos = new DataOutputStream(s.getOutputStream());
- dos.writeUTF("Protocol:CLI-connect");
-
- channel = new Channel("CLI connection to "+hudson, pool,
- new BufferedInputStream(new SocketInputStream(s)),
- new BufferedOutputStream(new SocketOutputStream(s)));
- } else {
- // connect via HTTP
- LOGGER.fine("Trying to connect to "+url+" via HTTP");
- url+="cli";
- hudson = new URL(url);
-
- FullDuplexHttpStream con = new FullDuplexHttpStream(hudson);
- channel = new Channel("Chunked connection to "+hudson,
- pool,con.getInputStream(),con.getOutputStream());
- new PingThread(channel,30*1000) {
- protected void onDead() {
- // noop. the point of ping is to keep the connection alive
- // as most HTTP servers have a rather short read time out
- }
- }.start();
- }
-
- // execute the command
- entryPoint = (CliEntryPoint)channel.waitForRemoteProperty(CliEntryPoint.class.getName());
-
- if(entryPoint.protocolVersion()!=CliEntryPoint.VERSION)
- throw new IOException(Messages.CLI_VersionMismatch());
- }
-
- /**
- * If the server advertises CLI port, returns it.
- */
- private int getCliTcpPort(String url) throws IOException {
- URLConnection head = new URL(url).openConnection();
- try {
- head.connect();
- } catch (IOException e) {
- throw (IOException)new IOException("Failed to connect to "+url).initCause(e);
- }
- String p = head.getHeaderField("X-Hudson-CLI-Port");
- if(p==null) return -1;
- return Integer.parseInt(p);
- }
-
- public void close() throws IOException, InterruptedException {
- channel.close();
- channel.join();
- if(ownsPool)
- pool.shutdown();
- }
-
- public int execute(List<String> args, InputStream stdin, OutputStream stdout, OutputStream stderr) {
- return entryPoint.main(args,Locale.getDefault(),
- new RemoteInputStream(stdin),
- new RemoteOutputStream(stdout),
- new RemoteOutputStream(stderr));
- }
-
- public int execute(List<String> args) {
- return execute(args,System.in,System.out,System.err);
- }
-
- public int execute(String... args) {
- return execute(Arrays.asList(args));
- }
-
- /**
- * Returns true if the named command exists.
- */
- public boolean hasCommand(String name) {
- return entryPoint.hasCommand(name);
- }
-
- public static void main(final String[] _args) throws Exception {
- List<String> args = Arrays.asList(_args);
-
- String url = System.getenv("HUDSON_URL");
-
- while(!args.isEmpty()) {
- String head = args.get(0);
- if(head.equals("-s") && args.size()>=2) {
- url = args.get(1);
- args = args.subList(2,args.size());
- continue;
- }
- break;
- }
-
- if(url==null) {
- printUsageAndExit(Messages.CLI_NoURL());
- return;
- }
-
- if(args.isEmpty())
- args = Arrays.asList("help"); // default to help
-
- CLI cli = new CLI(new URL(url));
- try {
- // execute the command
- // Arrays.asList is not serializable --- see 6835580
- args = new ArrayList<String>(args);
- System.exit(cli.execute(args, System.in, System.out, System.err));
- } finally {
- cli.close();
- }
- }
-
- private static void printUsageAndExit(String msg) {
- if(msg!=null) System.out.println(msg);
- System.err.println(Messages.CLI_Usage());
- System.exit(-1);
- }
-
- private static final Logger LOGGER = Logger.getLogger(CLI.class.getName());
-}
diff --git a/hudson-cli/src/main/java/org/eclipse/hudson/cli/CliEntryPoint.java b/hudson-cli/src/main/java/org/eclipse/hudson/cli/CliEntryPoint.java
deleted file mode 100644
index e9f895a2..00000000
--- a/hudson-cli/src/main/java/org/eclipse/hudson/cli/CliEntryPoint.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*******************************************************************************
- *
- * Copyright (c) 2004-2009, Oracle Corporation
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *
- *
- *
- *
- *******************************************************************************/
-
-package org.eclipse.hudson.cli;
-
-import java.io.OutputStream;
-import java.io.InputStream;
-import java.util.List;
-import java.util.Locale;
-
-/**
- * Remotable interface for CLI entry point on the server side.
- *
- * @author Kohsuke Kawaguchi
- */
-public interface CliEntryPoint {
- /**
- * Just like the static main method.
- *
- * @param locale
- * Locale of this client.
- */
- int main(List<String> args, Locale locale, InputStream stdin, OutputStream stdout, OutputStream stderr);
-
- /**
- * Does the named command exist?
- */
- boolean hasCommand(String name);
-
- /**
- * Returns {@link #VERSION}, so that the client and the server can detect version incompatibility
- * gracefully.
- */
- int protocolVersion();
-
- int VERSION = 1;
-}
diff --git a/hudson-cli/src/main/java/org/eclipse/hudson/cli/FullDuplexHttpStream.java b/hudson-cli/src/main/java/org/eclipse/hudson/cli/FullDuplexHttpStream.java
deleted file mode 100644
index 34230ebd..00000000
--- a/hudson-cli/src/main/java/org/eclipse/hudson/cli/FullDuplexHttpStream.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*******************************************************************************
- *
- * Copyright (c) 2004-2010 Oracle Corporation.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *
- *
- *******************************************************************************/
-
-package org.eclipse.hudson.cli;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.util.UUID;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import org.apache.commons.codec.binary.Base64;
-
-/**
- * Creates a capacity-unlimited bi-directional {@link InputStream}/{@link OutputStream} pair over
- * HTTP, which is a request/response protocol.
- *
- * @author Kohsuke Kawaguchi
- */
-public class FullDuplexHttpStream {
- private final URL target;
-
- private final OutputStream output;
- private final InputStream input;
-
- public InputStream getInputStream() {
- return input;
- }
-
- public OutputStream getOutputStream() {
- return output;
- }
-
- public FullDuplexHttpStream(URL target) throws IOException {
- this.target = target;
-
- String authorization = null;
- if (target.getUserInfo() != null) {
- authorization = new String(Base64.encodeBase64(target.getUserInfo().getBytes()));
- }
-
- CrumbData crumbData = new CrumbData();
-
- UUID uuid = UUID.randomUUID(); // so that the server can correlate those two connections
-
- // server->client
- HttpURLConnection con = (HttpURLConnection) target.openConnection();
- con.setDoOutput(true); // request POST to avoid caching
- con.setRequestMethod("POST");
- con.addRequestProperty("Session", uuid.toString());
- con.addRequestProperty("Side","download");
- if (authorization != null) {
- con.addRequestProperty("Authorization", "Basic " + authorization);
- }
- if(crumbData.isValid) {
- con.addRequestProperty(crumbData.crumbName, crumbData.crumb);
- }
- con.getOutputStream().close();
- input = con.getInputStream();
- // make sure we hit the right URL
- if(con.getHeaderField("Hudson-Duplex")==null)
- throw new IOException(target+" doesn't look like Hudson");
-
- // client->server uses chunked encoded POST for unlimited capacity.
- con = (HttpURLConnection) target.openConnection();
- con.setDoOutput(true); // request POST
- con.setRequestMethod("POST");
- con.setChunkedStreamingMode(0);
- con.setRequestProperty("Content-type","application/octet-stream");
- con.addRequestProperty("Session", uuid.toString());
- con.addRequestProperty("Side","upload");
- if (authorization != null) {
- con.addRequestProperty ("Authorization", "Basic " + authorization);
- }
-
- if(crumbData.isValid) {
- con.addRequestProperty(crumbData.crumbName, crumbData.crumb);
- }
- output = con.getOutputStream();
- }
-
- static final int BLOCK_SIZE = 1024;
- static final Logger LOGGER = Logger.getLogger(FullDuplexHttpStream.class.getName());
-
- private final class CrumbData {
- String crumbName;
- String crumb;
- boolean isValid;
-
- private CrumbData() {
- this.crumbName = "";
- this.crumb = "";
- this.isValid = false;
- getData();
- }
-
- private void getData() {
- try {
- String base = createCrumbUrlBase();
- crumbName = readData(base+"?xpath=/*/crumbRequestField/text()");
- crumb = readData(base+"?xpath=/*/crumb/text()");
- isValid = true;
- LOGGER.fine("Crumb data: "+crumbName+"="+crumb);
- } catch (IOException e) {
- // presumably this Hudson doesn't use crumb
- LOGGER.log(Level.FINE,"Failed to get crumb data",e);
- }
- }
-
- private String createCrumbUrlBase() {
- String url = target.toExternalForm();
- return new StringBuilder(url.substring(0, url.lastIndexOf("/cli"))).append("/crumbIssuer/api/xml/").toString();
- }
-
- private String readData(String dest) throws IOException {
- HttpURLConnection con = (HttpURLConnection) new URL(dest).openConnection();
- try {
- BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
- return reader.readLine();
- }
- finally {
- con.disconnect();
- }
- }
- }
-}

Back to the top