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

io.blitz.command.Curl Maven / Gradle / Ivy

/*
 * The MIT License
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package io.blitz.command;

import io.blitz.curl.AbstractTest;
import io.blitz.curl.Rush;
import io.blitz.curl.Sprint;
import io.blitz.curl.TestStep;
import io.blitz.curl.config.BasicAuthentication;
import io.blitz.curl.config.Content;
import io.blitz.curl.config.HttpHeader;
import io.blitz.curl.config.Interval;
import io.blitz.curl.config.variable.AlphaVariable;
import io.blitz.curl.config.variable.IVariable;
import io.blitz.curl.config.variable.ListVariable;
import io.blitz.curl.config.variable.NumberVariable;
import io.blitz.curl.config.variable.UdidVariable;
import java.net.HttpCookie;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Creates a curl (rush or sprint) test from a command line 
 * identical to the blitz bar.
 * @author ghermeto
 */
public class Curl {

    public static String RE_DQ = "\"[^\"\\\\\\r\\n]*(?:\\\\.[^\"\\\\\\r\\n]*)*\"";
    public static String RE_SQ = "'[^'\\\\\\r\\n]*(?:\\\\.[^'\\\\\\r\\n]*)*'";
    public static String RE_WS = "\\S+";
    public static String RE_PATTERN = "(?:.*\\s|^)(-p|--pattern)(?:\\s.+)";
    public static String RE_PATTERN_VALUE = "^(\\d+)-(\\d+):(\\d+)$";
    public static String RE_VARIABLE = "^(?:-v|--variable):(\\S+)$";
    public static String RE_VAR_LIST = "^(list)?\\[([^\\]]+)\\]$";
    public static String RE_VAR_ALPHA_1 = "^(a|alpha)$";
    public static String RE_VAR_ALPHA_2 = "^(a|alpha)\\[(\\d+),(\\d+)(,(\\d+))??\\]$";
    public static String RE_VAR_NUMBER_1 = "^(n|number)$";
    public static String RE_VAR_NUMBER_2 = "^(n|number)\\[(-?\\d+),(-?\\d+)(,(\\d+))?\\]$";
    public static String RE_VAR_UDID = "^(u|udid)$";
    

    /**
     * Parse a curl command line and create a sprint or rush instance, 
     * ready to be sent by the Client.
     * @param command the command to be parsed
     * @param username username to be used in the test
     * @param apiKey api key used to authenticate
     * @return a sprint of rush instance ready to run
     */
    public static AbstractTest parse(String username, 
            String apiKey, String command) {
        
        return parse(username, apiKey, null, null, command);
    }
    
    /**
     * Parse a curl command line and create a sprint or rush instance, 
     * ready to be sent by the Client.
     * @param command the command to be parsed
     * @param username username to be used in the test
     * @param apiKey api key used to authenticate
     * @param host host to connect
     * @param port port for the service
     * @return a sprint of rush instance ready to run
     */
    public static AbstractTest parse(String username, 
            String apiKey, String host, Integer port, String command) {
        
        if(command == null || command.length() == 0) {
            throw new IllegalArgumentException("No command line provided");
        }
        
        String quotesAndSpace = RE_DQ + "|" + RE_SQ + "|" + RE_WS;
        Pattern pattern = Pattern.compile(quotesAndSpace);
        Scanner scanner = new Scanner(command);

        // create the correct test instance based on the command
        AbstractTest test;
        if(command.matches(RE_PATTERN)) {
            test = new Rush(username, apiKey, host, port);
        }
        else {
            test = new Sprint(username, apiKey, host, port);
        }
        
        while(scanner.hasNext()) {
            String url = null;
            TestStep step = new TestStep();

            while(scanner.hasNext()) {
                String cmd = scanner.next();
                if(!cmd.startsWith("-")) {
                    url = cmd;
                    break;
                }

                //user-agent
                if(cmd.matches("-A|--user-agent")) {
                    String value = stripQuotes(scanner.findInLine(pattern));
                    step.setUserAgent(value);
                }
                //cookies
                else if(cmd.matches("-b|--cookie")) {
                    try {
                        String value = stripQuotes(scanner.findInLine(pattern));
                        if(step.getCookies() == null) {
                            step.setCookies(new ArrayList());
                        }
                        String[] pair = value.split("=");
                        step.getCookies().add(new HttpCookie(pair[0], pair[1]));
                    } 
                    catch (ArrayIndexOutOfBoundsException e) {
                        String msg = "Invalid cookie. Format: name=value";
                        throw new IllegalArgumentException(msg, e);
                    }
                }
                //input data
                else if(cmd.matches("-d|--data")) {
                    String value = stripQuotes(scanner.findInLine(pattern));
                    if(step.getContent() == null) {
                        step.setContent(new Content(new ArrayList()));
                    }
                    step.getContent().getData().add(value);
                }
                //referer url
                else if(cmd.matches("-e|--referer")) {
                    try {
                        String value = stripQuotes(scanner.findInLine(pattern));
                        step.setReferrer(new URL(value));
                    } catch (MalformedURLException e) {
                        String msg = "Invalid referer URL";
                        throw new IllegalArgumentException(msg, e);
                    }
                }
                //header
                else if(cmd.matches("-H|--header")) {
                    try {
                        String value = stripQuotes(scanner.findInLine(pattern));
                        if(step.getHeaders() == null) {
                            step.setHeaders(new ArrayList());
                        }
                        String[] pair = value.split(":");
                        step.getHeaders().add(new HttpHeader(pair[0], pair[1]));
                    } 
                    catch (ArrayIndexOutOfBoundsException e) {
                        String msg = "Invalid header. Format: name:value";
                        throw new IllegalArgumentException(msg, e);
                    }
                }
                //region
                else if(cmd.matches("-r|--region")) {
                    String value = stripQuotes(scanner.findInLine(pattern));
                    if("".equals(value)) {
                        String msg = "Missing value for region";
                        throw new IllegalArgumentException(msg);
                    }
                    test.setRegion(value);
                }
                //HTTP status code
                else if(cmd.matches("-s|--status")) {
                    try {
                        String value = stripQuotes(scanner.findInLine(pattern));
                        Integer status = Integer.parseInt(value);
                        step.setStatus(status);
                    }
                    catch(NumberFormatException e) {
                        String msg = "Wrong HTTP status code format";
                        throw new IllegalArgumentException(msg, e);
                    }
                }
                //timeout
                else if(cmd.matches("-T|--timeout")) {
                    try {
                        String value = stripQuotes(scanner.findInLine(pattern));
                        Integer timeout = Integer.parseInt(value);
                        step.setTimeout(timeout);
                    }
                    catch(NumberFormatException e) {
                        String msg = "Timeout must be an integer";
                        throw new IllegalArgumentException(msg, e);
                    }
                }
                //user authentication
                else if(cmd.matches("-u|--user")) {
                    try {
                        String value = stripQuotes(scanner.findInLine(pattern));
                        String[] pair = value.split(":");
                        step.setUser(new BasicAuthentication(pair[0], pair[1]));
                    } 
                    catch (ArrayIndexOutOfBoundsException e) {
                        String msg = "Invalid user. Format: username:password";
                        throw new IllegalArgumentException(msg, e);
                    }
                }
                //request method: GET, POST, PUT
                else if(cmd.matches("-X|--request")) {
                    String value = stripQuotes(scanner.findInLine(pattern));
                    step.setRequest(value);
                }
                //pattern
                else if(cmd.matches("-p|--pattern")) {
                    //requires a rush object
                    Rush rush = (Rush) test;
                    String value = stripQuotes(scanner.findInLine(pattern));
                    String[] list = value.split(",");
                    //initialize if needed
                    if(rush.getPattern() == null) {
                        Collection i = new ArrayList();
                        rush.setPattern(new io.blitz.curl.config.Pattern(1, i));
                    }
                    //for each pattern given
                    for(String ptn : list) {
                        try {
                            //if doesn't match a valid pattern
                            if(!ptn.matches(RE_PATTERN_VALUE)) {
                                String msg = "Invalid ramp pattern";
                                throw new IllegalArgumentException(msg);
                            }
                            //gets the regex capture groups
                            Matcher matcher = Pattern.compile(RE_PATTERN_VALUE).matcher(ptn);
                            matcher.matches();
                            Integer start = Integer.parseInt(matcher.group(1));
                            Integer end = Integer.parseInt(matcher.group(2));
                            Integer duration = Integer.parseInt(matcher.group(3));
                            //creates interval
                            Interval interval = new Interval(1, start, end, duration);
                            rush.getPattern().getIntervals().add(interval);
                        }
                        catch(Exception e) {
                            String msg = "Invalid ramp pattern";
                            throw new IllegalArgumentException(msg, e);
                        }
                    }
                }
                //variables
                else if(cmd.matches(RE_VARIABLE)) {
                    String value = stripQuotes(scanner.findInLine(pattern));
                    //gets the variable name
                    Matcher matcher = Pattern.compile(RE_VARIABLE).matcher(cmd);
                    matcher.matches();
                    String vname = matcher.group(1);
                    //validated the name
                    if(!vname.matches("^[a-zA-Z][a-zA-Z0-9]*")) {
                        String msg = "Variable name must be alphanumeric: " + vname;
                        throw new IllegalArgumentException(msg);
                    }
                    //initializes if needed
                    if(step.getVariables() == null) {
                        step.setVariables(new HashMap());
                    }
                    try {
                        IVariable variable;
                        //if variable is a list
                        if(value.matches(RE_VAR_LIST)) {
                            Matcher m = Pattern.compile(RE_VAR_LIST).matcher(value);
                            m.matches();
                            String[] values = m.group(2).split(",");
                            List list = Arrays.asList(values);
                            variable = new ListVariable(list);
                        }
                        //if is just a or alpha
                        else if(value.matches(RE_VAR_ALPHA_1)) {
                            variable = new AlphaVariable();
                        }
                        //if is alpha with min and max values
                        else if(value.matches(RE_VAR_ALPHA_2)) {
                            Matcher m = Pattern.compile(RE_VAR_ALPHA_2).matcher(value);
                            m.matches();
                            Integer min = Integer.parseInt(m.group(2));
                            Integer max = Integer.parseInt(m.group(3));
                            variable = new AlphaVariable(min, max);
                        }
                        //if is just n or number
                        else if(value.matches(RE_VAR_NUMBER_1)) {
                            variable = new NumberVariable();
                        }
                        //if is number with min and max values
                        else if(value.matches(RE_VAR_NUMBER_2)) {
                            Matcher m = Pattern.compile(RE_VAR_NUMBER_2).matcher(value);
                            m.matches();
                            Integer min = Integer.parseInt(m.group(2));
                            Integer max = Integer.parseInt(m.group(3));
                            variable = new NumberVariable(min, max);
                        }
                        //if is just u or uuid
                        else if(value.matches(RE_VAR_UDID)) {
                            variable = new UdidVariable();
                        }
                        //if not pattern was matched
                        else {
                            String msg = "Invalid variable args for " + vname 
                                    + ": " + value;
                            throw new IllegalArgumentException(msg);
                        }
                        // add variable to map
                        step.getVariables().put(vname, variable);
                    }
                    catch(Exception e) {
                        String msg = "Invalid variable args for " + vname 
                                + ": " + value;
                        throw new IllegalArgumentException(msg, e);
                    }
                }
                //ssl
                else if(cmd.matches("-1|--tlsv1")) {
                    step.setSsl("tlsv1");
                }
                //ssl
                else if(cmd.matches("-2|--sslv2")) {
                    step.setSsl("sslv2");
                }
                //ssl
                else if(cmd.matches("-3|--sslv3")) {
                    step.setSsl("sslv3");
                }
                //if the command is unknown
                else {
                    throw new IllegalArgumentException("Unknown option " + cmd);
                }
            }
            // no URL provided
            if(url == null) {
                throw new IllegalArgumentException("No URL specified");
            }
            try {
                step.setUrl(new URL(url));
                if(test.getSteps() == null) {
                    test.setSteps(new ArrayList());
                }
                test.getSteps().add(step);
            } catch (MalformedURLException e) {
                throw new IllegalArgumentException("Malformed URL", e);
            }
        }
        return test;
    }
    
    /**
     * Removed the quotes from around the string
     * @param quoted quoted string
     * @return string without quotes surrounding it
     */
    protected static String stripQuotes(String quoted) {
        if(quoted == null) {
            return "";
        }
        else if(quoted.startsWith("'") || quoted.startsWith("\"")) {
            return quoted.substring(1, quoted.length()-1);
        }
        return quoted;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy