package org.curriki.tools.loadtest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.*;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.params.CookiePolicy;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.impl.cookie.BasicClientCookie2;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
/**
*/
public class XWikiHttpClient extends DefaultHttpClient {
private static Log LOG = LogFactory.getLog(XWikiHttpClient.class);
public XWikiHttpClient(String baseURL, String userName, String userPassword) throws IOException {
super(new ThreadSafeClientConnManager());
this.baseURL = new URL(baseURL);
this.userName = userName; this.userPassword = userPassword;
this.host = new HttpHost(this.baseURL.getHost(), this.baseURL.getPort(), this.baseURL.getProtocol());
this.localcontext = new BasicHttpContext();
((ThreadSafeClientConnManager) super.getConnectionManager()).setDefaultMaxPerRoute(100);
super.getParams().setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.BROWSER_COMPATIBILITY);
super.setCookieStore(new BasicCookieStore());
super.getParams().setParameter(ClientPNames.HANDLE_REDIRECTS, Boolean.FALSE);
}
final URL baseURL;
final String userName, userPassword;
final HttpHost host;
final HttpContext localcontext;
public HttpResponse executeWithRelogin(HttpRequest request) throws HttpException, IOException {
HttpResponse response = super.execute(host, request, localcontext);
int sc = response.getStatusLine().getStatusCode();
Header locationHeader = response.getFirstHeader("Location");
String loc = null; if(locationHeader!=null) loc = locationHeader.getValue();
if((sc==301 || sc ==302 || sc==303) && loc!=null && loc.contains("Login")) {
tryLogin();
response = super.execute(host, request, localcontext);
}
return response;
}
public HttpResponse tryLogin() throws IOException {
StatusLine status = null;
HttpResponse response = null;
try {
String loginURL = new URL(baseURL,"/xwiki/bin/loginsubmit/XWiki/XWikiLogin?xredirect=%2Fxwiki%2Fbin%2Fview%2FSearch2%2FUserName%3Fxpage%3Dplain&xpage=plain").toExternalForm();
LOG.info("--- Logging in (" + loginURL + ").");
HttpPost loginPost = new HttpPost(loginURL);
List<NameValuePair> formparams = new ArrayList<NameValuePair>();
formparams.add(new BasicNameValuePair("j_username", "solr"));
formparams.add(new BasicNameValuePair("j_password", "currikiSearchFast"));
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams, "UTF-8");
loginPost.setEntity(entity);
response = super.execute(host, loginPost, localcontext);
status = response.getStatusLine();
if(status.getStatusCode()/100==3) { // consume the redirect
response = super.execute(host, new HttpGet(response.getHeaders("Location")[0].getValue()),localcontext);
status = response.getStatusLine();
}
} catch (IOException e) {
LOG.warn(e);
throw new IllegalStateException("Can't loging. Giving up.");
}
if(status.getStatusCode() / 100 == 3 || status.getStatusCode() / 100 == 2) {
verifyLoggedInUserName();
LOG.debug("Successful Login.");
} else {
LOG.info("Failed login: " + status);
throw new IllegalStateException("Can't login to XWiki with user \"" + userName + "\".");
}
return response;
}
public String verifyLoggedInUserName() throws IOException {
String u= new URL(baseURL,"/xwiki/bin/view/Search2/UserName?xpage=plain").toExternalForm();
HttpResponse response = super.execute(host, new HttpGet(u), localcontext);
StatusLine status = response.getStatusLine();
if(status.getStatusCode()!=200) return status.toString();
String userName = responseAscii(response);
LOG.info("--- Obtained userName \"" + userName + "\".");
if("XWiki.XWikiGuest".equals(userName.trim())) { // login and redo it
tryLogin();
response = super.execute(host, new HttpGet(u), localcontext);
status = response.getStatusLine();
userName = responseAscii(response);
}
if(status.getStatusCode()!=200) return status.toString();
long l = response.getEntity().getContentLength();
if(userName!=null && userName.length()==0) {
return "<empty>" + l;
}
else return userName;
}
public static String responseAscii(HttpResponse response) throws IOException {
StringBuilder buff = new StringBuilder(20);
InputStream in = response.getEntity().getContent();
int r=0;
while((r=in.read())!=-1) buff.append((char) r);
return buff.toString();
}
private Cookie getJSessionIdCookie(boolean remove) {
Iterator<Cookie> itC = super.getCookieStore().getCookies().iterator();
while(itC.hasNext()) {
Cookie cookie = itC.next();
if("JSESSIONID".equals(cookie.getName())) {
if(remove) itC.remove();
return cookie;
}
}
return null;
}
public String getClusterNodeOfSession() {
String value = getJSessionIdCookie(false).getValue();
if(!value.contains(".")) throw new IllegalStateException(
"JSESSIONID cookie does not contain a period (it is \"" + value + "\").");
value = value.substring(value.indexOf('.')+1);
return value;
}
public String changeClusterNode(String node1, String node2) {
node1 = "." + node1; node2 = "." + node2;
String returnValue = null;
Cookie cookie = getJSessionIdCookie(true);
String value = cookie.getValue();
LOG.info("---- cookie is " + value);
int p = value.indexOf('.');
if(value.endsWith(node1)) {
LOG.info("-- Changing cookie to " + node2 + ".");
returnValue = node2;
BasicClientCookie2 stdCookie = new BasicClientCookie2("JSESSIONID", value.substring(0, p)+node2);
stdCookie.setVersion(1);
stdCookie.setDomain(baseURL.getPath());
stdCookie.setPorts(new int[] {baseURL.getPort()});
stdCookie.setPath("/");
stdCookie.setSecure(true);
super.getCookieStore().addCookie(stdCookie);
} else if (value.endsWith(node2)) {
LOG.info("---- No need to change cookie.");
/* LOG.info("-- Changing cookie to " + node1 + ".");
returnValue = node1;
BasicClientCookie2 stdCookie = new BasicClientCookie2("JSESSIONID", value.substring(0, p)+node1);
stdCookie.setVersion(1);
stdCookie.setDomain(url.getPath());
stdCookie.setPorts(new int[] {url.getPort()});
stdCookie.setPath("/");
stdCookie.setSecure(true);
super.getCookieStore().addCookie(stdCookie); */
} else throw new IllegalStateException("Cookie JSESSIONID=\"" + value + "\" is not one of the node-routes.");
return returnValue;
}
public HttpResponse postForm(String url, String... keyVals) throws HttpException, IOException {
HttpPost post = new HttpPost(url);
List<NameValuePair> params = new LinkedList<NameValuePair>();
for(String kv: keyVals) {
int p = kv.indexOf(':');
params.add(new BasicNameValuePair(kv.substring(0,p), kv.substring(p+1)));
}
post.setEntity(new UrlEncodedFormEntity(params));
return this.executeWithRelogin(post);
}
public HttpResponse getPage(String url) throws IOException {
url = new URL(baseURL, url).toExternalForm();
HttpResponse response = super.execute(new HttpGet(url));
int count = 0;
while(response.getStatusLine().getStatusCode()==302) {
String location = response.getHeaders("Location")[0].getValue();
if(location.contains("/xwiki/bin/login") && count++<5) {
LOG.info("Redirected to " + response.getHeaders("Location")[0].getValue());
try {Thread.currentThread().sleep(1000);} catch(InterruptedException x) {}
this.tryLogin();
response = super.execute(new HttpGet(url));
} else break;
}
return response;
}
public String toString() {
return "XWikiHttpClient@" + hashCode() + " [" + baseURL + "]";
}
}