// 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;
    }
}
