use swanling::prelude::*;
use rand::Rng;
use regex::Regex;
fn main() -> Result<(), SwanlingError> {
SwanlingAttack::initialize()?
.register_taskset(
taskset!("AnonBrowsingUser")
.set_weight(4)?
.register_task(
task!(drupal_loadtest_front_page)
.set_weight(15)?
.set_name("(Anon) front page"),
)
.register_task(
task!(drupal_loadtest_node_page)
.set_weight(10)?
.set_name("(Anon) node page"),
)
.register_task(
task!(drupal_loadtest_profile_page)
.set_weight(3)?
.set_name("(Anon) user page"),
),
)
.register_taskset(
taskset!("AuthBrowsingUser")
.set_weight(1)?
.register_task(
task!(drupal_loadtest_login)
.set_on_start()
.set_name("(Auth) login"),
)
.register_task(
task!(drupal_loadtest_front_page)
.set_weight(15)?
.set_name("(Auth) front page"),
)
.register_task(
task!(drupal_loadtest_node_page)
.set_weight(10)?
.set_name("(Auth) node page"),
)
.register_task(
task!(drupal_loadtest_profile_page)
.set_weight(3)?
.set_name("(Auth) user page"),
)
.register_task(
task!(drupal_loadtest_post_comment)
.set_weight(3)?
.set_name("(Auth) comment form"),
),
)
.execute()?
.print();
Ok(())
}
async fn drupal_loadtest_front_page(user: &SwanlingUser) -> SwanlingTaskResult {
let mut swanling = user.get("/").await?;
match swanling.response {
Ok(response) => {
let headers = &response.headers().clone();
match response.text().await {
Ok(t) => {
let re = Regex::new(r#"src="(.*?)""#).unwrap();
let mut urls = Vec::new();
for url in re.captures_iter(&t) {
if url[1].contains("/misc") || url[1].contains("/themes") {
urls.push(url[1].to_string());
}
}
for asset in &urls {
let _ = user.get_named(asset, "static asset").await;
}
}
Err(e) => {
return user.set_failure(
&format!("front_page: failed to parse page: {}", e),
&mut swanling.request,
Some(&headers),
None,
);
}
}
}
Err(e) => {
return user.set_failure(
&format!("front_page: no response from server: {}", e),
&mut swanling.request,
None,
None,
);
}
}
Ok(())
}
async fn drupal_loadtest_node_page(user: &SwanlingUser) -> SwanlingTaskResult {
let nid = rand::thread_rng().gen_range(1..10_000);
let _swanling = user.get(format!("/node/{}", &nid).as_str()).await?;
Ok(())
}
async fn drupal_loadtest_profile_page(user: &SwanlingUser) -> SwanlingTaskResult {
let uid = rand::thread_rng().gen_range(2..5_001);
let _swanling = user.get(format!("/user/{}", &uid).as_str()).await?;
Ok(())
}
async fn drupal_loadtest_login(user: &SwanlingUser) -> SwanlingTaskResult {
let mut swanling = user.get("/user").await?;
match swanling.response {
Ok(response) => {
let headers = &response.headers().clone();
match response.text().await {
Ok(html) => {
let re = Regex::new(r#"name="form_build_id" value=['"](.*?)['"]"#).unwrap();
let form_build_id = match re.captures(&html) {
Some(f) => f,
None => {
return user.set_failure(
"login: no form_build_id on page: /user page",
&mut swanling.request,
Some(&headers),
Some(&html),
);
}
};
let uid: usize = rand::thread_rng().gen_range(3..5_002);
let username = format!("user{}", uid);
let params = [
("name", username.as_str()),
("pass", "12345"),
("form_build_id", &form_build_id[1]),
("form_id", "user_login"),
("op", "Log+in"),
];
let request_builder = user.swanling_post("/user").await?;
let _swanling = user
.swanling_send(request_builder.form(¶ms), None)
.await;
}
Err(e) => {
return user.set_failure(
&format!("login: unexpected error when loading /user page: {}", e),
&mut swanling.request,
Some(&headers),
None,
);
}
}
}
Err(e) => {
return user.set_failure(
&format!("login: no response from server: {}", e),
&mut swanling.request,
None,
None,
);
}
}
Ok(())
}
async fn drupal_loadtest_post_comment(user: &SwanlingUser) -> SwanlingTaskResult {
let nid: i32 = rand::thread_rng().gen_range(1..10_000);
let node_path = format!("node/{}", &nid);
let comment_path = format!("/comment/reply/{}", &nid);
let mut swanling = user.get(&node_path).await?;
match swanling.response {
Ok(response) => {
let headers = &response.headers().clone();
match response.text().await {
Ok(html) => {
let re = Regex::new(r#"name="form_build_id" value=['"](.*?)['"]"#).unwrap();
let form_build_id = match re.captures(&html) {
Some(f) => f,
None => {
return user.set_failure(
&format!("post_comment: no form_build_id found on {}", &node_path),
&mut swanling.request,
Some(&headers),
Some(&html),
);
}
};
let re = Regex::new(r#"name="form_token" value=['"](.*?)['"]"#).unwrap();
let form_token = match re.captures(&html) {
Some(f) => f,
None => {
return user.set_failure(
&format!("post_comment: no form_token found on {}", &node_path),
&mut swanling.request,
Some(&headers),
Some(&html),
);
}
};
let re = Regex::new(r#"name="form_id" value=['"](.*?)['"]"#).unwrap();
let form_id = match re.captures(&html) {
Some(f) => f,
None => {
return user.set_failure(
&format!("post_comment: no form_id found on {}", &node_path),
&mut swanling.request,
Some(&headers),
Some(&html),
);
}
};
let comment_body = "this is a test comment body";
let params = [
("subject", "this is a test comment subject"),
("comment_body[und][0][value]", &comment_body),
("comment_body[und][0][format]", "filtered_html"),
("form_build_id", &form_build_id[1]),
("form_token", &form_token[1]),
("form_id", &form_id[1]),
("op", "Save"),
];
let request_builder = user.swanling_post(&comment_path).await?;
let mut swanling = user
.swanling_send(request_builder.form(¶ms), None)
.await?;
match swanling.response {
Ok(response) => {
let headers = &response.headers().clone();
match response.text().await {
Ok(html) => {
if !html.contains(&comment_body) {
return user.set_failure(
&format!("post_comment: no comment showed up after posting to {}", &comment_path),
&mut swanling.request,
Some(&headers),
Some(&html),
);
}
}
Err(e) => {
return user.set_failure(
&format!(
"post_comment: unexpected error when posting to {}: {}",
&comment_path, e
),
&mut swanling.request,
Some(&headers),
None,
);
}
}
}
Err(e) => {
return user.set_failure(
&format!(
"post_comment: no response when posting to {}: {}",
&comment_path, e
),
&mut swanling.request,
None,
None,
);
}
}
}
Err(e) => {
return user.set_failure(
&format!("post_comment: no text when loading {}: {}", &node_path, e),
&mut swanling.request,
None,
None,
);
}
}
}
Err(e) => {
return user.set_failure(
&format!(
"post_comment: no response when loading {}: {}",
&node_path, e
),
&mut swanling.request,
None,
None,
);
}
}
Ok(())
}