Select Git revision
-
Jan Hadrava authoredJan Hadrava authored
client.c 8.38 KiB
#define _GNU_SOURCE
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
#include <tidy/tidy.h>
#include <tidy/tidybuffio.h>
#include <time.h>
#include "config.h"
struct memory {
char *response;
size_t size;
};
struct submit_action {
int contest_id;
int task_id;
char *local_file;
char *reported_filename;
};
static size_t write_callback(void *data, size_t size, size_t nmemb, void *userp) {
size_t realsize = size *nmemb;
struct memory *mem = (struct memory *)userp;
char *ptr = realloc(mem->response, mem->size + realsize + 1);
if (ptr == NULL)
return 0;
mem->response = ptr;
memcpy(&(mem->response[mem->size]), data, realsize);
mem->size += realsize;
mem->response[mem->size] = 0;
return realsize;
}
static void debug_print_cookies(CURL *curl) {
CURLcode res;
struct curl_slist *cookies;
struct curl_slist *nc;
int i;
printf("Cookies, curl knows:\n");
res = curl_easy_getinfo(curl, CURLINFO_COOKIELIST, &cookies);
if (res != CURLE_OK) {
fprintf(stderr, "Curl curl_easy_getinfo failed: %s\n", curl_easy_strerror(res));
return;
}
nc = cookies;
i = 0;
while (nc) {
printf("[%d]: %s\n", i, nc->data);
nc = nc->next;
i++;
}
if (i == 0) {
printf("(none)\n");
}
curl_slist_free_all(cookies);
}
void setup_curl(CURL *curl, struct memory *chunk) {
chunk->response = NULL;
chunk->size = 0;
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "");
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); // skip cert verification
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); // skip hostname verification (is it measureably faster?)
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)chunk);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
}
void free_body(struct memory *chunk) {
free(chunk->response);
chunk->response = NULL;
chunk->size=0;
}
void print_body(CURL *curl, struct memory *chunk) {
printf("%li\n", chunk->size);
printf("BEGIN >>>>>>\n");
for (int i = 0; i < chunk->size; i++) {
printf("%c", chunk->response[i]);
}
printf("\n<<<<<< END\n");
}
void perform_get(CURL *curl, char *url) {
CURLcode res;
curl_easy_setopt(curl, CURLOPT_URL, url);
res = curl_easy_perform(curl);
if (res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
}
void search_csrf(TidyDoc doc, TidyNode tnod, char **csrf) {
TidyNode child;
for (child = tidyGetChild(tnod); child; child = tidyGetNext(child) ) {
ctmbstr name = tidyNodeGetName(child);
if (name) {
// It is HTML tag
TidyAttr attr;
bool it_is_csrf = false;
const char *it_has_value = NULL;
for (attr = tidyAttrFirst(child); attr; attr = tidyAttrNext(attr) ) {
if (!strcmp(tidyAttrName(attr), "id")) {
if (!strcmp(tidyAttrValue(attr), "csrf_token")) {
it_is_csrf = true;
}
}
if (!strcmp(tidyAttrName(attr), "value")) {
it_has_value = tidyAttrValue(attr);
}
}
if (it_is_csrf && it_has_value) {
//printf("Yay! csrf token = %s\n", it_has_value);
if (*csrf)
free(*csrf);
*csrf = strdup(it_has_value);
}
}
search_csrf(doc, child, csrf);
}
}
void extract_csrf(struct memory *chunk, char **csrf) {
TidyDoc tdoc;
TidyBuffer docbuf = {0};
TidyBuffer tidy_errbuf = {0};
tdoc = tidyCreate();
tidySetErrorBuffer(tdoc, &tidy_errbuf);
tidyBufInit(&docbuf);
// copy response buffer
tidyBufAppend(&docbuf, chunk->response, chunk->size);
tidyParseBuffer(tdoc, &docbuf); // real parse
search_csrf(tdoc, tidyGetRoot(tdoc), csrf); // find element
//fprintf(stderr, "%s\n", tidy_errbuf.bp); // print errors
tidyBufFree(&docbuf);
tidyBufFree(&tidy_errbuf);
tidyRelease(tdoc);
}
void load_login_page (CURL *curl, struct memory *chunk, char **csrf) {
perform_get(curl, BASE_URL "/");
free_body(chunk);
perform_get(curl, BASE_URL "/auth/login");
//print_body(curl, chunk);
//print_cookies(curl);
extract_csrf(chunk, csrf);
//printf("csrf token = %s\n", csrf);
free_body(chunk);
}
void do_login (CURL *curl, struct memory *chunk, char **csrf, char *login_email, char *login_password) {
char *enc_email = curl_easy_escape(curl, login_email, strlen(login_email));
char *enc_password = curl_easy_escape(curl, login_password, strlen(login_password));
char *enc_submit = curl_easy_escape(curl, "Přihlásit se", strlen("Přihlásit se"));
char *post_data;
asprintf(&post_data, "csrf_token=%s&email=%s&passwd=%s&submit=%s&next=", *csrf, enc_email, enc_password, enc_submit);
curl_free(enc_email);
curl_free(enc_password);
curl_free(enc_submit);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data);
perform_get(curl, BASE_URL "/auth/login");
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, NULL);
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
free(post_data);
free_body(chunk);
}
void load_contest (CURL *curl, struct memory *chunk, int contest_id) {
char *url;
asprintf(&url, BASE_URL "/user/contest/%i/", contest_id);
perform_get(curl, url);
free(url);
//print_body(curl, chunk);
free_body(chunk);
}
void load_task (CURL *curl, struct memory *chunk, char **csrf, int contest_id, int task_id) {
char *url;
asprintf(&url, BASE_URL "/user/contest/%i/task/%i/", contest_id, task_id);
perform_get(curl, url);
free(url);
//print_body(curl, chunk);
extract_csrf(chunk, csrf);
//printf("csrf token = %s\n", csrf);
free_body(chunk);
}
bool submit_task (CURL *curl, struct memory *chunk, char **csrf, int contest_id, int task_id, char *local_file, char *reported_filename) {
char *url;
asprintf(&url, BASE_URL "/user/contest/%i/task/%i/", contest_id, task_id);
curl_mime *mime;
curl_mimepart *part;
mime = curl_mime_init(curl);
part = curl_mime_addpart(mime);
curl_mime_data(part, *csrf, CURL_ZERO_TERMINATED);
curl_mime_name(part, "csrf_token");
part = curl_mime_addpart(mime);
curl_mime_data(part, "Jenduv automatizovany test submit", CURL_ZERO_TERMINATED);
curl_mime_name(part, "note");
part = curl_mime_addpart(mime);
curl_mime_data(part, "Odevzdat", CURL_ZERO_TERMINATED);
curl_mime_name(part, "submit");
part = curl_mime_addpart(mime);
curl_mime_filedata(part, local_file);
curl_mime_filename(part, reported_filename);
curl_mime_name(part, "file");
curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
curl_easy_setopt(curl, CURLOPT_URL, url);
char errbuf[CURL_ERROR_SIZE];
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
errbuf[0] = 0;
CURLcode res = curl_easy_perform(curl);
if(res != CURLE_OK) {
size_t len = strlen(errbuf);
fprintf(stderr, "\nlibcurl: (%d) ", res);
if(len)
fprintf(stderr, "%s%s", errbuf,
((errbuf[len - 1] != '\n') ? "\n" : ""));
else
fprintf(stderr, "%s\n", curl_easy_strerror(res));
}
free(url);
curl_easy_setopt(curl, CURLOPT_MIMEPOST, NULL);
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
curl_mime_free(mime);
long http_code = 0;
curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &http_code);
if (http_code != 200) {
printf("Post file failed:\n");
print_body(curl, chunk);
free_body(chunk);
return false;
}
free_body(chunk);
return true;
}
bool full_test(char *login_email, char *login_password, struct submit_action *actions) {
bool ret = true;
CURL *curl;
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
struct memory chunk;
char *csrf = NULL;
if (curl) {
setup_curl(curl, &chunk);
load_login_page(curl, &chunk, &csrf);
do_login(curl, &chunk, &csrf, login_email, login_password);
while (actions->contest_id) {
/*
printf("performing action %i %i %s %s\n", actions->contest_id, actions->task_id,
actions->local_file, actions->reported_filename);
*/
load_contest(curl, &chunk, actions->contest_id);
load_task(curl, &chunk,&csrf, actions->contest_id, actions->task_id);
if (!submit_task(curl, &chunk, &csrf,
actions->contest_id, actions->task_id,
actions->local_file, actions->reported_filename)) {
ret = false;
}
actions++;
}
// cleanup
curl_easy_cleanup(curl);
}
curl_global_cleanup();
if (csrf)
free(csrf);
return ret;
}
int main() {
char *login_email = "had+ucastnik@kam.mff.cuni.cz";
char *login_password = "UTX0seFkVim51vkOwER5G8GjB5eEq7G9";
struct submit_action actions[] = {
//{ 25, 3, "/home/had/BratruvZpevnik_v4-0.pdf", "zpevnik.pdf"},
//{ 25, 4, "testsubmit_02.pdf", "moje_reseni.pdf"},
//{ 25, 5, "/home/had/sada3.pdf", "sendvic.pdf"},
//{ 25, 6, "/home/had/stitek.pdf", "sken.pdf"},
{ 0, 0, NULL, NULL}
};
full_test(login_email, login_password, actions);
return 0;
}