/**
* Copyright 2011 Intuit Inc. All Rights Reserved
*/
package com.intuit.tank.script.util;
/*
* #%L
* Script Processor
* %%
* Copyright (C) 2011 - 2015 Intuit Inc.
* %%
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
* #L%
*/
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import com.intuit.tank.conversation.Cookie;
import com.intuit.tank.conversation.Header;
import com.intuit.tank.conversation.Transaction;
import com.intuit.tank.project.RequestData;
import com.intuit.tank.project.ScriptStep;
import com.intuit.tank.script.RequestDataType;
import com.intuit.tank.script.ScriptConstants;
import com.intuit.tank.util.HeaderParser;
import com.intuit.tank.util.KeyValuePair;
import com.intuit.tank.util.WebConversationJaxbParseXML;
import com.intuit.tank.util.HeaderParser.HeaderType;
import com.intuit.tank.vm.exception.WatsParseException;
/**
* @author dangleton patterns: Util
*/
public class OwaspReader implements RecordedScriptReader {
private static final Logger LOG = LogManager.getLogger(OwaspReader.class);
/**
* private constructor to implement the Util Pattern
*/
public OwaspReader() {
// empty constructor
}
/**
* @{inheritDoc
*/
@Override
public List<ScriptStep> read(String xml) throws WatsParseException {
return read(new StringReader(xml));
}
/**
* @{inheritDoc
*/
@Override
public List<ScriptStep> read(Reader reader) throws WatsParseException {
return transactionsToRequest(new WebConversationJaxbParseXML()
.parse(reader));
}
public List<ScriptStep> transactionsToRequest(
Collection<Transaction> entries) {
List<ScriptStep> result = new ArrayList<ScriptStep>();
int index = 0;
for (Transaction transaction : entries) {
index++;
result.add(transactionToResult(transaction, index));
}
return result;
}
/**
* @param entry
* @return
* @throws MalformedURLException
*/
private ScriptStep transactionToResult(Transaction fromXml, int currentIndex) {
try {
HeaderParser requestParser = new HeaderParser(HeaderType.Request,
fromXml.getRequest().getFirstLine(), fromXml.getRequest()
.getHeaders());
HeaderParser responseParser = new HeaderParser(HeaderType.Response,
fromXml.getResponse().getFirstLine(), fromXml.getResponse()
.getHeaders());
ScriptStep entry = new ScriptStep();
entry.setStepIndex(currentIndex);
entry.setType(ScriptConstants.REQUEST);
// String url = fromXml.getUrl();
entry.setUrl(requestParser.getUrl(fromXml.getRequest()
.getProtocol()));
try {
entry.setHostname(requestParser.getHost());
entry.setProtocol(fromXml.getRequest().getProtocol().name());
entry.setSimplePath(requestParser.getPath());
} catch (Exception e) {
LOG.error(
"url is not valid: ignoring host, protocol, and path",
e);
}
String mimeType = responseParser.getContentType();
entry.setMethod(requestParser.getMethod());
entry.setMimetype(mimeType);
entry.setResult(responseParser.getStatusMessage());
entry.setRequestheaders(populateHeaders(
requestParser.getPassThroughHeaders(),
RequestDataType.requestHeader.name()));
entry.setReqFormat(findRequestFormat(requestParser.getContentType()));
entry.setRespFormat(findResponseFormat(responseParser
.getContentType()));
entry.setResponseheaders(populateHeaders(
responseParser.getPassThroughHeaders(),
RequestDataType.responseHeader.name()));
entry.setRequestCookies(populateCookies(requestParser.getCookies(),
RequestDataType.requestCookie.name()));
entry.setResponseCookies(populateCookies(
responseParser.getCookies(),
RequestDataType.responseCookie.name()));
String bodyAsString = fromXml.getRequest().getBodyAsString();
// entry.setPayload(bodyAsString);
if (!StringUtils.isEmpty(bodyAsString)) {
if (ScriptConstants.JSON_TYPE.equalsIgnoreCase(entry.getReqFormat())
|| ScriptConstants.XML_TYPE.equalsIgnoreCase(entry.getReqFormat())
|| ScriptConstants.PLAIN_TEXT_TYPE.equalsIgnoreCase(entry.getReqFormat())) {
entry.setPayload(bodyAsString);
} else if (ScriptConstants.MULTI_PART_TYPE.equalsIgnoreCase(entry.getReqFormat())) {
entry.setPayload(new String(Base64.encodeBase64(fromXml.getRequest().getBody())));
} else {
entry.setPostDatas(formDataToSet(requestParser
.getPostParameters(bodyAsString),
RequestDataType.requestPostData.name()));
}
}
entry.setResponse(fromXml.getResponse().getBodyAsString());
entry.setQueryStrings(formDataToSet(requestParser.getQueryParams(),
RequestDataType.queryString.name()));
return entry;
} catch (Exception e) {
LOG.error("Error processing script at step "
+ currentIndex + ": " + e.toString(), e);
if (e instanceof RuntimeException) {
String err = e.getCause() != null ? e.getCause().toString() : e
.toString();
throw new RuntimeException("Error processing script at step "
+ currentIndex + ": " + err);
}
throw new RuntimeException("Error processing script at step "
+ currentIndex + ": " + e.toString());
}
}
/**
* @param headers
* @return
*/
private String findRequestFormat(String contentType) {
String ret = ScriptConstants.NVP_TYPE;
if (!StringUtils.isBlank(contentType)) {
if (contentType.toLowerCase().contains(ScriptConstants.JSON_TYPE)) {
ret = ScriptConstants.JSON_TYPE;
} else if (contentType.toLowerCase().contains(
ScriptConstants.XML_TYPE)) {
ret = ScriptConstants.XML_TYPE;
} else if (contentType.toLowerCase().contains(
ScriptConstants.PLAIN_TEXT_TYPE)) {
ret = ScriptConstants.PLAIN_TEXT_TYPE;
} else if (contentType.toLowerCase().contains(ScriptConstants.MULTI_PART_TYPE)) {
ret = ScriptConstants.MULTI_PART_TYPE;
}
}
return ret;
}
/**
* @param headers
* @return
*/
private String findResponseFormat(String contentType) {
String ret = ScriptConstants.NVP_TYPE;
if (!StringUtils.isEmpty(contentType)) {
if (contentType.toLowerCase().contains(ScriptConstants.JSON_TYPE)) {
ret = ScriptConstants.JSON_TYPE;
} else if (contentType.toLowerCase().contains(
ScriptConstants.XML_TYPE)) {
ret = ScriptConstants.XML_TYPE;
} else if (contentType.toLowerCase().contains(
ScriptConstants.PLAIN_TEXT_TYPE)) {
ret = ScriptConstants.PLAIN_TEXT_TYPE;
}
}
return ret;
}
private Set<RequestData> populateCookies(List<Cookie> list, String type) {
Set<RequestData> cs = new HashSet<RequestData>();
if (list != null) {
for (Cookie c : list) {
RequestData cookie = new RequestData();
cookie.setType(type);
cookie.setKey(c.getKey());
cookie.setValue(c.getValue());
cs.add(cookie);
}
}
return cs;
}
private Set<RequestData> populateHeaders(List<Header> headers, String type) {
Set<RequestData> list = new HashSet<RequestData>();
for (Header h : headers) {
list.add(new RequestData(h.getKey(), h.getValue(), type));
}
return list;
}
/**
* @param param
* @param string
* @return
*/
private Set<RequestData> formDataToSet(List<KeyValuePair> params,
String type) {
Set<RequestData> map = new HashSet<RequestData>();
if (params != null) {
for (KeyValuePair param : params) {
String name = param.getKey();
String value = param.getValue();
if (value != null) {
try {
value = URLDecoder.decode(value, ScriptConstants.UTF);
} catch (UnsupportedEncodingException e) {
// never happens since utf-8 is universally supported
}
value = value.replaceAll("[\\r\\n]", "").replaceAll(
">\\s+<", "><");
}
RequestData data = new RequestData();
data.setKey(name);
data.setValue(value);
data.setType(type);
map.add(data);
}
}
return map;
}
/**
* @param rawdata
* @return
* @throws JSONException
*/
public static Set<RequestData> rawJsonToSet(String response)
throws JSONException {
Set<RequestData> map = new LinkedHashSet<RequestData>();
JSONObject jsonObject = new JSONObject(response);
String[] names = JSONObject.getNames(jsonObject);
List<RequestData> itemList = new ArrayList<RequestData>();
for (String name : names) {
traverse(name, jsonObject, itemList, new RequestDataBuilder(
RequestDataType.requestPostData.name()));
}
map.addAll(itemList);
return map;
}
private static void traverse(String name, JSONObject jsonObject,
List<RequestData> itemList, RequestDataBuilder dataItem) {
try {
Object childObject = jsonObject.get(name);
if (childObject instanceof JSONArray) {
JSONArray jsonArray = (JSONArray) childObject;
dataItem.addPathElement(name);
for (int i = 0; i < jsonArray.length(); i++) {
Object child = jsonArray.get(i);
RequestDataBuilder copy = dataItem.copy();
copy.addPathElement("[" + i + "]");
if (child instanceof JSONObject) {
JSONObject childJson = (JSONObject) child;
String[] names = JSONObject.getNames(childJson);
for (String childName : names) {
traverse(childName, childJson, itemList, copy);
}
}
}
} else if (childObject instanceof JSONObject) {
JSONObject childJson = (JSONObject) childObject;
String[] names = JSONObject.getNames(childJson);
dataItem.addPathElement(name);
if (names != null) {
for (String childName : names) {
traverse(childName, childJson, itemList, dataItem.copy());
}
}
} else {
RequestData item = dataItem.build(name,
jsonObject.getString(name));
itemList.add(item);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}