Skip to content

Commit

Permalink
Added multi threaded version.
Browse files Browse the repository at this point in the history
  • Loading branch information
pptacher committed Apr 27, 2022
1 parent 3bdb19b commit b2ede54
Show file tree
Hide file tree
Showing 2 changed files with 352 additions and 0 deletions.
3 changes: 3 additions & 0 deletions paris.fr/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@ list(APPEND CMAKE_CXX_FLAGS "-std=c++17")

add_executable(booking.bin booking.cc)
target_link_libraries(booking.bin curl re2)

add_executable(booking_mt.bin booking_mt.cc)
target_link_libraries(booking_mt.bin curl re2)
349 changes: 349 additions & 0 deletions paris.fr/cpp/booking_mt.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,349 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <cassert>
#include <cstdlib>
#include <ctime>
#include <curl/curl.h>
#include <re2.h>
//#include <chrono>
#include <thread>
#include <iomanip>
#include <iostream>
#include <fstream>
#include <sstream>
#include <unordered_map>
#include <mutex>

using std::string;

std::mutex output_mutex;

std::unordered_map<string, string> hmap;

// libcurl write callback function
static int writer(char *data, size_t size, size_t nmemb, std::string *writerData)
{
if(writerData == NULL)
return 0;

writerData->append(data, size*nmemb);

return size * nmemb;
}

void book(){
CURL *curl = NULL;
CURLcode code;

char errorBuffer[CURL_ERROR_SIZE];
std::string buffer;

curl = curl_easy_init();

//curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
//curl_easy_setopt(curl, CURLOPT_HEADER, 1L);
//curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);

if(curl == NULL) {
fprintf(stderr, "Failed to create CURL connection\n");
exit(EXIT_FAILURE);
}

std::srand(std::hash<std::thread::id>{}(std::this_thread::get_id())+std::time(NULL));
string rdstring;
const char alphanum[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
for (size_t i = 0; i < 16; i++) {
rdstring.push_back(alphanum[std::rand()/((RAND_MAX + 1u)/62)]);
}

curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer);
curl_easy_setopt(curl, CURLOPT_URL, "https://teleservices.paris.fr/rdvtitres/jsp/site/Portal.jsp?page=appointmentsearch&view=search&category=titres");
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 0L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writer);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
//curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
//curl_easy_setopt(curl, CURLOPT_USERPWD, "james:bond");
curl_easy_setopt(curl, CURLOPT_USERAGENT, "Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148");

curl_easy_setopt(curl, CURLOPT_COOKIEJAR, ("/tmp/cookies" + rdstring + ".txt").c_str());
code = curl_easy_perform(curl);
if(code != CURLE_OK) {
fprintf(stderr, "Failed to get url [%s]\n", errorBuffer);
exit(EXIT_FAILURE);
}

const char* jsonObj = "{ \"username\" : \"username\" , \"password\" : \"password\" }";
//sprintf(jsonObj, "\"name\" : \"%s\", \"age\" : \"%s\"", name, age);
struct curl_slist *list = NULL;
list = curl_slist_append(list, "Content-Type: application/json");
list = curl_slist_append(list, "charset: utf-8");

curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonObj);

int i(0);

do {
i = (i+1)%20;
buffer = "";
code = curl_easy_perform(curl);
if(code != CURLE_OK) {
fprintf(stderr, "Failed to get url [%s]\n", errorBuffer);
exit(EXIT_FAILURE);
}
//std::cout << "\r\e[1mPolling the server\e[0m " << std::setw(20) << std::left << std::string(20,' ');
//std::cout << "\r\e[1mPolling the server\e[0m " << std::setw(i) << std::left << std::string(i,'.') << std::flush;


//std::this_thread::sleep_for(std::chrono::milliseconds(1000));

} while (RE2::PartialMatch(buffer,"(Merci de renouveler votre demande dans quelques minutes)|"
"(Tous les rendez-vous ont)|"
"(Veuillez en choisir un autre.)|"
"(Aucun rendez-vous n'est actuellement disponible.)|"
"(Ville de Paris pour cette semaine ont tous)|"
"Le 3975 n’est pas en mesure de vous proposer des rendez-vous|"
"Les 5 600|"
"Maintenance|"
"Le 3975 n’est pas en mesure de vous proposer des rendez-vous|"
"Les 5 500" ));

std::cout << std::endl;

string link, date;
RE2::PartialMatch(buffer, R"(<\s*a\s.*href=\"([[:ascii:]]*)\".*id=\".*appointment_first_slot\"\s*>([[:alnum:]\s:]*)</a>)",&link, &date);

buffer.clear();

auto it = link.find("step3");
link.erase(it,5);

string id3;
RE2::PartialMatch(link, R"(id_form=(\d{2}))", &id3);

curl_easy_setopt(curl, CURLOPT_URL, link.c_str());
code = curl_easy_perform(curl);
if(code != CURLE_OK) {
fprintf(stderr, "Failed to get '%s' [%s]\n", link.c_str(), errorBuffer);
exit(EXIT_FAILURE);
}

string id1, id2;
RE2::PartialMatch(buffer, R"(<\s*input\s.*id=\"(attribute\d{2}).*size=\"10")",&id1);
RE2::PartialMatch(buffer, R"(<\s*input\s.*id=\"(attribute\d{2}).*size=\"5")",&id2);

string name, domain;
RE2::FullMatch(hmap["email"],"(.*)@(.*)", &name, &domain);
string email = name + '+' + rdstring + '@' + domain;

curl_mime* multipart = curl_mime_init(curl);
curl_mimepart* part = curl_mime_addpart(multipart);
curl_mime_name(part, "page");
curl_mime_data(part, "appointment", CURL_ZERO_TERMINATED);

part = curl_mime_addpart(multipart);
curl_mime_name(part, "action");
curl_mime_data(part, "doValidateForm", CURL_ZERO_TERMINATED);

part = curl_mime_addpart(multipart);
curl_mime_name(part, "id_form");
curl_mime_data(part, id3.c_str(), CURL_ZERO_TERMINATED);

part = curl_mime_addpart(multipart);
curl_mime_name(part, "date_of_display");
curl_mime_data(part, "2022-04-02", CURL_ZERO_TERMINATED);

part = curl_mime_addpart(multipart);
curl_mime_name(part, "session");
curl_mime_data(part, "session", CURL_ZERO_TERMINATED);

part = curl_mime_addpart(multipart);
curl_mime_name(part, "anchor");
curl_mime_data(part, "step4", CURL_ZERO_TERMINATED);

part = curl_mime_addpart(multipart);
curl_mime_name(part, "lastname");
curl_mime_data(part, hmap["lastname"].c_str(), CURL_ZERO_TERMINATED);

part = curl_mime_addpart(multipart);
curl_mime_name(part, "firstname");
curl_mime_data(part, hmap["firstname"].c_str(), CURL_ZERO_TERMINATED);

part = curl_mime_addpart(multipart);
curl_mime_name(part, "email");
curl_mime_data(part, email.c_str(), CURL_ZERO_TERMINATED);

part = curl_mime_addpart(multipart);
curl_mime_name(part, "emailConfirm");
curl_mime_data(part, email.c_str(), CURL_ZERO_TERMINATED);

part = curl_mime_addpart(multipart);
curl_mime_name(part, id1.c_str());
curl_mime_data(part, hmap["phone"].c_str(), CURL_ZERO_TERMINATED);

part = curl_mime_addpart(multipart);
curl_mime_name(part, id2.c_str());
curl_mime_data(part, hmap["postalcode"].c_str(), CURL_ZERO_TERMINATED);

part = curl_mime_addpart(multipart);
curl_mime_name(part, "save");
curl_mime_data(part, "", CURL_ZERO_TERMINATED);

buffer.clear();
curl_slist_free_all(list);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, NULL);
curl_easy_setopt(curl, CURLOPT_MIMEPOST, multipart);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); // the server weirdly redirects to url#step4.
curl_easy_setopt(curl, CURLOPT_URL, "https://teleservices.paris.fr/rdvtitres/jsp/site/Portal.jsp?page=appointment&view=displayRecapAppointment&anchor=");

curl_easy_perform(curl);

curl_mime_free(multipart);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 0L);

curl_easy_setopt(curl, CURLOPT_HTTPHEADER, NULL);

while (true) {
char filename[] = "/tmp/fileXXXXXX";
mktemp(filename);
strcat(filename, ".jpg");
FILE* fp = fopen(filename, "wb");

curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
curl_easy_setopt(curl, CURLOPT_URL, "https://teleservices.paris.fr/rdvtitres/JCaptchaImage");

curl_easy_perform(curl);

fclose(fp);
string captcha;
char command[60];
strcpy(command, "open ");
strcat(command, filename);

{
std::lock_guard guard(output_mutex);
std::system(command);
std::cout << std::this_thread::get_id() << '\t' << date << ' ' << filename << '\n' << '\t' << "Enter Captcha: ";
std::cin >> captcha;
}


multipart = curl_mime_init(curl);
part = curl_mime_addpart(multipart);
curl_mime_name(part, "page");
curl_mime_data(part, "appointment", CURL_ZERO_TERMINATED);

part = curl_mime_addpart(multipart);
curl_mime_name(part, "action");
curl_mime_data(part, "doMakeAppointment", CURL_ZERO_TERMINATED);

part = curl_mime_addpart(multipart);
curl_mime_name(part, "lastname");
curl_mime_data(part, hmap["lastname"].c_str(), CURL_ZERO_TERMINATED);

part = curl_mime_addpart(multipart);
curl_mime_name(part, "firstname");
curl_mime_data(part, hmap["firstname"].c_str(), CURL_ZERO_TERMINATED);

part = curl_mime_addpart(multipart);
curl_mime_name(part, "email");
curl_mime_data(part, email.c_str(), CURL_ZERO_TERMINATED);

part = curl_mime_addpart(multipart);
curl_mime_name(part, "anchor");
curl_mime_data(part, "step5", CURL_ZERO_TERMINATED);

part = curl_mime_addpart(multipart);
curl_mime_name(part, "j_captcha_response");
curl_mime_data(part, captcha.c_str(), CURL_ZERO_TERMINATED);

part = curl_mime_addpart(multipart);
curl_mime_name(part, "jcaptchahoneypot");
curl_mime_data(part, "", CURL_ZERO_TERMINATED);

part = curl_mime_addpart(multipart);
curl_mime_name(part, "validate");
curl_mime_data(part, "validate", CURL_ZERO_TERMINATED);

buffer.clear();
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, NULL);
curl_easy_setopt(curl, CURLOPT_MIMEPOST, multipart);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writer);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
char url1[150];
sprintf(url1, "https://teleservices.paris.fr/rdvtitres/jsp/site/Portal.jsp?page=appointment&view=getAppointmentCreated&id_form=%s&anchor=", id3.c_str());
curl_easy_setopt(curl, CURLOPT_URL, url1);

CURLcode res = curl_easy_perform(curl);

remove(filename);
//printf("%s\n", buffer.c_str());

if ( res == CURLE_OK ) {
long response_code;
char* url = NULL;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &url);

if (response_code == 200 && RE2::PartialMatch(url, "getAppointmentCreated")) {
break;
}

}

}

curl_easy_cleanup(curl);

}


int main(int argc, char *argv[])
{

std::ifstream file;
file.open("../data.txt");
string line;

if(file.is_open()){
while(std::getline(file, line)) {
std::istringstream iss(line);
string key, value;

iss >> key;
iss >> value;
hmap[key] = value;
}
}
else{
fprintf(stderr, "Failed to open file \'data.txt\'.\n");
exit(EXIT_FAILURE);
}

curl_global_init(CURL_GLOBAL_DEFAULT);

unsigned int nt = argc>1 ? atoi(argv[0]):std::thread::hardware_concurrency();
std::vector<std::thread> threads;

for (uint j=0; j<1; ++j) {
threads.push_back(std::thread(book));
}

book();

for (auto& th : threads) {
th.join();
}

threads.clear();

curl_global_cleanup();

return EXIT_SUCCESS;

}

0 comments on commit b2ede54

Please sign in to comment.