Skip to content

Instantly share code, notes, and snippets.

@opsJson
Last active November 13, 2023 18:33
Show Gist options
  • Save opsJson/ccef4231c9fa69ad1b698874fd2fc797 to your computer and use it in GitHub Desktop.
Save opsJson/ccef4231c9fa69ad1b698874fd2fc797 to your computer and use it in GitHub Desktop.
Webdriver Interface in C
#ifndef _WEBDRIVER_H_
#define _WEBDRIVER_H_
#include "cmdl.h" /* https://gist.github.com/opsJson/515644eff27b29ad91b79522ca3b2c40 */
#include "makestr.h" /* https://gist.github.com/opsJson/ce29f980360713b74e4abc152217849a */
#include "json_parser.h" /* https://gist.github.com/opsJson/d79503f7b206c6697f20d8c979e3e74a */
#include "json_maker.h" /* https://github.com/opsJson/json-maker */
#include <stdbool.h>
#define STRINGIFY(...) #__VA_ARGS__
static char *prompt_escape(char c) {
static char ret[2];
if (c == '\"') return "\\\"";
if (c == '\\') return "\\\\";
sprintf(ret, "%c", c);
return ret;
}
static char *webdriver_curl(const char *method, const char *url, const char *payload) {
char *curl_cmd, *result, *data;
char buffer[4096] = {0};
if (payload) {
data = string("--data \"%v\"", prompt_escape, payload);
curl_cmd = string("curl \"localhost:9515%s\" -X \"%s\" %s", url, method, data);
}
else {
curl_cmd = string("curl \"localhost:9515%s\" -X \"%s\"", url, method);
}
if (!cmdl(curl_cmd, buffer, sizeof(buffer))) {
printf("ERROR: %s\n", cmdl_strerror());
free(curl_cmd);
return NULL;
}
if (payload) {
free(data);
}
free(curl_cmd);
result = calloc(strlen(buffer) + 1, 1);
strncpy(result, buffer, strlen(buffer));
return result;
}
char *webdriver_new_session(void) {
char *result = webdriver_curl("POST", "/session", STRINGIFY({"capabilities": {}}));
char *value = json_get(result, "value");
char *session_id = json_get(value, "sessionId");
free(result);
free(value);
return session_id;
}
void webdriver_delete_session(const char *session_id) {
char *url = string("/session/%s", session_id);
char *result = webdriver_curl("DELETE", url, NULL);
free(url);
free(result);
}
char *webdriver_status(void) {
char *result = webdriver_curl("GET", "/status", NULL);
char *value = json_get(result, "value");
free(result);
return value;
}
char *webdriver_get_timeouts(const char *session_id) {
char *url = string("/session/%s/timeouts", session_id);
char *result = webdriver_curl("GET", url, NULL);
char *value = json_get(result, "value");
free(url);
free(result);
return value;
}
void webdriver_set_timeouts(const char *session_id, int implicit, int pageLoad, int script) {
char *url = string("/session/%s/timeouts", session_id);
char payload[1024] = "";
json_begin(payload);
if (script >= 0) {
json_key(payload, "script");
json_value_number(payload, script);
}
if (pageLoad >= 0) {
json_key(payload, "pageLoad");
json_value_number(payload, pageLoad);
}
if (implicit >= 0) {
json_key(payload, "implicit");
json_value_number(payload, implicit);
}
json_end(payload);
char *result = webdriver_curl("POST", url, payload);
free(url);
free(result);
}
void webdriver_navigate_to(const char *session_id, const char *url) {
char *_url = string("/session/%s/url", session_id);
char *payload = string(STRINGIFY({"url": "%s"}), url);
char *result = webdriver_curl("POST", _url, payload);
free(_url);
free(payload);
free(result);
}
char *webdriver_get_url(const char *session_id) {
char *url = string("/session/%s/url", session_id);
char *result = webdriver_curl("GET", url, NULL);
char *value = json_get(result, "value");
free(url);
free(result);
return value;
}
void webdriver_back(const char *session_id) {
char *url = string("/session/%s/back", session_id);
char *result = webdriver_curl("POST", url, "{}");
free(url);
free(result);
}
void webdriver_forward(const char *session_id) {
char *url = string("/session/%s/forward", session_id);
char *result = webdriver_curl("POST", url, "{}");
free(url);
free(result);
}
void webdriver_refresh(const char *session_id) {
char *url = string("/session/%s/refresh", session_id);
char *result = webdriver_curl("POST", url, "{}");
free(url);
free(result);
}
char *webdriver_get_title(const char *session_id) {
char *url = string("/session/%s/title", session_id);
char *result = webdriver_curl("GET", url, NULL);
char *value = json_get(result, "value");
free(url);
free(result);
return value;
}
char *webdriver_get_window(const char *session_id) {
char *url = string("/session/%s/window", session_id);
char *result = webdriver_curl("GET", url, NULL);
char *value = json_get(result, "value");
free(url);
free(result);
return value;
}
void webdriver_close_window(const char *session_id) {
char *url = string("/session/%s/window", session_id);
char *result = webdriver_curl("DELETE", url, NULL);
free(url);
free(result);
}
char *webdriver_switch_to_window(const char *session_id, const char *handle_id) {
char *url = string("/session/%s/window", session_id);
char *payload = string(STRINGIFY({"handle": "%s"}), handle_id);
char *result = webdriver_curl("POST", url, payload);
free(url);
free(payload);
return result;
}
char *webdriver_get_window_handles(const char *session_id) {
char *url = string("/session/%s/window/handles", session_id);
char *result = webdriver_curl("GET", url, NULL);
char *value = json_get(result, "value");
free(url);
free(result);
return value;
}
char *webdriver_new_window(const char *session_id, const char *type) {
char *url = string("/session/%s/window/new", session_id);
char *payload = string(STRINGIFY({"type": "%s"}), type);
char *result = webdriver_curl("POST", url, payload);
char *value = json_get(result, "value");
char *handle = json_get(value, "handle");
free(url);
free(payload);
free(result);
free(value);
return handle;
}
char *webdriver_get_window_rect(const char *session_id) {
char *url = string("/session/%s/window/rect", session_id);
char *result = webdriver_curl("GET", url, NULL);
char *value = json_get(result, "value");
free(url);
free(result);
return value;
}
void webdriver_set_window_rect(const char *session_id, int x, int y, int width, int height) {
char *url = string("/session/%s/window/rect", session_id);
char payload[256] = "";
json_begin(payload);
if (x >= 0) {
json_key(payload, "x");
json_value_number(payload, x);
}
if (y >= 0) {
json_key(payload, "y");
json_value_number(payload, y);
}
if (width >= 0) {
json_key(payload, "width");
json_value_number(payload, width);
}
if (height >= 0) {
json_key(payload, "height");
json_value_number(payload, height);
}
json_end(payload);
char *result = webdriver_curl("POST", url, payload);
free(url);
free(result);
}
void webdriver_maximize_window(const char *session_id) {
char *url = string("/session/%s/window/maximize", session_id);
char *result = webdriver_curl("POST", url, "{}");
free(url);
free(result);
}
void webdriver_minimize_window(const char *session_id) {
char *url = string("/session/%s/window/minimize", session_id);
char *result = webdriver_curl("POST", url, "{}");
free(url);
free(result);
}
void webdriver_fullscreen_window(const char *session_id) {
char *url = string("/session/%s/window/fullscreen", session_id);
char *result = webdriver_curl("POST", url, "{}");
free(url);
free(result);
}
char *webdriver_get_active_element(const char *session_id) {
char *url = string("/session/%s/element/active", session_id);
char *result = webdriver_curl("GET", url, NULL);
char *value = json_get(result, "value");
char *element = json_get(value, "element-6066-11e4-a52e-4f735466cecf");
free(url);
free(result);
free(value);
return element;
}
char *webdriver_find_element(const char *session_id, const char *using, const char *value) {
char *url = string("/session/%s/element", session_id);
char *payload = string(STRINGIFY({"using":"%s","value":"%s"}), using, value);
char *result = webdriver_curl("POST", url, payload);
char *_value = json_get(result, "value");
char *element = json_get(_value, "element-6066-11e4-a52e-4f735466cecf");
free(url);
free(payload);
free(result);
free(_value);
return element;
}
char *webdriver_find_elements(const char *session_id, const char *using, const char *value) {
char *url = string("/session/%s/elements", session_id);
char *payload = string(STRINGIFY({"using":"%s","value":"%s"}), using, value);
char *result = webdriver_curl("POST", url, payload);
char *_value = json_get(result, "value");
char *element = json_get(_value, "element-6066-11e4-a52e-4f735466cecf");
free(url);
free(payload);
free(result);
free(_value);
return element;
}
char *webdriver_is_element_selected(const char *session_id, const char *element_id) {
char *url = string("/session/%s/element/%s/selected", session_id, element_id);
char *result = webdriver_curl("GET", url, NULL);
char *value = json_get(result, "value");
free(url);
free(result);
return value;
}
char *webdriver_get_element_attribute(const char *session_id, const char *element_id, const char *name) {
char *url = string("/session/%s/element/%s/attribute/%s", session_id, element_id, name);
char *result = webdriver_curl("GET", url, NULL);
char *value = json_get(result, "value");
free(url);
free(result);
return value;
}
char *webdriver_get_element_property(const char *session_id, const char *element_id, const char *name) {
char *url = string("/session/%s/element/%s/property/%s", session_id, element_id, name);
char *result = webdriver_curl("GET", url, NULL);
char *value = json_get(result, "value");
free(url);
free(result);
return value;
}
char *webdriver_get_element_css_value(const char *session_id, const char *element_id, const char *name) {
char *url = string("/session/%s/element/%s/css/%s", session_id, element_id, name);
char *result = webdriver_curl("GET", url, NULL);
char *value = json_get(result, "value");
free(url);
free(result);
return value;
}
char *webdriver_get_element_text(const char *session_id, const char *element_id) {
char *url = string("/session/%s/element/%s/text", session_id, element_id);
char *result = webdriver_curl("GET", url, NULL);
char *value = json_get(result, "value");
free(url);
free(result);
return value;
}
char *webdriver_get_element_tag_name(const char *session_id, const char *element_id) {
char *url = string("/session/%s/element/%s/name", session_id, element_id);
char *result = webdriver_curl("GET", url, NULL);
char *value = json_get(result, "value");
free(url);
free(result);
return value;
}
char *webdriver_get_element_rect(const char *session_id, const char *element_id) {
char *url = string("/session/%s/element/%s/rect", session_id, element_id);
char *result = webdriver_curl("GET", url, NULL);
char *value = json_get(result, "value");
free(url);
free(result);
return value;
}
int webdriver_is_element_enabled(const char *session_id, const char *element_id) {
char *url = string("/session/%s/element/%s/enabled", session_id, element_id);
char *result = webdriver_curl("GET", url, NULL);
char *value = json_get(result, "value");
int ret;
free(url);
free(result);
if (strcmp(value, "true") == 0) ret = 1;
else ret = 0;
free(value);
return ret;
}
char *webdriver_get_computed_role(const char *session_id, const char *element_id) {
char *url = string("/session/%s/element/%s/computedrole", session_id, element_id);
char *result = webdriver_curl("GET", url, NULL);
char *value = json_get(result, "value");
free(url);
free(result);
return value;
}
char *webdriver_get_computed_label(const char *session_id, const char *element_id) {
char *url = string("/session/%s/element/%s/computedlabel", session_id, element_id);
char *result = webdriver_curl("GET", url, NULL);
char *value = json_get(result, "value");
free(url);
free(result);
return value;
}
int webdriver_element_click(const char *session_id, const char *element_id) {
char *url = string("/session/%s/element/%s/click", session_id, element_id);
char *result = webdriver_curl("POST", url, "{}");
char *value = json_get(result, "value");
int ret;
if (strcmp(value, "null") == 0) {
ret = 1;
}
else {
ret = 0;
}
free(url);
free(result);
free(value);
return ret;
}
int webdriver_element_clear(const char *session_id, const char *element_id) {
char *url = string("/session/%s/element/%s/clear", session_id, element_id);
char *result = webdriver_curl("POST", url, "{}");
char *value = json_get(result, "value");
int ret;
if (strcmp(value, "null") == 0) {
ret = 1;
}
else {
ret = 0;
}
free(url);
free(result);
free(value);
return ret;
}
int webdriver_element_send_keys(const char *session_id, const char *element_id, const char *text) {
char *url = string("/session/%s/element/%s/value", session_id, element_id);
char *payload = string(STRINGIFY({
"text": "%v"
}), prompt_escape, text);
char *result = webdriver_curl("POST", url, payload);
char *value = json_get(result, "value");
int ret;
if (strcmp(value, "null") == 0) {
ret = 1;
}
else {
ret = 0;
}
free(url);
free(payload);
free(result);
free(value);
return ret;
}
char *webdriver_get_page_source(const char *session_id) {
char *url = string("/session/%s/source", session_id);
char *result = webdriver_curl("GET", url, NULL);
char *value = json_get(result, "value");
free(url);
free(result);
return value;
}
char *webdriver_execute_script_sync(const char *session_id, const char *script) {
char *url = string("/session/%s/execute/sync", session_id);
char *payload = string(STRINGIFY({"script":"%v","args":[]}), prompt_escape, script);
char *result = webdriver_curl("POST", url, payload);
char *value = json_get(result, "value");
free(url);
free(payload);
free(result);
return value;
}
char *webdriver_execute_async_script(const char *session_id, const char *script) {
char *url = string("/session/%s/execute/async", session_id);
char *payload = string(STRINGIFY({"script":"%s","args":[]}), script);
char *result = webdriver_curl("POST", url, payload);
char *value = json_get(result, "value");
free(url);
free(payload);
free(result);
return value;
}
char *webdriver_get_all_cookies(const char *session_id) {
char *url = string("/session/%s/cookie", session_id);
char *result = webdriver_curl("GET", url, NULL);
char *value = json_get(result, "value");
free(url);
free(result);
return value;
}
char *webdriver_get_named_cookie(const char *session_id, const char *name) {
char *url = string("/session/%s/cookie/%s", session_id, name);
char *result = webdriver_curl("GET", url, NULL);
char *value = json_get(result, "value");
free(url);
free(result);
return value;
}
struct webdriver_cookie {
const char *name;
const char *value;
const char *path;
const char *domain;
const char *sameSite;
bool secure;
bool httpOnly;
long int expiry;
};
int webdriver_add_cookie(const char *session_id, struct webdriver_cookie cookie) {
char *url = string("/session/%s/cookie", session_id);
char payload[2048] = "";
int ret;
json_begin(payload);
json_key(payload, "cookie");
json_begin(payload);
if (cookie.name) {
json_key(payload, "name");
json_value_string(payload, cookie.name);
}
if (cookie.value) {
json_key(payload, "value");
json_value_string(payload, cookie.value);
}
if (cookie.path) {
json_key(payload, "path");
json_value_string(payload, cookie.path);
}
if (cookie.domain) {
json_key(payload, "domain");
json_value_string(payload, cookie.domain);
}
if (cookie.secure) {
json_key(payload, "secure");
json_value_bool(payload, cookie.secure);
}
if (cookie.expiry) {
json_key(payload, "expiry");
json_value_number(payload, cookie.expiry);
}
if (cookie.httpOnly) {
json_key(payload, "httpOnly");
json_value_bool(payload, cookie.httpOnly);
}
if (cookie.sameSite) {
json_key(payload, "sameSite");
json_value_string(payload, cookie.sameSite);
}
json_end(payload);
json_end(payload);
char *result = webdriver_curl("POST", url, payload);
char *value = json_get(result, "value");
if (strcmp(value, "null") == 0) {
ret = 1;
}
else {
ret = 0;
}
free(url);
free(result);
free(value);
return ret;
}
int webdriver_delete_cookie(const char *session_id, const char *name) {
char *url = string("/session/%s/cookie/%s", session_id, name);
char *result = webdriver_curl("DELETE", url, NULL);
char *value = json_get(result, "value");
int ret;
if (strcmp(value, "null") == 0) {
ret = 1;
}
else {
ret = 0;
}
free(url);
free(result);
free(value);
return ret;
}
int webdriver_delete_all_cookies(const char *session_id) {
char *url = string("/session/%s/cookie", session_id);
char *result = webdriver_curl("DELETE", url, NULL);
char *value = json_get(result, "value");
int ret;
if (strcmp(value, "null") == 0) {
ret = 1;
}
else {
ret = 0;
}
free(url);
free(result);
free(value);
return ret;
}
int webdriver_dismiss_alert(const char *session_id) {
char *url = string("/session/%s/alert/dismiss", session_id);
char *result = webdriver_curl("POST", url, "{}");
char *value = json_get(result, "value");
int ret;
if (strcmp(value, "null") == 0) {
ret = 1;
}
else {
ret = 0;
}
free(url);
free(result);
free(value);
return ret;
}
int webdriver_accept_alert(const char *session_id) {
char *url = string("/session/%s/alert/accept", session_id);
char *result = webdriver_curl("POST", url, "{}");
char *value = json_get(result, "value");
int ret;
if (strcmp(value, "null") == 0) {
ret = 1;
}
else {
ret = 0;
}
free(url);
free(result);
free(value);
return ret;
}
char *webdriver_get_alert_text(const char *session_id) {
char *url = string("/session/%s/alert/text", session_id);
char *result = webdriver_curl("GET", url, NULL);
char *value = json_get(result, "value");
free(url);
free(result);
return value;
}
int webdriver_send_alert_text(const char *session_id, const char *text) {
char *url = string("/session/%s/alert/text", session_id);
char *payload = string(STRINGIFY({"text":"%v"}), prompt_escape, text);
char *result = webdriver_curl("POST", url, payload);
char *value = json_get(result, "value");
int ret;
if (strcmp(value, "null") == 0) {
ret = 1;
}
else {
ret = 0;
}
free(url);
free(payload);
free(result);
free(value);
return ret;
}
char *webdriver_take_screenshot(const char *session_id) {
char *url = string("/session/%s/screenshot", session_id);
char *result = webdriver_curl("GET", url, NULL);
char *value = json_get(result, "value");
free(url);
free(result);
return value;
}
char *webdriver_take_element_screenshot(const char *session_id, const char *element_id) {
char *url = string("/session/%s/element/%s/screenshot", session_id, element_id);
char *result = webdriver_curl("GET", url, NULL);
char *value = json_get(result, "value");
free(url);
free(result);
return value;
}
char *webdriver_print_page(const char *session_id) {
char *url = string("/session/%s/print", session_id);
char *result = webdriver_curl("POST", url, "{}");
char *value = json_get(result, "value");
free(url);
free(result);
return value;
}
#endif
/*///////////////////////////////////
Testing:
///////////////////////////////////*/
int main(void) {
char *session_id = webdriver_new_session();
webdriver_navigate_to(session_id, "https://lite.duckduckgo.com/lite/");
char *input_id = webdriver_find_element(session_id, "css selector", "[name='q']");
char *button_id = webdriver_find_element(session_id, "css selector", "[type='submit']");
webdriver_element_send_keys(session_id, input_id, "last news");
webdriver_element_click(session_id, button_id);
char *link = webdriver_execute_script_sync(session_id, STRINGIFY(
const length = document.querySelectorAll("a").length;
const index = Math.floor(Math.random() * length);
const link = document.querySelectorAll("a")[index].href;
return link;
));
printf("random link: %s\n", link);
free(link);
free(button_id);
free(input_id);
free(session_id);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment