Last active
December 5, 2023 00:43
-
-
Save Kansattica/5cdd58600393e82c475d183842b3a03d to your computer and use it in GitHub Desktop.
gay little cgi script hit counter
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
// compile with g++ counter.cpp --std=c++17 -O2 -o counter | |
// if your server does multiple CGI requests at once, define MULTI_CGI, e.g.: | |
// g++ counter.cpp --std=c++17 -DMULTI_CGI -O2 -o counter | |
#include <iostream> | |
#include <stdio.h> | |
#include <unordered_map> | |
#include <string> | |
#include <cstring> | |
#include <fstream> | |
#include <charconv> | |
#ifdef MULTI_CGI | |
#include <fcntl.h> | |
#include <sys/file.h> | |
#include <unistd.h> | |
#endif | |
constexpr static const char* countfile = "stor/counts.txt"; | |
std::unordered_map<std::string, size_t> read_count_file() | |
{ | |
std::unordered_map<std::string, size_t> to_return = {}; | |
std::ifstream counts(countfile); | |
if (!counts.is_open()) | |
return to_return; | |
for (std::string line; std::getline(counts, line);) | |
{ | |
const auto sep_idx = line.find('='); | |
if (std::string::npos != sep_idx) | |
{ | |
size_t hit_count = 0; | |
const auto result = std::from_chars(line.c_str()+sep_idx+1, line.c_str()+line.size(), hit_count); | |
if (result.ec == std::errc{}) | |
to_return.emplace(line.substr(0, sep_idx), hit_count); | |
} | |
} | |
return to_return; | |
} | |
void write_count_file(const std::unordered_map<std::string, size_t>& counts) | |
{ | |
std::ofstream count_out_file(countfile); | |
for (const auto& [key, value] : counts) | |
{ | |
count_out_file << key << '=' << value << '\n'; | |
} | |
} | |
std::string getquery() | |
{ | |
const char* envquery = getenv("QUERY_STRING"); | |
if (envquery) | |
return envquery; | |
else | |
return ""; | |
} | |
#ifdef MULTI_CGI | |
int get_file_lock(void) | |
{ | |
int fd = open(countfile, O_CREAT | O_RDONLY); | |
flock(fd, LOCK_EX); | |
return fd; | |
} | |
void release_file_lock(int fd) | |
{ | |
flock(fd, LOCK_UN); | |
close(fd); | |
} | |
#endif | |
int main() | |
{ | |
std::cout << "Content-type: text/plain\n\n"; | |
std::string querystring = getquery(); | |
if (!querystring.empty()) | |
{ | |
//std::cout << "Query string: " << querystring << "\n"; | |
} | |
else | |
{ | |
//std::cout << "No query string :(\n"; | |
std::cout << ":(\n"; | |
return 1; | |
} | |
if (std::string::npos != querystring.find('=')) | |
{ | |
std::cout << ":(\n"; | |
return 1; | |
} | |
#ifdef MULTI_CGI | |
int lockfd = get_file_lock(); | |
#endif | |
auto counts = read_count_file(); | |
auto count_element = counts.find(querystring); | |
if (count_element == counts.end()) | |
{ | |
// didn't find it, make it | |
counts.emplace(querystring, 1); | |
std::cout << 1; | |
} | |
else | |
{ | |
// we found it! | |
count_element->second++; | |
std::cout << count_element->second; | |
} | |
write_count_file(counts); | |
#ifdef MULTI_CGI | |
release_file_lock(lockfd); | |
#endif | |
std::cout << '\n'; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment