Skip to content

Instantly share code, notes, and snippets.

@tsohr
Last active August 29, 2015 14:15
Show Gist options
  • Save tsohr/4385c11e8ad338f881c5 to your computer and use it in GitHub Desktop.
Save tsohr/4385c11e8ad338f881c5 to your computer and use it in GitHub Desktop.
tomcat_rewrite
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <vector>
#include <iterator>
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#include <cctype>
#include <locale>
#include <chrono>
#include <thread>
#include <mutex>
#include <algorithm>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xpath.h>
#include <curl/curl.h>
using namespace std;
static const char* TOMCAT_APPS = "http://localhost:8080/manager/text/list";
static const char* TOMCAT_CONF_XML = "/etc/tomcat/tomcat-users.xml";
static const char* TOMCAT_CONV_XPATH = "/tomcat-users/user[contains(@roles,\"admin\")]";
static bool firstfetch = false;
static std::mutex g_pages_mutex;
static ofstream of_log ("/var/log/tomcat-rewrite.log", std::ios_base::app | std::ios_base::out);
xmlDocPtr getdoc (const char *docname) {
xmlDocPtr doc;
doc = xmlParseFile(docname);
if (doc == NULL ) {
fprintf(stderr,"Document not parsed successfully. \n");
return NULL;
}
return doc;
}
xmlXPathObjectPtr getnodeset (xmlDocPtr doc, xmlChar *xpath){
xmlXPathContextPtr context;
xmlXPathObjectPtr result;
context = xmlXPathNewContext(doc);
if (context == NULL) {
printf("Error in xmlXPathNewContext\n");
return NULL;
}
result = xmlXPathEvalExpression(xpath, context);
xmlXPathFreeContext(context);
if (result == NULL) {
printf("Error in xmlXPathEvalExpression\n");
return NULL;
}
if(xmlXPathNodeSetIsEmpty(result->nodesetval)){
xmlXPathFreeObject(result);
printf("No result\n");
return NULL;
}
return result;
}
size_t writefunc(void *ptr, size_t size, size_t nmemb, string * s)
{
(*s) += (char *) ptr;
return size*nmemb;
}
static inline std::string &ltrim(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
return s;
}
static inline std::string &rtrim(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
return s;
}
static inline std::string &trim(std::string &s) {
return ltrim(rtrim(s));
}
std::vector<std::string> &split(const std::string &s, const char delim, std::vector<std::string> &elems) {
std::stringstream ss(s);
std::string item;
while (std::getline(ss, item, delim)) {
elems.push_back(item);
}
return elems;
}
std::vector<std::string> split(const std::string &s, const char delim) {
std::vector<std::string> elems;
split(s, delim, elems);
return elems;
}
vector<string> removeempty(const vector<string>& vt) {
vector<string> n;
for (const string & s : vt) {
string trimmed = s;
trimmed = trim(trimmed);
if (trimmed.length() > 0)
n.push_back(trimmed);
}
return n;
}
ostream& timestamp(ostream& os) {
time_t ltime;
struct tm *Tm;
ltime=time(NULL);
Tm=localtime(&ltime);
char buf[50] = {0,};
sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d",
Tm->tm_year+1900,
Tm->tm_mon+1,
Tm->tm_mday,
Tm->tm_hour,
Tm->tm_min,
Tm->tm_sec);
os << buf << "\t";
return os;
}
const int curl_retry_limit = 10;
int curl_retry_count = 0;
void getdeployed(vector<string> & deployed) {
xmlDocPtr doc = getdoc(TOMCAT_CONF_XML);
if (doc == NULL) {
exit(-1);
return;
}
xmlXPathObjectPtr result = getnodeset(doc,(xmlChar*) TOMCAT_CONV_XPATH);
if (result == NULL) {
exit(-1);
return;
}
xmlNodeSetPtr nodeset = result->nodesetval;
if (nodeset == NULL) {
exit(-1);
return;
}
if (nodeset->nodeNr != 1) {
of_log << "nodeNr not matched\n" << endl;
exit(-1);
return;
}
xmlNode& node = **(nodeset->nodeTab);
string user = "undefined";
string pass = "undefined";
for (xmlAttr* nodeAttr = node.properties; nodeAttr != NULL; nodeAttr = nodeAttr->next) {
const string attrName = string((const char *)nodeAttr->name);
const string attrValue = string((const char *)nodeAttr->children->content);
if (attrName.compare("name") == 0) {
user.assign(attrValue);
continue;
}
if (attrName.compare("password") == 0) {
pass.assign(attrValue);
continue;
}
continue;
}
xmlFreeDoc(doc);
xmlCleanupParser();
curl_global_init(CURL_GLOBAL_ALL);
CURL* curl = curl_easy_init();
if (curl == NULL) {
of_log << "cannot init curl\n" << endl;
exit(-2);
return;
}
string chunk = "";
curl_easy_setopt(curl, CURLOPT_URL, TOMCAT_APPS);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunc);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &chunk);
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_easy_setopt(curl, CURLOPT_USERNAME, user.c_str());
curl_easy_setopt(curl, CURLOPT_PASSWORD, pass.c_str());
CURLcode res = curl_easy_perform(curl);
if(res != CURLE_OK) {
timestamp(of_log)
<< "curl_easy_perform() failed: " << curl_easy_strerror(res) << "\t"
<< "remaining retry count: " << (curl_retry_limit-curl_retry_count) << endl;
curl_retry_count ++;
if (curl_retry_count == curl_retry_limit) {
timestamp(of_log)
<< "retry count exhausted. exit...";
exit(-3);
}
return;
}
curl_easy_cleanup(curl);
curl_global_cleanup();
curl_retry_count = 0;
istringstream iss(chunk);
vector<string> buf;
while (! iss.eof()) {
string line;
iss >> line;
vector<string> x = split(line, ':');
if (x.size() != 4)
continue;
if (x[0].substr(0, 1).compare("/") != 0)
continue;
if (x[3].compare("ROOT") == 0)
continue;
buf.push_back(x[0].substr(1,string::npos));
}
firstfetch = true;
g_pages_mutex.lock();
deployed.clear();
// timestamp(of_log) << "deployed: \t" ;
for (string & d : buf) {
// of_log << d << " ";
deployed.push_back(d);
}
// of_log << endl;
g_pages_mutex.unlock();
}
void getdeployedloop(void * ptrdeployed) {
vector<string> & deployed = *((vector<string> *)(ptrdeployed));
while(1) {
getdeployed(deployed);
std::this_thread::sleep_for(std::chrono::seconds(20));
}
}
int main(int argc, char** argv) {
LIBXML_TEST_VERSION;
vector<string> deployed;
std::thread fetchdeployed (getdeployedloop, &deployed);
while (! firstfetch)
std::this_thread::sleep_for(std::chrono::seconds(1));
while (!cin.eof()) {
string line;
std::getline(cin, line);
vector<string> reqdirvt = removeempty(split(line, '/'));
string reqdir = "";
string answer = "0";
if (reqdirvt.size() > 0)
reqdir = reqdirvt[0];
g_pages_mutex.lock();
timestamp(of_log) << "\t" << reqdir << "\t";
for (string& d : deployed) {
if (d.compare(reqdir) == 0) {
answer = "1";
break;
}
}
g_pages_mutex.unlock();
of_log << answer << endl;
cout << answer << endl;
}
exit(EXIT_SUCCESS);
return 0;
}
tomcat-rewrite: tomcat-rewrite.cpp
g++ tomcat-rewrite.cpp -o tomcat-rewrite -std=c++11 `xml2-config --cflags --libs` `curl-config --cflags --libs`
chmod 711 tomcat-rewrite
# Take higher priority to the apache server content first.
# And then relay next to the Tomcat server.
# NOTE: Symlinks will be needed under DOCUMENT_ROOT for aliased
# resources such as phpMyAdmin, phpPgAdmin, ...
#LogLevel alert rewrite:trace6
RewriteEngine On
RewriteMap take_tomcat prg:/etc/httpd/conf.d/tomcat-rewrite
RewriteCond ${take_tomcat:%{REQUEST_FILENAME}} -eq1
RewriteRule ^/(.*) ajp://localhost:8009/$1 [P,last]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment