Last active
August 29, 2015 14:15
-
-
Save tsohr/4385c11e8ad338f881c5 to your computer and use it in GitHub Desktop.
tomcat_rewrite
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
#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 <rim(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(<ime); | |
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; | |
} | |
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
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 |
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
# 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