Last active
November 13, 2023 18:33
-
-
Save opsJson/ccef4231c9fa69ad1b698874fd2fc797 to your computer and use it in GitHub Desktop.
Webdriver Interface in C
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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