/*
* Copyright (c) 1999-2008 Caucho Technology. All rights reserved.
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*/
/*
* config.c is responsible for scanning the parsed registry and grabbing
* relevant data.
*
* Important data include the web-app and the servlet-mapping so any filter
* can properly dispatch the request.
*
* Also, config.c needs to grab the srun and srun-backup blocks to properly
* send the requests to the proper JVM.
*/
#ifdef WIN32
#include <winsock2.h>
#include <fcntl.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <sys/stat.h>
#include <errno.h>
#include "cse.h"
#define CACHE_SIZE 16384
#define AUTO_WRITE_TIME (15 * 60)
#define DEFAULT_HOST_MAX 256
#define HMUX_DISPATCH_QUERY 'q'
#define HMUX_DISPATCH_QUERY_CLUSTER 's'
#define HMUX_DISPATCH_HOST 'h'
#define HMUX_DISPATCH_WEB_APP 'a'
#define HMUX_DISPATCH_MATCH 'm'
#define HMUX_DISPATCH_IGNORE 'i'
#define HMUX_DISPATCH_ETAG 'e'
#define HMUX_DISPATCH_NO_CHANGE 'n'
#define HMUX_DISPATCH_SRUN 's'
typedef struct hash_t {
char *host;
int port;
char *uri;
resin_host_t *match_host;
volatile int count;
volatile int update_count;
} hash_t;
static int g_update_count;
static hash_t g_url_cache[CACHE_SIZE];
static resin_host_t *
cse_match_host_impl(config_t *config, const char *host_name,
int port, time_t now);
static int
resin_atoi(char *s)
{
int sign = 1;
int value = 0;
if (*s == '-') {
sign = -1;
s++;
}
else if (*s == '+') {
s++;
}
for (; *s && '0' <= *s && *s <= '9'; s++) {
value = 10 * value + *s - '0';
if (value < 0 || value > 0x3fffffff)
return sign * 0x3fffffff;
}
return sign * value;
}
static location_t *
cse_add_unique_location(mem_pool_t *pool, web_app_t *app, char *prefix,
char *suffix, int is_exact, int ignore)
{
location_t *loc;
for (loc = app->locations; loc; loc = loc->next) {
if (is_exact != loc->is_exact)
continue;
else if ((prefix == 0) != (loc->prefix == 0))
continue;
else if (prefix && strcmp(prefix, loc->prefix))
continue;
else if ((suffix == 0) != (loc->suffix == 0))
continue;
else if (suffix && strcmp(suffix, loc->suffix))
continue;
return loc;
}
loc = (location_t *) cse_alloc(pool, sizeof(location_t));
memset(loc, 0, sizeof(location_t));
loc->next = app->locations;
app->locations = loc;
loc->application = app;
loc->prefix = prefix;
loc->suffix = suffix;
loc->is_exact = is_exact;
loc->ignore = ignore;
LOG(("%s:%d:cse_add_unique_location(): loc %s %s %x %s\n",
__FILE__, __LINE__,
loc->prefix ? loc->prefix : "(null)",
loc->suffix ? loc->suffix : "(null)",
loc->next,
loc->ignore ? "ignore" : ""));
return loc;
}
static web_app_t *
cse_add_web_app(mem_pool_t *pool, resin_host_t *host,
web_app_t *applications, char *context_path)
{
web_app_t *app;
if (! context_path)
context_path = "";
else if (! strcmp(context_path, "/"))
context_path = "";
for (app = applications; app; app = app->next) {
if (strcmp(context_path, app->context_path))
continue;
return app;
}
app = (web_app_t *) cse_alloc(pool, sizeof(web_app_t));
memset(app, 0, sizeof(web_app_t));
app->next = applications;
applications = app;
app->host = host;
/* defaults to having data. Set false if web-app is unavailable */
app->has_data = 1;
app->context_path = cse_strdup(pool, context_path);
LOG(("%s:%d:cse_add_web_app(): new web-app host:%s path:%s\n",
__FILE__, __LINE__, host->name, app->context_path));
return applications;
}
/**
* Add an application pattern to the list of recognized locations
*
* @param config the configuration
* @param host the host for the pattern
* @param prefix the web-app prefix
*
* @return the new application
*/
static web_app_t *
cse_add_application(mem_pool_t *pool, resin_host_t *host,
web_app_t *applications, char *prefix)
{
char loc_prefix[8192];
int i, j;
i = 0;
if (prefix && *prefix && *prefix != '/')
loc_prefix[i++] = '/';
#ifdef WIN32
if (prefix) {
for (j = 0; prefix[j]; j++)
loc_prefix[i++] = tolower(prefix[j]);
}
#else
if (prefix) {
for (j = 0; prefix[j]; j++)
loc_prefix[i++] = prefix[j];
}
#endif
loc_prefix[i] = 0;
return cse_add_web_app(pool, host, applications, loc_prefix);
}
/**
* Add a location pattern to the list of recognized locations
*
* @param app the containing application
* @param pattern the url-pattern to match
*
* @return the new location
*/
static void
cse_add_location(mem_pool_t *pool, web_app_t *app,
char *pattern, char *servlet_name)
{
char cleanPrefix[4096];
int prefixLength;
int cleanLength;
char *loc_prefix = 0;
char *loc_suffix = 0;
int loc_is_exact = 0;
int ignore = 0;
#ifdef WIN32
if (pattern) {
int i;
pattern = cse_strdup(pool, pattern);
for (i = 0; pattern[i]; i++)
pattern[i] = tolower(pattern[i]);
}
#endif /* WIN32 */
cleanPrefix[0] = 0;
if (pattern[0] && pattern[0] != '/' && pattern[0] != '*')
strcpy(cleanPrefix, "/");
prefixLength = strlen(cleanPrefix);
if (prefixLength > 0 && cleanPrefix[prefixLength - 1] == '/')
cleanPrefix[prefixLength - 1] = 0;
if (! pattern[0]) {
loc_prefix = cse_strdup(pool, cleanPrefix);
loc_suffix = 0;
}
else if (pattern[0] == '*') {
loc_prefix = cse_strdup(pool, cleanPrefix);
loc_suffix = cse_strdup(pool, pattern + 1);
}
else {
if (pattern[0] != '/')
strcat(cleanPrefix, "/");
strcat(cleanPrefix, pattern);
cleanLength = strlen(cleanPrefix);
if (strlen(pattern) <= 1)
cleanPrefix[cleanLength - 1] = 0;
else if (cleanPrefix[cleanLength - 1] != '*')
loc_is_exact = 1;
else if (cleanLength >= 2 && cleanPrefix[cleanLength - 2] == '/')
cleanPrefix[cleanLength - 2] = 0;
else if (cleanLength > 1)
cleanPrefix[cleanLength - 1] = 0;
loc_prefix = cse_strdup(pool, cleanPrefix);
loc_suffix = 0;
}
if (servlet_name && ! strcmp(servlet_name, "plugin_ignore"))
ignore = 1;
cse_add_unique_location(pool, app, loc_prefix, loc_suffix,
loc_is_exact, ignore);
}
/**
* Add a url-pattern to the list of matching locations.
*
* @param app the containing application
* @param pattern the url-pattern to match
*
* @return the new location
*/
static void
cse_add_match_pattern(mem_pool_t *pool, web_app_t *app, char *pattern)
{
cse_add_location(pool, app, pattern, "plugin_match");
}
/**
* Add a url-pattern to the list of matching locations.
*
* @param app the containing application
* @param pattern the url-pattern to match
*
* @return the new location
*/
static void
cse_add_ignore_pattern(mem_pool_t *pool, web_app_t *app, char *pattern)
{
c