// Copyright 2012 Citrix Systems, Inc. Licensed under the
// Apache License, Version 2.0 (the "License"); you may not use this
// file except in compliance with the License. Citrix Systems, Inc.
// reserves all rights not expressly granted by the License.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Automatically generated by addcopyright.py at 04/03/2012
package com.cloud.consoleproxy.util;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
//
// This file is originally from XenConsole with modifications
//
/**
* Send an HTTP CONNECT or PUT request to a XenAPI host with a Session ID,
* return the connected socket and the Task ID. Used for tunnelling VNC
* connections and import/export operations.
*/
public final class RawHTTP {
private static final Logger s_logger = Logger.getLogger(RawHTTP.class);
private static final Pattern END_PATTERN = Pattern.compile("^\r\n$");
private static final Pattern HEADER_PATTERN = Pattern
.compile("^([A-Z_a-z0-9-]+):\\s*(.*)\r\n$");
private static final Pattern HTTP_PATTERN = Pattern
.compile("^HTTP/\\d+\\.\\d+ (\\d*) (.*)\r\n$");
/**
* @uml.property name="command"
*/
private final String command;
/**
* @uml.property name="host"
*/
private final String host;
/**
* @uml.property name="port"
*/
private final int port;
/**
* @uml.property name="path"
*/
private final String path;
/**
* @uml.property name="session"
*/
private final String session;
/**
* @uml.property name="useSSL"
*/
private final boolean useSSL;
/**
* @uml.property name="responseHeaders"
* @uml.associationEnd qualifier="group:java.lang.String java.lang.String"
*/
private final Map<String, String> responseHeaders = new HashMap<String, String>();
/**
* @uml.property name="ic"
*/
private InputStream ic;
/**
* @uml.property name="oc"
*/
private OutputStream oc;
/**
* @uml.property name="s"
*/
private Socket s;
public InputStream getInputStream() {
return ic;
}
public OutputStream getOutputStream() {
return oc;
}
public Socket getSocket() {
return s;
}
public RawHTTP(String command, String host, int port, String path,
String session, boolean useSSL) {
this.command = command;
this.host = host;
this.port = port;
this.path = path;
this.session = session;
this.useSSL = useSSL;
}
private static final TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};
private Socket _getSocket() throws IOException {
if (useSSL) {
SSLContext context = getClientSSLContext();
if(context == null)
throw new IOException("Unable to setup SSL context");
SSLSocket ssl = null;
try {
context.init(null, trustAllCerts, new SecureRandom());
SocketFactory factory = context.getSocketFactory();
ssl = (SSLSocket) factory.createSocket(host, port);
/* ssl.setSSLParameters(context.getDefaultSSLParameters()); */
} catch (IOException e) {
s_logger.error("IOException: " + e.getMessage(), e);
throw e;
} catch (KeyManagementException e) {
s_logger.error("KeyManagementException: " + e.getMessage(), e);
}
return ssl;
} else {
return new Socket(host, port);
}
}
public Socket connect() throws IOException {
String[] headers = makeHeaders();
s = _getSocket();
try {
oc = s.getOutputStream();
for (String header : headers) {
oc.write(header.getBytes());
oc.write("\r\n".getBytes());
}
oc.flush();
ic = s.getInputStream();
while (true) {
String line = readline(ic);
Matcher m = END_PATTERN.matcher(line);
if (m.matches()) {
return s;
}
m = HEADER_PATTERN.matcher(line);
if (m.matches()) {
responseHeaders.put(m.group(1), m.group(2));
continue;
}
m = HTTP_PATTERN.matcher(line);
if (m.matches()) {
String status_code = m.group(1);
String reason_phrase = m.group(2);
if (!"200".equals(status_code)) {
throw new IOException("HTTP status " + status_code
+ " " + reason_phrase);
}
} else {
throw new IOException("Unknown HTTP line " + line);
}
}
} catch (IOException exn) {
s.close();
throw exn;
} catch (RuntimeException exn) {
s.close();
throw exn;
}
}
public Map<String, String> getResponseHeaders() {
return responseHeaders;
}
private String[] makeHeaders() {
String[] headers = { String.format("%s %s HTTP/1.0", command, path),
String.format("Host: %s", host),
String.format("Cookie: session_id=%s", session), "" };
return headers;
}
private static String readline(InputStream ic) throws IOException {
String result = "";
while (true) {
try {
int c = ic.read();
if (c == -1) {
return result;
}
result = result + (char) c;
if (c == 0x0a /* LF */) {
return result;
}
} catch (IOException e) {
ic.close();
throw e;
}
}
}
private SSLContext getClientSSLContext() {
SSLContext sslContext = null;
try {
sslContext = SSLContext.getInstance("SSL", "SunJSSE");
} catch (NoSuchAlgorithmException e) {
s_logger.error("Unexpected exception ", e);
} catch (NoSuchProviderException e) {
s_logger.error("Unexpected exception ", e);
}
return sslContext;
}
}