hudson.cli.FullDuplexHttpStream Maven / Gradle / Ivy
/*******************************************************************************
*
* 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 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();
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy