All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.thoughtworks.selenium.HttpCommandProcessor Maven / Gradle / Ivy

/*
 * Copyright 2006 ThoughtWorks, Inc.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with 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.
 *
 */

package com.thoughtworks.selenium;

import com.google.common.collect.Lists;
import org.openqa.selenium.net.Urls;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.ConnectException;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Arrays;
import java.util.List;

/**
 * Sends commands and retrieves results via HTTP.
 * @author Ben Griffiths, Jez Humble
 */
public class HttpCommandProcessor implements CommandProcessor {

    private String pathToServlet;
    private String browserStartCommand;
    private String browserURL;
    private String sessionId;
    private String extensionJs;
    private String rcServerLocation;

    /** Specifies a server host/port, a command to launch the browser, and a starting URL for the browser.
     * 
     * @param serverHost - the host name on which the Selenium Server resides
     * @param serverPort - the port on which the Selenium Server is listening
     * @param browserStartCommand - the command string used to launch the browser, e.g. "*firefox" or "c:\\program files\\internet explorer\\iexplore.exe"
     * @param browserURL - the starting URL including just a domain name.  We'll start the browser pointing at the Selenium resources on this URL,
     * @param extensionJs - extension Javascript for this session
     * e.g. "http://www.google.com" would send the browser to "http://www.google.com/selenium-server/core/RemoteRunner.html"
     */
    public HttpCommandProcessor(String serverHost, int serverPort, String browserStartCommand, String browserURL) {
        rcServerLocation = serverHost +
        ":"+ Integer.toString(serverPort);
        this.pathToServlet = "http://" + rcServerLocation + "/selenium-server/driver/";
        this.browserStartCommand = browserStartCommand;
        this.browserURL = browserURL;
        this.extensionJs = "";
    }
    
    /** Specifies the URL to the CommandBridge servlet, a command to launch the browser, and a starting URL for the browser.
     * 
     * @param pathToServlet - the URL of the Selenium Server Driver, e.g. "http://localhost:4444/selenium-server/driver/" (don't forget the final slash!)
     * @param browserStartCommand - the command string used to launch the browser, e.g. "*firefox" or "c:\\program files\\internet explorer\\iexplore.exe"
     * @param browserURL - the starting URL including just a domain name.  We'll start the browser pointing at the Selenium resources on this URL,
     * @param extensionJs - extension Javascript for this session
     */
    public HttpCommandProcessor(String pathToServlet, String browserStartCommand, String browserURL) {
        this.pathToServlet = pathToServlet;
        this.browserStartCommand = browserStartCommand;
        this.browserURL = browserURL;
        this.extensionJs = "";
    }

    public String getRemoteControlServerLocation() {
        return rcServerLocation;
    }

    public String doCommand(String commandName, String[] args) {
        DefaultRemoteCommand command = new DefaultRemoteCommand(commandName,args);
        String result = executeCommandOnServlet(command.getCommandURLString());
        if (result == null) {
            throw new NullPointerException("Selenium Bug! result must not be null");
        }
        if (!result.startsWith("OK")) {
            return throwAssertionFailureExceptionOrError(result);
        }
        return result;
    }

    protected String throwAssertionFailureExceptionOrError(String message) {
        throw new SeleniumException(message);
    }

    /** Sends the specified command string to the bridge servlet */  
    public String executeCommandOnServlet(String command) {
        InputStream is = null;
        try {
            return getCommandResponseAsString(command);
        } catch (IOException e) {
            if (e instanceof ConnectException) {
                throw new SeleniumException(e.getMessage(),e);
            }
            e.printStackTrace();
            throw new UnsupportedOperationException("Catch body broken: IOException from " + command + " -> " + e, e);
        }
    }

    private String stringContentsOfInputStream(Reader rdr) throws IOException {
        StringBuffer sb = new StringBuffer();
        int c;
        try {
          while ((c = rdr.read()) != -1) {
              sb.append((char) c);
          }
          return sb.toString();
        } finally {
          rdr.close();
        }
    }
    
    // for testing
    protected HttpURLConnection getHttpUrlConnection(URL urlForServlet) throws IOException {
      return (HttpURLConnection) urlForServlet.openConnection();
    }
    
    // for testing
    protected Writer getOutputStreamWriter(HttpURLConnection conn) throws IOException {
      return new BufferedWriter(new OutputStreamWriter(conn.getOutputStream())); 
    }
    
    // for testing
    protected Reader getInputStreamReader(HttpURLConnection conn) throws IOException {
      return new InputStreamReader(conn.getInputStream(), "UTF-8");
    }
    
    // for testing
    protected int getResponseCode(HttpURLConnection conn) throws IOException {
      return conn.getResponseCode();
    }

    protected String getCommandResponseAsString(String command) throws IOException {
        String responseString = null;
        int responsecode = HttpURLConnection.HTTP_MOVED_PERM;
        HttpURLConnection uc = null;
        Writer wr = null;
        Reader rdr = null;
        while (responsecode == HttpURLConnection.HTTP_MOVED_PERM) {
            URL result = new URL(pathToServlet); 
            String body = buildCommandBody(command);
            try {
                uc = getHttpUrlConnection(result);
                uc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
                uc.setInstanceFollowRedirects(false);
                uc.setDoOutput(true);
                wr = getOutputStreamWriter(uc);;
                wr.write(body);
                wr.flush();
                responsecode = getResponseCode(uc);
                if (responsecode == HttpURLConnection.HTTP_MOVED_PERM) {
                    pathToServlet = uc.getRequestProperty("Location");
                } else if (responsecode != HttpURLConnection.HTTP_OK) {
                    throwAssertionFailureExceptionOrError(uc.getResponseMessage());
                } else {
                    rdr = getInputStreamReader(uc);
                    responseString = stringContentsOfInputStream(rdr);
                }
            } finally {
              closeResources(uc, wr, rdr);
            }
        }
        return responseString;
    }
    
    protected void closeResources(HttpURLConnection conn, Writer wr, Reader rdr) {
      try {
        if (null != wr) {
          wr.close();
        }
      } catch (IOException ioe) {
        // ignore
      }
      
      try {
        if (null != rdr) {
          rdr.close();
        }
      } catch (IOException ioe) {
        // ignore
      }
      
      if (null != conn) {
        conn.disconnect();
      }
    }

    private String buildCommandBody(String command) {
        StringBuffer sb = new StringBuffer();
        sb.append(command);
        if (sessionId != null) {
            sb.append("&sessionId=");
          sb.append(Urls.urlEncode(sessionId));
        }
        return sb.toString();
    }

    /**
     * This should be invoked before start().
     *
     * @param extensionJs  the extra extension Javascript to include in this
     *                     browser session.
     */
    public void setExtensionJs(String extensionJs) {
        this.extensionJs = extensionJs;
    }
    
    public void start() {
        String result = getString("getNewBrowserSession",
            new String[]{browserStartCommand, browserURL, extensionJs});
        setSessionInProgress(result);
    }
    
    public void start(String optionsString) {
        String result = getString("getNewBrowserSession",
            new String[]{browserStartCommand, browserURL, 
                 extensionJs, optionsString});
        setSessionInProgress(result);
    }
    
    /**
     * Wraps the version of start() that takes a String parameter, sending it
     * the result of calling toString() on optionsObject, which will likely be
     * a BrowserConfigurationOptions instance.
     * 
     * @param optionsObject
     */
    public void start(Object optionsObject) {
        start(optionsObject.toString());
    }

    protected void setSessionInProgress(String result) {
        sessionId = result;
    }

    public void stop() {
        if (hasSessionInProgress()) {
          doCommand("testComplete", null);
        }
        setSessionInProgress(null);
    }

    public boolean hasSessionInProgress() {
        return null != sessionId;
    }

    public String getString(String commandName, String[] args) {
        String result = doCommand(commandName, args);
        if (result.length() >= "OK,".length()) {
            return result.substring("OK,".length());
        }
        System.err.println("WARNING: getString(" + commandName + ") saw a bad result " + result);
        return "";
    }

    public String[] getStringArray(String commandName, String[] args) {
        String result = getString(commandName, args);
        return parseCSV(result);
    }

    /** Convert backslash-escaped comma-delimited string into String array.  As described in SRC-CDP
     * spec section 5.2.1.2, these strings are comma-delimited, but commas
     * can be escaped with a backslash "\".  Backslashes can also be escaped
     * as a double-backslash. 
     * @param input the unparsed string, e.g. "veni\, vidi\, vici,c:\\foo\\bar,c:\\I came\, I \\saw\\\, I conquered" 
     * @return the string array resulting from parsing this string
     */
    public static String[] parseCSV(String input) {
        List output = Lists.newArrayList();
        StringBuffer sb = new StringBuffer();
        for(int i = 0; i < input.length(); i++) {
            char c = input.charAt(i);
            switch (c) {
                case ',':
                    output.add(sb.toString());
                    sb = new StringBuffer();
                    continue;
                case '\\':
                    i++;
                    c = input.charAt(i);
                    // fall through to:
                default:
                    sb.append(c);
            }  
        }
        output.add(sb.toString());
        return output.toArray(new String[output.size()]);
    }
    
    public Number getNumber(String commandName, String[] args) {
        String result = getString(commandName, args);
        Number n;
        try {
            n = NumberFormat.getInstance().parse(result);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
        if (n instanceof Long) {
            // SRC-315 we should return Integers if possible
            if (n.intValue() == n.longValue()) {
                return new Integer(n.intValue());
            }
        }
        return n;
    }

    public Number[] getNumberArray(String commandName, String[] args) {
        String[] result = getStringArray(commandName, args);
        Number[] n = new Number[result.length];
        for (int i = 0; i < result.length; i++) {
            try {
                n[i] = NumberFormat.getInstance().parse(result[i]);
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }
        }
        return n;
    }

    public boolean getBoolean(String commandName, String[] args) {
        String result = getString(commandName, args);
        boolean b;
        if ("true".equals(result)) {
            b = true;
            return b;
        }
        if ("false".equals(result)) {
            b = false;
            return b;
        }
        throw new RuntimeException("result was neither 'true' nor 'false': " + result);
    }

    public boolean[] getBooleanArray(String commandName, String[] args) {
        String[] result = getStringArray(commandName, args);
        boolean[] b = new boolean[result.length];
        for (int i = 0; i < result.length; i++) {
            if ("true".equals(result[i])) {
                b[i] = true;
                continue;
            }
            if ("false".equals(result[i])) {
                b[i] = false;
                continue;
            }
            throw new RuntimeException("result was neither 'true' nor 'false': " + Arrays.toString(result));
        }
        return b;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy