Skip to content

Instantly share code, notes, and snippets.

@Kansattica
Last active December 5, 2023 00:43
Show Gist options
  • Save Kansattica/5cdd58600393e82c475d183842b3a03d to your computer and use it in GitHub Desktop.
Save Kansattica/5cdd58600393e82c475d183842b3a03d to your computer and use it in GitHub Desktop.
gay little cgi script hit counter
// 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