//
//  ========================================================================
//  Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd.
//  ------------------------------------------------------------------------
//  All rights reserved. This program and the accompanying materials
//  are made available under the terms of the Eclipse Public License v1.0
//  and Apache License v2.0 which accompanies this distribution.
//
//      The Eclipse Public License is available at
//      http://www.eclipse.org/legal/epl-v10.html
//
//      The Apache License v2.0 is available at
//      http://www.opensource.org/licenses/apache2.0.php
//
//  You may elect to redistribute this code under either of these licenses.
//  ========================================================================
//

// JettyTest.java --
//
// Junit test that shows the Jetty SSL bug.
//

package org.eclipse.jetty.server.ssl;

import static org.hamcrest.Matchers.greaterThan;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.URL;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

/**
 *
 */
public class SSLEngineTest
{
    // Useful constants
    private static final String HELLO_WORLD="Hello world. The quick brown fox jumped over the lazy dog. How now brown cow. The rain in spain falls mainly on the plain.\n";
    private static final String JETTY_VERSION= Server.getVersion();
    private static final String PROTOCOL_VERSION="2.0";

    /** The request. */
    private static final String REQUEST0_HEADER="POST /r0 HTTP/1.1\n"+"Host: localhost\n"+"Content-Type: text/xml\n"+"Content-Length: ";
    private static final String REQUEST1_HEADER="POST /r1 HTTP/1.1\n"+"Host: localhost\n"+"Content-Type: text/xml\n"+"Connection: close\n"+"Content-Length: ";
    private static final String REQUEST_CONTENT=
        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"+
        "<requests xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"+
        "        xsi:noNamespaceSchemaLocation=\"commander.xsd\" version=\""+PROTOCOL_VERSION+"\">\n"+
        "</requests>";

    private static final String REQUEST0=REQUEST0_HEADER+REQUEST_CONTENT.getBytes().length+"\n\n"+REQUEST_CONTENT;
    private static final String REQUEST1=REQUEST1_HEADER+REQUEST_CONTENT.getBytes().length+"\n\n"+REQUEST_CONTENT;

    /** The expected response. */
    private static final String RESPONSE0="HTTP/1.1 200 OK\n"+"Content-Length: "+HELLO_WORLD.length()+"\n"+"Server: Jetty("+JETTY_VERSION+")\n"+'\n'+HELLO_WORLD;
    private static final String RESPONSE1="HTTP/1.1 200 OK\n"+"Connection: close\n"+"Server: Jetty("+JETTY_VERSION+")\n"+'\n'+HELLO_WORLD;

    private static final int BODY_SIZE=300;

    private Server server;
    private ServerConnector connector;


    @Before
    public void startServer() throws Exception
    {
        String keystore = MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath();
        SslContextFactory sslContextFactory = new SslContextFactory();
        sslContextFactory.setKeyStorePath(keystore);
        sslContextFactory.setKeyStorePassword("storepwd");
        sslContextFactory.setKeyManagerPassword("keypwd");

        server=new Server();
        HttpConnectionFactory http = new HttpConnectionFactory();
        http.setInputBufferSize(512);
        http.getHttpConfiguration().setRequestHeaderSize(512);
        connector=new ServerConnector(server, sslContextFactory, http);
        connector.setPort(0);
        connector.getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration().setSendDateHeader(false);

        server.addConnector(connector);
    }

    @After
    public void stopServer() throws Exception
    {
        server.stop();
        server.join();
    }

    @Test
    public void testHelloWorld() throws Exception
    {
        server.setHandler(new HelloWorldHandler());
        server.start();

        SSLContext ctx=SSLContext.getInstance("TLS");
        ctx.init(null,SslContextFactory.TRUST_ALL_CERTS,new java.security.SecureRandom());

        int port=connector.getLocalPort();

        Socket client=ctx.getSocketFactory().createSocket("localhost",port);
        OutputStream os=client.getOutputStream();

        String request =
            "GET / HTTP/1.1\r\n"+
            "Host: localhost:"+port+"\r\n"+
            "Connection: close\r\n"+
            "\r\n";

        os.write(request.getBytes());
        os.flush();

        String response = IO.toString(client.getInputStream());

        assertThat(response, Matchers.containsString("200 OK"));
        assertThat(response,Matchers.containsString(HELLO_WORLD));
    }

    @Test
    public void testBigResponse() throws Exception
    {
        server.setHandler(new HelloWorldHandler());
        server.start();

        SSLContext ctx=SSLContext.getInstance("TLS");
        ctx.init(null,SslContextFactory.TRUST_ALL_CERTS,new java.security.SecureRandom());

        int port=connector.getLocalPort();

        Socket client=ctx.getSocketFactory().createSocket("localhost",port);
        OutputStream os=client.getOutputStream();

        String request =
            "GET /?dump=102400 HTTP/1.1\r\n"+
            "Host: localhost:"+port+"\r\n"+
            "Connection: close\r\n"+
            "\r\n";

        os.write(request.getBytes());
        os.flush();

        String response = IO.toString(client.getInputStream());

        assertThat(response.length(),greaterThan(102400));
    }

    @Test
    public void testRequestJettyHttps() throws Exception
    {
        server.setHandler(new HelloWorldHandler());
        server.start();

        final int loops=10;
        final int numConns=20;

        Socket[] client=new Socket[numConns];

        SSLContext ctx=SSLContext.getInstance("TLSv1.2");
        ctx.init(null,SslContextFactory.TRUST_ALL_CERTS,new java.security.SecureRandom());

        int port=connector.getLocalPort();

        try
        {
            for (int l=0;l<loops;l++)
            {
                // System.err.print('.');
                try
                {
                    for (int i=0; i<numConns; ++i)
                    {
                        // System.err.println("write:"+i);
                        client[i]=ctx.getSocketFactory().createSocket("localhost",port);
                        OutputStream os=client[i].getOutputStream();

                        os.write(REQUEST0.getBytes());
                        os.write(REQUEST0.getBytes());
                        os.flush();
                    }

                    for (int i=0; i<numConns; ++i)
                    {
                        // System.err.println("flush:"+i);
                        OutputStream os=client[i].getOutputStream();
                        os.write(REQUEST1.getBytes());
                        os.flush();
                    }

                    for (int i=0; i<numConns; ++i)
                    {
                        // System.err.println("read:"+i);
                        // Read the response.
                        String responses=readResponse(client[i]);
                        // Check the responses
                        assertEquals(String.format("responses loop=%d connection=%d",l,i),RESPONSE0+RESPONSE0+RESPONSE1,responses);
                    }
                }
                finally
                {
                    for (int i=0; i<numConns; ++i)
                    {
                        if (client[i]!=null)
                        {
                            try
                            {
                                assertEquals(-1,client[i].getInputStream().read());
                            }
                            catch(SocketException e)
                            {
                            }
                        }
                    }
                }
            }
        }
        finally
        {
            // System.err.println();
        }
    }

    @Test
    public void testURLConnectionChunkedPost() throws Exception
    {
        StreamHandler handler = new StreamHandler();
        server.setHandler(handler);
        server.start();

        SSLContext context = SSLContext.getInstance("SSL");
        context.init(null,SslContextFactory.TRUST_ALL_CERTS,new java.security.SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());

        URL url = new URL("https://localhost:"+connector.getLocalPort()+"/test");

        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
        if (conn instanceof HttpsURLConnection)
        {
            ((HttpsURLConnection)conn).setHostnameVerifier(new HostnameVerifier()
            {
                @Override
                public boolean verify(String urlHostName, SSLSession session)
                {
                    return true;
                }
            });
        }

        conn.setConnectTimeout(10000);
        conn.setReadTimeout(100000);
        conn.setDoInput(true);
        conn.setDoOutput(true);
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type","text/plain");
        conn.setChunkedStreamingMode(128);
        conn.connect();
        byte[] b = new byte[BODY_SIZE];
        for (int i = 0; i < BODY_SIZE; i++)
        {
            b[i] = 'x';
        }
        OutputStream os = conn.getOutputStream();
        os.write(b);
        os.flush();

        int len = 0;
        InputStream is = conn.getInputStream();
        int bytes=0;
        while ((len = is.read(b)) > -1)
            bytes+=len;
        is.close();

        assertEquals(BODY_SIZE,handler.bytes);
        assertEquals(BODY_SIZE,bytes);
    }

    /**
     * Reads entire response from the client. Close the output.
     *
     * @param client Open client socket.
     * @return The response string.
     * @throws IOException in case of I/O errors
     */
    private static String readResponse(Socket client) throws IOException
    {
        BufferedReader br=null;
        StringBuilder sb=new StringBuilder(1000);

        try
        {
            client.setSoTimeout(5000);
            br=new BufferedReader(new InputStreamReader(client.getInputStream()));

            String line;

            while ((line=br.readLine())!=null)
            {
                sb.append(line);
                sb.append('\n');
            }
        }
        catch(SocketTimeoutException e)
        {
            System.err.println("Test timedout: "+e.toString());
            e.printStackTrace(); // added to see if we can get more info from failures on CI
        }
        finally
        {
            if (br!=null)
            {
                br.close();
            }
        }
        return sb.toString();
    }

    private static class HelloWorldHandler extends AbstractHandler
    {
        @Override
        public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
        {
            // System.err.println("HANDLE "+request.getRequestURI());
            String ssl_id = (String)request.getAttribute("javax.servlet.request.ssl_session_id");
            assertNotNull(ssl_id);
            
            if (request.getParameter("dump")!=null)
            {
                ServletOutputStream out=response.getOutputStream();
                byte[] buf = new byte[Integer.valueOf(request.getParameter("dump"))];
                // System.err.println("DUMP "+buf.length);
                for (int i=0;i<buf.length;i++)
                    buf[i]=(byte)('0'+(i%10));
                out.write(buf);
                out.close();
            }
            else
            {
                PrintWriter out=response.getWriter();
                out.print(HELLO_WORLD);
                out.close();
            }
        }
    }

    private static class StreamHandler extends AbstractHandler
    {
        private int bytes=0;

        public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
        {
            response.setContentType("text/plain");
            response.setBufferSize(128);
            byte[] b = new byte[BODY_SIZE];
            int len = 0;
            InputStream is = request.getInputStream();
            while ((len = is.read(b)) > -1)
            {
                bytes+=len;
            }

            OutputStream os = response.getOutputStream();
            for (int i = 0; i < BODY_SIZE; i++)
            {
                b[i] = 'x';
            }
            os.write(b);
            response.flushBuffer();
        }
    }

}
