package com.yahoo.dtf.actions.http; import com.yahoo.dtf.actions.Action; import com.yahoo.dtf.exception.DTFException; import com.yahoo.dtf.exception.ParseException; import com.yahoo.dtf.recorder.Event; import com.yahoo.dtf.util.TimeUtil; public abstract class HttpBase extends Action { public static final String HTTP_POST_EVENT = "http.post"; public static final String HTTP_GET_EVENT = "http.get"; public static final String HTTP_PUT_EVENT = "http.put"; public static final String HTTP_DELETE_EVENT = "http.delete"; public static final String HTTP_HEAD_EVENT = "http.head"; // event attribute names public static final String HTTP_EVENT_URI = "uri"; public static final String HTTP_EVENT_DATA = "data"; public static final String HTTP_EVENT_DATA_HASH = "datahash"; public static final String HTTP_EVENT_DATA_SIZE = "datasize"; public static final String HTTP_EVENT_HASH_ALGO = "hashalgo"; public static final String HTTP_EVENT_BODY = "body"; public static final String HTTP_EVENT_BODY_HASH = "bodyhash"; public static final String HTTP_EVENT_BODY_SIZE = "bodysize"; public static final String HTTP_EVENT_STATUS = "status"; public static final String HTTP_EVENT_STATUSMSG = "statusmsg"; public static final String HTTP_EVENT_HEADER_IN = "headerin"; public static final String HTTP_EVENT_HEADER_OUT = "headerout"; public static final String HTTP_EVENT_COOKIE_IN = "cookiein"; public static final String HTTP_EVENT_COOKIE_OUT = "cookieout"; /** * @dtf.attr.name uri * @dtf.attr.desc the uri is the exact hostname, port and path to where the * following http request should be sent. The format looks * like so: http://server:port/path */ private String uri = null; /** * @dtf.attr.name acceptredirects * @dtf.attr.desc this attribute will dictate if the http client should * accept redirects. When set to 'false' if the server requests * an http redirect then the client will fail because it was * set to not follow redirects. * <b>Redirects are only automatically followed for GET and * HEAD methods, the HTTP spec says these are simply * followed while other methods can't just be re-issued * to a subsequent URL.</b> * <br/> * By default the redirects are accepted since most http * servers use this feature to do some form of load balancing * or to recover from temporary service inavailability. */ private String acceptredirects = "false"; /** * @dtf.attr.name perfrun * @dtf.attr.desc the perfrun attribute controls the amount of data that is * recorded about each HTTP request. When set to 'true' the * HTTP request will only log the start and stop timestamp * for the request as well as the status code and message. * <br/><br/> * The data sent and the data received through the body * response is not going to be recorded unless the perfrun * attribute is set to false. * <br/><br/> * <b>Additional attributes recorded when perfrun is set * to true:</b> * <ul> * <li>bodyhash</li> * <li>datahash</li> * </ul> * * Currently the bodyhash and datahash are recorded instead * of the contents of the body or data being used by the * current http request. This performs really well and still * allows the test case writer to validate the data * correctness by comparing hash values. * * Note: you can disable hash calculation all together for * performance testing by using the hash attribute and * setting that to 'none'. */ private String perfrun = "false"; /** * @dtf.attr.name onFailure * @dtf.attr.desc this attribute maybe used to control the behavior of when * operations return an http status code != 200. When set to * 'continue' even if an operation fails the test will continue * to execute and will just log the request has having a * status code != 200. This is useful when running performance * tests or long running tests that may hit timeouts or other * acceptable errors that we later need to triage. * <br/> * When set to 'fail' the http request will throw an exception * if the request returns with an http status code != 200. * This is useful in a scenario where we dont' have a huge * amount of load pointed at the http server being tested and * we know that a failure at this point would just be * unacceptable. */ private String onFailure = "continue"; /** * @dtf.attr connecttimeout * @dtf.attr.desc the connect timeout for this http request. The default is * 5 seconds. The value of this attribute can be any of the * following exampels 5s - 5 seconds, 5m - 5 minutes. etc. */ private String connecttimeout = "5000"; /** * @dtf.attr hash * @dtf.attr.desc specifies the hash algorithm to use, by default sha1. * Can be set to md5, none, etc. * * The hashing algorithm used has a minimal effect on the * amount of operations per second you can do for very small * objects but has some impact on the through put that you * can do per single stream on PUT,POST activities. So be * aware when designing performance tests that disabling * SHA1 may be a needed option when getting official * performance numbers. */ private String hash = null; /** * @dtf.attr bandwidth * @dtf.attr.desc This attribute will limit the bandwidth when sending or * receiving data in the body of the HTTP request or * response. This means the headers will still be streamed * at network speed but the body of the request/response will * only have the bandwidth specified by this attribute. The * bandwidth value can be defined with the follow suffixes: * <table border="1"> * <tr> * <th>Value</th> * <th>Description</th> * </tr> * <tr> * <td>b</td> * <td>bit</td> * </tr> * <tr> * <td>Kb</td> * <td>Kilobit</td> * </tr> * <tr> * <td>Mb</td> * <td>Megabit</td> * </tr> * <tr> * <td>Gb</td> * <td>Gigabit</td> * </tr> * <tr> * <td>B</td> * <td>Byte</td> * </tr> * <tr> * <td>KB</td> * <td>KiloByte</td> * </tr> * <tr> * <td>MB</td> * <td>MegaByte</td> * </tr> * <tr> * <td>GB</td> * <td>GigaByte</td> * </tr> * </table> * */ private String bandwidth = null; private static HttpOp op = null; protected HttpBase() { synchronized(this) { if ( op == null ) { op = new ApacheHttpOp(); op.init(); } } } /** * * @return * @throws DTFException */ public abstract Event executeOp() throws DTFException; @Override final public void execute() throws DTFException { getRecorder().record(executeOp()); } public HttpOp getOp() { return op; } public static void releaseConnections() { if ( op != null ) op.shutdown(); } @Deprecated public String getURI() throws ParseException { return replaceProperties(uri); } public String getUri() throws ParseException { return replaceProperties(uri); } public void setURI(String uri) { this.uri = uri; } public String getPerfrun() throws ParseException { return replaceProperties(perfrun); } public boolean isPerfrun() throws ParseException { return toBoolean("perfrun", perfrun); } public void setPerfrun(String perfrun) { this.perfrun = perfrun; } public boolean getAcceptredirects() throws ParseException { return toBoolean("acceptredirects",acceptredirects); } public void setAcceptredirects(String acceptredirects) { this.acceptredirects = acceptredirects; } public String getOnfailure() throws ParseException { return replaceProperties(onFailure); } public void setOnfailure(String onFailure) { this.onFailure = onFailure; } public boolean continueOnFailure() throws ParseException { return getOnfailure().equals("continue"); } public void setConnectTimeout(String connecttimeout) { this.connecttimeout = connecttimeout; } public Integer getConnecttimeout() throws ParseException { return TimeUtil.parseTimeToInt("connecttimeout", connecttimeout); } public void setHash(String hash) { this.hash = hash; } public String getHash() throws ParseException { return replaceProperties(hash); } public String getBandwidth() throws ParseException { return replaceProperties(bandwidth); } public void setBandwidth(String bandwidth) { this.bandwidth = bandwidth; } }