在互联网应用中都会面对多线负载与策略的问题,nginx cross isp module提供了一种简单的解决方案。
nginx cross isp module是基于nginx(http://nginx.org/)开发的,完全用c语言编写,借助于linux系统与nginx强大的功能与性能。
nginx cross isp module的主要逻辑很简单,根据访问用户的ip,从isp数据中查找,如果找到符合条件的,则根据配置,重新定向与相对应的链接地址。isp数据存在mysql中,由于isp数据一般不会经常变化,所以是nginx启动时,一次性读入。如果数据变更,可以重新启动nginx。
在实际应用中,需要为每个isp配置不同的域名,可以是二级域名。以下是nginx cross isp module的所有源码:
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
#include <ngx_regex.h>
#include <pcre.h>
#include <my_global.h>
#include <mysql.h>
#define HTTP_COOKIES_MAX_EXPIRES 2145916555
#define HTTP_DOMAIN_COOKIE_NAME_LEN (size_t) 6
#define HTTP_SCHEMA_LEN (size_t) 7
#define HTTPS_SCHEMA_LEN (size_t) 8
typedef struct
{
ngx_uint_t ip_start;
ngx_uint_t ip_end;
u_char isp[3];
} ngx_isp_store_t;
typedef struct
{
u_char isp[3];
ngx_regex_t *regex;
ngx_str_t pattern;
ngx_str_t replace;
ngx_str_t domain;
} ngx_isp_domain_t;
typedef struct
{
ngx_regex_t *regex;
ngx_str_t pattern;
} ngx_isp_proxy_t;
typedef struct
{
ngx_str_t host;
ngx_int_t port;
ngx_str_t usr;
ngx_str_t pwd;
ngx_str_t db;
ngx_str_t tb;
ngx_str_t isp_rhost_cookie_name;
ngx_str_t isp_taddr_cookie_name;
time_t isp_cookies_expires;
ngx_array_t isp_store;
ngx_array_t isp_domains;
ngx_array_t isp_proxies;
} ngx_http_cross_isp_main_conf_t;
static u_char ngx_http_domain_cookie_name[] = "domain";
static u_char ngx_http_cookies_expires[] =
"; expires=Thu, 31-Dec-37 23:55:55 GMT";
static u_char ngx_http_schema[] = "http://";
static u_char ngx_https_schema[] = "https://";
static u_char ngx_http_302_page[] = "<html><head>" CRLF
"<title>302 Redirect</title></head>" CRLF
"<body><center><h1>302 Redirect</h1>" CRLF "</center></body></html>" CRLF;
static ngx_int_t ngx_http_cross_isp_init (ngx_conf_t * cf);
static void *ngx_http_cross_isp_create_main_conf (ngx_conf_t * cf);
static char *ngx_http_cross_isp_init_main_conf (ngx_conf_t * cf, void *conf);
static char *ngx_conf_set_isp_cookies_expires (ngx_conf_t * cf,
ngx_command_t * cmd,
void *conf);
static char *ngx_conf_set_isp_domain (ngx_conf_t * cf, ngx_command_t * cmd,
void *conf);
static char *ngx_conf_set_isp_proxy (ngx_conf_t * cf, ngx_command_t * cmd,
void *conf);
static ngx_int_t ngx_http_cross_isp_handler (ngx_http_request_t * r);
static long ngx_isp_store_binary_search (ngx_array_t data, ngx_uint_t ip);
static ngx_int_t ngx_cross_isp_redirect (ngx_http_request_t * r,
ngx_str_t url);
static void ngx_http_write_isp_cookie (ngx_http_request_t * r,
u_char * cookie);
static ngx_command_t ngx_http_cross_isp_commands[] = {
{
ngx_string ("isp_store_host"),
NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_MAIN_CONF_OFFSET,
offsetof (ngx_http_cross_isp_main_conf_t, host),
NULL},
{
ngx_string ("isp_store_port"),
NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
NGX_HTTP_MAIN_CONF_OFFSET,
offsetof (ngx_http_cross_isp_main_conf_t, port),
NULL},
{
ngx_string ("isp_store_usr"),
NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_MAIN_CONF_OFFSET,
offsetof (ngx_http_cross_isp_main_conf_t, usr),
NULL},
{
ngx_string ("isp_store_pwd"),
NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_MAIN_CONF_OFFSET,
offsetof (ngx_http_cross_isp_main_conf_t, pwd),
NULL},
{
ngx_string ("isp_store_db"),
NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_MAIN_CONF_OFFSET,
offsetof (ngx_http_cross_isp_main_conf_t, db),
NULL},
{
ngx_string ("isp_store_tb"),
NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_MAIN_CONF_OFFSET,
offsetof (ngx_http_cross_isp_main_conf_t, tb),
NULL},
{
ngx_string ("isp_rhost_cookie_name"),
NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_MAIN_CONF_OFFSET,
offsetof (ngx_http_cross_isp_main_conf_t, isp_rhost_cookie_name),
NULL},
{
ngx_string ("isp_taddr_cookie_name"),
NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_MAIN_CONF_OFFSET,
offsetof (ngx_http_cross_isp_main_conf_t, isp_taddr_cookie_name),
NULL},
{
ngx_string ("isp_cookies_expires"),
NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1,
ngx_conf_set_isp_cookies_expires,
NGX_HTTP_MAIN_CONF_OFFSET,
offsetof (ngx_http_cross_isp_main_conf_t, isp_cookies_expires),
NULL},
{
ngx_string ("isp_domain"),
NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE4,
ngx_conf_set_isp_domain,
NGX_HTTP_MAIN_CONF_OFFSET,
offsetof (ngx_http_cross_isp_main_conf_t, isp_domains),
NULL},
{
ngx_string ("cross_isp"),
NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1,
ngx_conf_set_isp_proxy,
NGX_HTTP_MAIN_CONF_OFFSET,
offsetof (ngx_http_cross_isp_main_conf_t, isp_proxies),
NULL},
ngx_null_command
};
static ngx_http_module_t ngx_http_cross_isp_module_ctx = {
NULL, /* preconfiguration */
ngx_http_cross_isp_init, /* postconfiguration */
ngx_http_cross_isp_create_main_conf, /* create main configuration */
ngx_http_cross_isp_init_main_conf, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
NULL, /* create location configuration */
NULL /* merge location configuration */
};
ngx_module_t ngx_http_cross_isp_module = {
NGX_MODULE_V1,
&ngx_http_cross_isp_module_ctx, /* module context */
ngx_http_cross_isp_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static ngx_int_t
ngx_http_cross_isp_init (ngx_conf_t * cf)
{
ngx_http_handler_pt *h;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_conf_get_module_main_conf (cf, ngx_http_core_module);
h = ngx_array_push (&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers);
if (h == NULL)
{
return NGX_ERROR;
}
*h = ngx_http_cross_isp_handler;
return NGX_OK;
}
static void *
ngx_http_cross_isp_create_main_conf (ngx_conf_t * cf)
{
ngx_http_cross_isp_main_conf_t *iscf;
iscf = ngx_pcalloc (cf->pool, sizeof (ngx_http_cross_isp_main_conf_t));
if (iscf == NULL)
{
return NGX_CONF_ERROR;
}
if (ngx_array_init
(&iscf->isp_store, cf->pool, 20000, sizeof (ngx_isp_store_t)) != NGX_OK)
{
return NGX_CONF_ERROR;
}
if (ngx_array_init
(&iscf->isp_domains, cf->pool, 10, sizeof (ngx_isp_domain_t)) != NGX_OK)
{
return NGX_CONF_ERROR;
}
if (ngx_array_init
(&iscf->isp_proxies, cf->pool, 100, sizeof (ngx_isp_proxy_t)) != NGX_OK)
{
return NGX_CONF_ERROR;
}
iscf->port = NGX_CONF_UNSET_UINT;
iscf->isp_cookies_expires = NGX_CONF_UNSET;
return iscf;
}
static char *
ngx_http_cross_isp_init_main_conf (ngx_conf_t * cf, void *conf)
{
MYSQL *conn = NULL;
MYSQL_RES *result = NULL;
MYSQL_ROW row;
char query[80];
ngx_isp_store_t *elt;
ngx_http_cross_isp_main_conf_t *iscf = conf;
sprintf (query,
"SELECT `ip_start`,`ip_end`,`isp` FROM `%s` ORDER BY `ip_start`",
(char *) iscf->tb.data);
conn = mysql_init (NULL);
if (conn == NULL)
{
ngx_conf_log_error (NGX_LOG_EMERG,
cf,
0,
"init mysql error(host: %V port:%d user: %V password: %V database: %V table:%V)",
iscf->host, iscf->port, iscf->pwd, iscf->db,
iscf->tb);
}
mysql_real_connect (conn, (char *) iscf->host.data, (char *) iscf->usr.data,
(char *) iscf->pwd.data, (char *) iscf->db.data,
(unsigned int) iscf->port, NULL, 0);
mysql_real_query (conn, query, strlen (query));
result = mysql_store_result (conn);
if (result == NULL)
{
ngx_conf_log_error (NGX_LOG_EMERG,
cf,
0,
"can not get isp data from mysql(host: %V port:%d user: %V password: %V database: %V table:%V)",
iscf->host, iscf->port, iscf->pwd, iscf->db,
iscf->tb);
return NGX_CONF_ERROR;
}
while ((row = mysql_fetch_row (result)))
{
elt = (ngx_isp_store_t *) ngx_array_push (&iscf->isp_store);
elt->ip_start = strtol (row[0], NULL, 10);
elt->ip_end = strtol (row[1], NULL, 10);
ngx_strlow (elt->isp, (u_char *) row[2], 3);
}
mysql_free_result (result);
mysql_close (conn);
return NGX_CONF_OK;
}
static char *
ngx_conf_set_isp_cookies_expires (ngx_conf_t * cf, ngx_command_t * cmd,
void *conf)
{
ngx_http_cross_isp_main_conf_t *iscf = conf;
ngx_str_t *value;
if (iscf->isp_cookies_expires != NGX_CONF_UNSET)
{
return "is duplicate";
}
value = cf->args->elts;
if (ngx_strcmp (value[1].data, "max") == 0)
{
iscf->isp_cookies_expires = HTTP_COOKIES_MAX_EXPIRES;
return NGX_CONF_OK;
}
if (ngx_strcmp (value[1].data, "off") == 0)
{
iscf->isp_cookies_expires = 0;
return NGX_CONF_OK;
}
iscf->isp_cookies_expires = ngx_parse_time (&value[1], 1);
if (iscf->isp_cookies_expires == NGX_ERROR)
{
return "invalid value";
}
if (iscf->isp_cookies_expires == NGX_PARSE_LARGE_TIME)
{
return "value must be less than 68 years";
}
return NGX_CONF_OK;
}
static char *
ngx_conf_set_isp_domain (ngx_conf_t * cf, ngx_command_t * cmd, void *conf)
{
ngx_regex_compile_t rc;
u_char errstr[NGX_MAX_CONF_ERRSTR];
char *p = conf;
ngx_isp_domain_t *s;
ngx_str_t *value;
ngx_array_t *a;
a = (ngx_array_t *) (p + cmd->offset);
s = ngx_array_push (a);
if (s == NULL)
{
return NGX_CONF_ERROR;
}
value = cf->args->elts;
ngx_strlow (s->isp, value[1].data, 3);
s->pattern = value[2];
s->replace = value[3];
s->domain = value[4];
ngx_memzero (&rc, sizeof (ngx_regex_compile_t));
rc.pattern = s->pattern;
rc.pool = cf->pool;
rc.err.len = NGX_MAX_CONF_ERRSTR;
rc.err.data = errstr;
if (ngx_regex_compile (&rc) != NGX_OK)
{
ngx_conf_log_error (NGX_LOG_EMERG, cf, 0, "%V", &rc.err);
return NGX_CONF_ERROR;
}
s->regex = rc.regex;
if (s->regex == NULL)
{
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}
static char *
ngx_conf_set_isp_proxy (ngx_conf_t * cf, ngx_command_t * cmd, void *conf)
{
ngx_regex_compile_t rc;
u_char errstr[NGX_MAX_CONF_ERRSTR];
char *p = conf;
ngx_isp_proxy_t *s;
ngx_str_t *value;
ngx_array_t *a;
a = (ngx_array_t *) (p + cmd->offset);
s = ngx_array_push (a);
if (s == NULL)
{
return NGX_CONF_ERROR;
}
value = cf->args->elts;
s->pattern = value[1];
ngx_memzero (&rc, sizeof (ngx_regex_compile_t));
rc.pattern = s->pattern;
rc.pool = cf->pool;
rc.err.len = NGX_MAX_CONF_ERRSTR;
rc.err.data = errstr;
if (ngx_regex_compile (&rc) != NGX_OK)
{
ngx_conf_log_error (NGX_LOG_EMERG, cf, 0, "%V", &rc.err);
return NGX_CONF_ERROR;
}
s->regex = rc.regex;
if (s->regex == NULL)
{
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}
static ngx_int_t
ngx_http_cross_isp_handler (ngx_http_request_t * r)
{
ngx_http_cross_isp_main_conf_t *ipmcf;
ngx_int_t pc1 = NGX_DECLINED, pc2 = NGX_DECLINED, ssl, rc;
ngx_uint_t i, m;
ngx_uint_t ip;
ngx_str_t str_uri;
ngx_str_t isp_rhost_cookie, isp_taddr_cookie;
ngx_isp_proxy_t *ipt;
ngx_isp_store_t *ist;
ngx_isp_domain_t *idt;
u_char *u_uri, *u_relative_uri, *p, *u_isp_rhost_cookie,
*u_isp_taddr_cookie, *taddr;
struct sockaddr_in *sin;
size_t str_uri_len, str_relative_uri_len, con_schema_len, taddr_len,
cookie_expires_len;
char *pt;
long ip_pos;
int cmp_r1, cmp_r2;
ipmcf = ngx_http_get_module_main_conf (r, ngx_http_cross_isp_module);
ipt = ipmcf->isp_proxies.elts;
for (i = 0; i < ipmcf->isp_proxies.nelts; i++)
{
rc = ngx_regex_exec (ipt[i].regex, &r->uri, NULL, 0);
if (rc == NGX_REGEX_NO_MATCHED)
{
continue;
}
pc1 =
ngx_http_parse_multi_header_lines (&r->headers_in.cookies,
&ipmcf->isp_rhost_cookie_name,
&isp_rhost_cookie);
pc2 =
ngx_http_parse_multi_header_lines (&r->headers_in.cookies,
&ipmcf->isp_taddr_cookie_name,
&isp_taddr_cookie);
sin = (struct sockaddr_in *) (r->connection->sockaddr);
ip = ntohl (sin->sin_addr.s_addr);
pt = inet_ntoa (sin->sin_addr);
if (pt == NULL)
{
ngx_log_error (NGX_LOG_ERR,
r->connection->log, 0, "inet_ntoa get taddr error");
return NGX_DECLINED;
}
taddr_len = strlen (pt);
taddr = ngx_pcalloc (r->pool, taddr_len * sizeof (u_char));
if (taddr == NULL)
{
ngx_log_error (NGX_LOG_ERR,
r->connection->log,
0, "ngx_pcalloc no args taddr error");
return NGX_DECLINED;
}
p = ngx_copy (taddr, pt, taddr_len);
cmp_r1 =
ngx_strncmp (isp_rhost_cookie.data, r->headers_in.host->value.data,
isp_rhost_cookie.len);
cmp_r2 =
ngx_strncmp (isp_taddr_cookie.data, taddr, isp_taddr_cookie.len);
if (pc1 != NGX_DECLINED && cmp_r1 == 0 && pc2 != NGX_DECLINED
&& cmp_r2 == 0)
{
return NGX_DECLINED;
}
ip_pos = ngx_isp_store_binary_search (ipmcf->isp_store, ip);
if (ip_pos == -1)
{
return NGX_DECLINED;
}
ist = ipmcf->isp_store.elts;
idt = ipmcf->isp_domains.elts;
for (m = 0; m < ipmcf->isp_domains.nelts; m++)
{
if (ngx_strcmp (idt[m].isp, ist[ip_pos].isp) == 0)
{
rc = ngx_regex_exec (idt[m].regex, &r->headers_in.host->value,
NULL, 0);
if (rc >= 0)
{
if (ipmcf->isp_cookies_expires)
{
cookie_expires_len =
sizeof (ngx_http_cookies_expires) - 1;
}
if (pc1 == NGX_DECLINED || cmp_r1 != 0)
{
u_isp_rhost_cookie = ngx_pcalloc (r->pool,
(ipmcf->isp_rhost_cookie_name.len
+ 1 +
r->headers_in.
host->value.len +
cookie_expires_len +
1 +
HTTP_DOMAIN_COOKIE_NAME_LEN
+ 1 +
idt[m].domain.len +
1) *
sizeof (u_char));
if (u_isp_rhost_cookie == NULL)
{
ngx_log_error (NGX_LOG_ERR,
r->connection->log,
0,
"ngx_pcalloc no args u_isp_rhost_cookie error");
return NGX_DECLINED;
}
p = ngx_copy (u_isp_rhost_cookie,
ipmcf->isp_rhost_cookie_name.data,
ipmcf->isp_rhost_cookie_name.len);
*p++ = '=';
p = ngx_copy (p, r->headers_in.host->value.data,
r->headers_in.host->value.len);
if (ipmcf->isp_cookies_expires ==
HTTP_COOKIES_MAX_EXPIRES)
{
p =
ngx_copy (p, ngx_http_cookies_expires,
cookie_expires_len);
}
else if (ipmcf->isp_cookies_expires)
{
p =
ngx_copy (p, ngx_http_cookies_expires,
sizeof ("; expires=") - 1);
p =
ngx_http_cookie_time (p,
ngx_time () +
ipmcf->isp_cookies_expires);
}
*p++ = ';';
p = ngx_copy (p, ngx_http_domain_cookie_name,
HTTP_DOMAIN_COOKIE_NAME_LEN);
*p++ = '=';
p = ngx_copy (p, idt[m].domain.data, idt[m].domain.len);
*p++ = '\0';
ngx_http_write_isp_cookie (r, u_isp_rhost_cookie);
}
if (pc2 == NGX_DECLINED || cmp_r2 != 0)
{
u_isp_taddr_cookie = ngx_pcalloc (r->pool,
(ipmcf->isp_taddr_cookie_name.len
+ 1 + taddr_len +
cookie_expires_len +
1 +
HTTP_DOMAIN_COOKIE_NAME_LEN
+ 1 +
idt[m].domain.len +
1) *
sizeof (u_char));
if (u_isp_taddr_cookie == NULL)
{
ngx_log_error (NGX_LOG_ERR,
r->connection->log,
0,
"ngx_pcalloc no args u_isp_taddr_cookie error");
return NGX_DECLINED;
}
p =
ngx_copy (u_isp_taddr_cookie,
ipmcf->isp_taddr_cookie_name.data,
ipmcf->isp_taddr_cookie_name.len);
*p++ = '=';
p = ngx_copy (p, taddr, taddr_len);
if (ipmcf->isp_cookies_expires ==
HTTP_COOKIES_MAX_EXPIRES)
{
p =
ngx_copy (p, ngx_http_cookies_expires,
cookie_expires_len);
}
else if (ipmcf->isp_cookies_expires)
{
p =
ngx_copy (p, ngx_http_cookies_expires,
sizeof ("; expires=") - 1);
p =
ngx_http_cookie_time (p,
ngx_time () +
ipmcf->isp_cookies_expires);
}
*p++ = ';';
p =
ngx_copy (p, ngx_http_domain_cookie_name,
HTTP_DOMAIN_COOKIE_NAME_LEN);
*p++ = '=';
p = ngx_copy (p, idt[m].domain.data, idt[m].domain.len);
*p++ = '\0';
ngx_http_write_isp_cookie (r, u_isp_taddr_cookie);
}
return NGX_DECLINED;
}
else
{
ssl = r->connection->ssl == NULL ? 0 : 1;
con_schema_len = ssl ? HTTPS_SCHEMA_LEN : HTTP_SCHEMA_LEN;
if (r->args.data == NULL)
{
u_relative_uri =
ngx_pcalloc (r->pool,
(r->uri.len + 1) * sizeof (u_char));
if (u_relative_uri == NULL)
{
ngx_log_error (NGX_LOG_ERR,
r->connection->log,
0,
"ngx_pcalloc no args u_relative_uri error");
return NGX_DECLINED;
}
p = ngx_copy (u_relative_uri, r->uri.data, r->uri.len);
*p++ = '\0';
}
else
{
u_relative_uri =
ngx_pcalloc (r->pool,
(r->uri.len + r->args.len +
2) * sizeof (u_char));
if (u_relative_uri == NULL)
{
ngx_log_error (NGX_LOG_ERR,
r->connection->log,
0,
"ngx_pcalloc with args u_relative_uri error");
return NGX_DECLINED;
}
p = ngx_copy (u_relative_uri, r->uri.data, r->uri.len);
*p++ = '?';
p = ngx_copy (p, r->args.data, r->args.len);
*p++ = '\0';
}
str_relative_uri_len = ngx_strlen (u_relative_uri);
str_uri_len =
con_schema_len + idt[m].replace.len +
str_relative_uri_len;
u_uri =
ngx_pcalloc (r->pool, str_uri_len * sizeof (u_char));
if (u_uri == NULL)
{
ngx_log_error (NGX_LOG_ERR,
r->connection->log,
0, "ngx_pcalloc no args u_uri error");
return NGX_DECLINED;
}
p =
(ssl ? ngx_copy (u_uri, ngx_https_schema, con_schema_len)
: ngx_copy (u_uri, ngx_http_schema, con_schema_len));
p = ngx_copy (p, idt[m].replace.data, idt[m].replace.len);
p = ngx_copy (p, u_relative_uri, str_relative_uri_len);
str_uri.len = str_uri_len;
str_uri.data = u_uri;
return ngx_cross_isp_redirect (r, str_uri);
}
}
}
}
return NGX_DECLINED;
}
static long
ngx_isp_store_binary_search (ngx_array_t data, ngx_uint_t ip)
{
long low = -1;
long high = data.nelts;
ngx_uint_t mid;
ngx_isp_store_t *ist = data.elts;
while (high - low > 1)
{
mid = (low + high) >> 1;
if (ist[mid].ip_start > ip)
{
high = mid;
}
else
{
low = mid;
}
}
if ((low == -1) || !(ist[low].ip_start <= ip && ip <= ist[low].ip_end))
{
return -1;
}
else
{
return low;
}
}
static ngx_int_t
ngx_cross_isp_redirect (ngx_http_request_t * r, ngx_str_t url)
{
ngx_buf_t *b;
ngx_chain_t out;
size_t ngx_http_302_page_len = ngx_strlen (ngx_http_302_page);
r->headers_out.content_type.len = sizeof ("text/html") - 1;
r->headers_out.content_type.data = (u_char *) "text/html";
b = ngx_pcalloc (r->pool, sizeof (ngx_buf_t));
out.buf = b;
out.next = NULL;
b->pos = ngx_http_302_page;
b->last = ngx_http_302_page + ngx_http_302_page_len;
b->memory = 1;
b->last_buf = 1;
r->headers_out.status = NGX_HTTP_MOVED_TEMPORARILY;
r->headers_out.location = ngx_list_push (&r->headers_out.headers);
r->headers_out.location->hash = 1;
ngx_str_set (&r->headers_out.location->key, "Location");
r->headers_out.location->value = url;
r->headers_out.content_length_n = ngx_http_302_page_len;
ngx_http_send_header (r);
return ngx_http_write_filter (r, &out);
}
static void
ngx_http_write_isp_cookie (ngx_http_request_t * r, u_char * cookie)
{
ngx_table_elt_t *set_cookie;
set_cookie = ngx_list_push (&r->headers_out.headers);
if (set_cookie == NULL)
{
return;
}
set_cookie->hash = 1;
set_cookie->key.len = sizeof ("Set-Cookie") - 1;
set_cookie->key.data = (u_char *) "Set-Cookie";
set_cookie->value.len = ngx_strlen (cookie);
set_cookie->value.data = cookie;
}
nginx cross isp module将会开源在http://code.google.com/p/easy-net/,后期将会对现有功能进行改进。
#include <ngx_core.h>
#include <ngx_http.h>
#include <ngx_regex.h>
#include <pcre.h>
#include <my_global.h>
#include <mysql.h>
#define HTTP_COOKIES_MAX_EXPIRES 2145916555
#define HTTP_DOMAIN_COOKIE_NAME_LEN (size_t) 6
#define HTTP_SCHEMA_LEN (size_t) 7
#define HTTPS_SCHEMA_LEN (size_t) 8
typedef struct
{
ngx_uint_t ip_start;
ngx_uint_t ip_end;
u_char isp[3];
} ngx_isp_store_t;
typedef struct
{
u_char isp[3];
ngx_regex_t *regex;
ngx_str_t pattern;
ngx_str_t replace;
ngx_str_t domain;
} ngx_isp_domain_t;
typedef struct
{
ngx_regex_t *regex;
ngx_str_t pattern;
} ngx_isp_proxy_t;
typedef struct
{
ngx_str_t host;
ngx_int_t port;
ngx_str_t usr;
ngx_str_t pwd;
ngx_str_t db;
ngx_str_t tb;
ngx_str_t isp_rhost_cookie_name;
ngx_str_t isp_taddr_cookie_name;
time_t isp_cookies_expires;
ngx_array_t isp_store;
ngx_array_t isp_domains;
ngx_array_t isp_proxies;
} ngx_http_cross_isp_main_conf_t;
static u_char ngx_http_domain_cookie_name[] = "domain";
static u_char ngx_http_cookies_expires[] =
"; expires=Thu, 31-Dec-37 23:55:55 GMT";
static u_char ngx_http_schema[] = "http://";
static u_char ngx_https_schema[] = "https://";
static u_char ngx_http_302_page[] = "<html><head>" CRLF
"<title>302 Redirect</title></head>" CRLF
"<body><center><h1>302 Redirect</h1>" CRLF "</center></body></html>" CRLF;
static ngx_int_t ngx_http_cross_isp_init (ngx_conf_t * cf);
static void *ngx_http_cross_isp_create_main_conf (ngx_conf_t * cf);
static char *ngx_http_cross_isp_init_main_conf (ngx_conf_t * cf, void *conf);
static char *ngx_conf_set_isp_cookies_expires (ngx_conf_t * cf,
ngx_command_t * cmd,
void *conf);
static char *ngx_conf_set_isp_domain (ngx_conf_t * cf, ngx_command_t * cmd,
void *conf);
static char *ngx_conf_set_isp_proxy (ngx_conf_t * cf, ngx_command_t * cmd,
void *conf);
static ngx_int_t ngx_http_cross_isp_handler (ngx_http_request_t * r);
static long ngx_isp_store_binary_search (ngx_array_t data, ngx_uint_t ip);
static ngx_int_t ngx_cross_isp_redirect (ngx_http_request_t * r,
ngx_str_t url);
static void ngx_http_write_isp_cookie (ngx_http_request_t * r,
u_char * cookie);
static ngx_command_t ngx_http_cross_isp_commands[] = {
{
ngx_string ("isp_store_host"),
NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_MAIN_CONF_OFFSET,
offsetof (ngx_http_cross_isp_main_conf_t, host),
NULL},
{
ngx_string ("isp_store_port"),
NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
NGX_HTTP_MAIN_CONF_OFFSET,
offsetof (ngx_http_cross_isp_main_conf_t, port),
NULL},
{
ngx_string ("isp_store_usr"),
NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_MAIN_CONF_OFFSET,
offsetof (ngx_http_cross_isp_main_conf_t, usr),
NULL},
{
ngx_string ("isp_store_pwd"),
NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_MAIN_CONF_OFFSET,
offsetof (ngx_http_cross_isp_main_conf_t, pwd),
NULL},
{
ngx_string ("isp_store_db"),
NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_MAIN_CONF_OFFSET,
offsetof (ngx_http_cross_isp_main_conf_t, db),
NULL},
{
ngx_string ("isp_store_tb"),
NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_MAIN_CONF_OFFSET,
offsetof (ngx_http_cross_isp_main_conf_t, tb),
NULL},
{
ngx_string ("isp_rhost_cookie_name"),
NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_MAIN_CONF_OFFSET,
offsetof (ngx_http_cross_isp_main_conf_t, isp_rhost_cookie_name),
NULL},
{
ngx_string ("isp_taddr_cookie_name"),
NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_MAIN_CONF_OFFSET,
offsetof (ngx_http_cross_isp_main_conf_t, isp_taddr_cookie_name),
NULL},
{
ngx_string ("isp_cookies_expires"),
NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1,
ngx_conf_set_isp_cookies_expires,
NGX_HTTP_MAIN_CONF_OFFSET,
offsetof (ngx_http_cross_isp_main_conf_t, isp_cookies_expires),
NULL},
{
ngx_string ("isp_domain"),
NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE4,
ngx_conf_set_isp_domain,
NGX_HTTP_MAIN_CONF_OFFSET,
offsetof (ngx_http_cross_isp_main_conf_t, isp_domains),
NULL},
{
ngx_string ("cross_isp"),
NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1,
ngx_conf_set_isp_proxy,
NGX_HTTP_MAIN_CONF_OFFSET,
offsetof (ngx_http_cross_isp_main_conf_t, isp_proxies),
NULL},
ngx_null_command
};
static ngx_http_module_t ngx_http_cross_isp_module_ctx = {
NULL, /* preconfiguration */
ngx_http_cross_isp_init, /* postconfiguration */
ngx_http_cross_isp_create_main_conf, /* create main configuration */
ngx_http_cross_isp_init_main_conf, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
NULL, /* create location configuration */
NULL /* merge location configuration */
};
ngx_module_t ngx_http_cross_isp_module = {
NGX_MODULE_V1,
&ngx_http_cross_isp_module_ctx, /* module context */
ngx_http_cross_isp_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static ngx_int_t
ngx_http_cross_isp_init (ngx_conf_t * cf)
{
ngx_http_handler_pt *h;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_conf_get_module_main_conf (cf, ngx_http_core_module);
h = ngx_array_push (&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers);
if (h == NULL)
{
return NGX_ERROR;
}
*h = ngx_http_cross_isp_handler;
return NGX_OK;
}
static void *
ngx_http_cross_isp_create_main_conf (ngx_conf_t * cf)
{
ngx_http_cross_isp_main_conf_t *iscf;
iscf = ngx_pcalloc (cf->pool, sizeof (ngx_http_cross_isp_main_conf_t));
if (iscf == NULL)
{
return NGX_CONF_ERROR;
}
if (ngx_array_init
(&iscf->isp_store, cf->pool, 20000, sizeof (ngx_isp_store_t)) != NGX_OK)
{
return NGX_CONF_ERROR;
}
if (ngx_array_init
(&iscf->isp_domains, cf->pool, 10, sizeof (ngx_isp_domain_t)) != NGX_OK)
{
return NGX_CONF_ERROR;
}
if (ngx_array_init
(&iscf->isp_proxies, cf->pool, 100, sizeof (ngx_isp_proxy_t)) != NGX_OK)
{
return NGX_CONF_ERROR;
}
iscf->port = NGX_CONF_UNSET_UINT;
iscf->isp_cookies_expires = NGX_CONF_UNSET;
return iscf;
}
static char *
ngx_http_cross_isp_init_main_conf (ngx_conf_t * cf, void *conf)
{
MYSQL *conn = NULL;
MYSQL_RES *result = NULL;
MYSQL_ROW row;
char query[80];
ngx_isp_store_t *elt;
ngx_http_cross_isp_main_conf_t *iscf = conf;
sprintf (query,
"SELECT `ip_start`,`ip_end`,`isp` FROM `%s` ORDER BY `ip_start`",
(char *) iscf->tb.data);
conn = mysql_init (NULL);
if (conn == NULL)
{
ngx_conf_log_error (NGX_LOG_EMERG,
cf,
0,
"init mysql error(host: %V port:%d user: %V password: %V database: %V table:%V)",
iscf->host, iscf->port, iscf->pwd, iscf->db,
iscf->tb);
}
mysql_real_connect (conn, (char *) iscf->host.data, (char *) iscf->usr.data,
(char *) iscf->pwd.data, (char *) iscf->db.data,
(unsigned int) iscf->port, NULL, 0);
mysql_real_query (conn, query, strlen (query));
result = mysql_store_result (conn);
if (result == NULL)
{
ngx_conf_log_error (NGX_LOG_EMERG,
cf,
0,
"can not get isp data from mysql(host: %V port:%d user: %V password: %V database: %V table:%V)",
iscf->host, iscf->port, iscf->pwd, iscf->db,
iscf->tb);
return NGX_CONF_ERROR;
}
while ((row = mysql_fetch_row (result)))
{
elt = (ngx_isp_store_t *) ngx_array_push (&iscf->isp_store);
elt->ip_start = strtol (row[0], NULL, 10);
elt->ip_end = strtol (row[1], NULL, 10);
ngx_strlow (elt->isp, (u_char *) row[2], 3);
}
mysql_free_result (result);
mysql_close (conn);
return NGX_CONF_OK;
}
static char *
ngx_conf_set_isp_cookies_expires (ngx_conf_t * cf, ngx_command_t * cmd,
void *conf)
{
ngx_http_cross_isp_main_conf_t *iscf = conf;
ngx_str_t *value;
if (iscf->isp_cookies_expires != NGX_CONF_UNSET)
{
return "is duplicate";
}
value = cf->args->elts;
if (ngx_strcmp (value[1].data, "max") == 0)
{
iscf->isp_cookies_expires = HTTP_COOKIES_MAX_EXPIRES;
return NGX_CONF_OK;
}
if (ngx_strcmp (value[1].data, "off") == 0)
{
iscf->isp_cookies_expires = 0;
return NGX_CONF_OK;
}
iscf->isp_cookies_expires = ngx_parse_time (&value[1], 1);
if (iscf->isp_cookies_expires == NGX_ERROR)
{
return "invalid value";
}
if (iscf->isp_cookies_expires == NGX_PARSE_LARGE_TIME)
{
return "value must be less than 68 years";
}
return NGX_CONF_OK;
}
static char *
ngx_conf_set_isp_domain (ngx_conf_t * cf, ngx_command_t * cmd, void *conf)
{
ngx_regex_compile_t rc;
u_char errstr[NGX_MAX_CONF_ERRSTR];
char *p = conf;
ngx_isp_domain_t *s;
ngx_str_t *value;
ngx_array_t *a;
a = (ngx_array_t *) (p + cmd->offset);
s = ngx_array_push (a);
if (s == NULL)
{
return NGX_CONF_ERROR;
}
value = cf->args->elts;
ngx_strlow (s->isp, value[1].data, 3);
s->pattern = value[2];
s->replace = value[3];
s->domain = value[4];
ngx_memzero (&rc, sizeof (ngx_regex_compile_t));
rc.pattern = s->pattern;
rc.pool = cf->pool;
rc.err.len = NGX_MAX_CONF_ERRSTR;
rc.err.data = errstr;
if (ngx_regex_compile (&rc) != NGX_OK)
{
ngx_conf_log_error (NGX_LOG_EMERG, cf, 0, "%V", &rc.err);
return NGX_CONF_ERROR;
}
s->regex = rc.regex;
if (s->regex == NULL)
{
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}
static char *
ngx_conf_set_isp_proxy (ngx_conf_t * cf, ngx_command_t * cmd, void *conf)
{
ngx_regex_compile_t rc;
u_char errstr[NGX_MAX_CONF_ERRSTR];
char *p = conf;
ngx_isp_proxy_t *s;
ngx_str_t *value;
ngx_array_t *a;
a = (ngx_array_t *) (p + cmd->offset);
s = ngx_array_push (a);
if (s == NULL)
{
return NGX_CONF_ERROR;
}
value = cf->args->elts;
s->pattern = value[1];
ngx_memzero (&rc, sizeof (ngx_regex_compile_t));
rc.pattern = s->pattern;
rc.pool = cf->pool;
rc.err.len = NGX_MAX_CONF_ERRSTR;
rc.err.data = errstr;
if (ngx_regex_compile (&rc) != NGX_OK)
{
ngx_conf_log_error (NGX_LOG_EMERG, cf, 0, "%V", &rc.err);
return NGX_CONF_ERROR;
}
s->regex = rc.regex;
if (s->regex == NULL)
{
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}
static ngx_int_t
ngx_http_cross_isp_handler (ngx_http_request_t * r)
{
ngx_http_cross_isp_main_conf_t *ipmcf;
ngx_int_t pc1 = NGX_DECLINED, pc2 = NGX_DECLINED, ssl, rc;
ngx_uint_t i, m;
ngx_uint_t ip;
ngx_str_t str_uri;
ngx_str_t isp_rhost_cookie, isp_taddr_cookie;
ngx_isp_proxy_t *ipt;
ngx_isp_store_t *ist;
ngx_isp_domain_t *idt;
u_char *u_uri, *u_relative_uri, *p, *u_isp_rhost_cookie,
*u_isp_taddr_cookie, *taddr;
struct sockaddr_in *sin;
size_t str_uri_len, str_relative_uri_len, con_schema_len, taddr_len,
cookie_expires_len;
char *pt;
long ip_pos;
int cmp_r1, cmp_r2;
ipmcf = ngx_http_get_module_main_conf (r, ngx_http_cross_isp_module);
ipt = ipmcf->isp_proxies.elts;
for (i = 0; i < ipmcf->isp_proxies.nelts; i++)
{
rc = ngx_regex_exec (ipt[i].regex, &r->uri, NULL, 0);
if (rc == NGX_REGEX_NO_MATCHED)
{
continue;
}
pc1 =
ngx_http_parse_multi_header_lines (&r->headers_in.cookies,
&ipmcf->isp_rhost_cookie_name,
&isp_rhost_cookie);
pc2 =
ngx_http_parse_multi_header_lines (&r->headers_in.cookies,
&ipmcf->isp_taddr_cookie_name,
&isp_taddr_cookie);
sin = (struct sockaddr_in *) (r->connection->sockaddr);
ip = ntohl (sin->sin_addr.s_addr);
pt = inet_ntoa (sin->sin_addr);
if (pt == NULL)
{
ngx_log_error (NGX_LOG_ERR,
r->connection->log, 0, "inet_ntoa get taddr error");
return NGX_DECLINED;
}
taddr_len = strlen (pt);
taddr = ngx_pcalloc (r->pool, taddr_len * sizeof (u_char));
if (taddr == NULL)
{
ngx_log_error (NGX_LOG_ERR,
r->connection->log,
0, "ngx_pcalloc no args taddr error");
return NGX_DECLINED;
}
p = ngx_copy (taddr, pt, taddr_len);
cmp_r1 =
ngx_strncmp (isp_rhost_cookie.data, r->headers_in.host->value.data,
isp_rhost_cookie.len);
cmp_r2 =
ngx_strncmp (isp_taddr_cookie.data, taddr, isp_taddr_cookie.len);
if (pc1 != NGX_DECLINED && cmp_r1 == 0 && pc2 != NGX_DECLINED
&& cmp_r2 == 0)
{
return NGX_DECLINED;
}
ip_pos = ngx_isp_store_binary_search (ipmcf->isp_store, ip);
if (ip_pos == -1)
{
return NGX_DECLINED;
}
ist = ipmcf->isp_store.elts;
idt = ipmcf->isp_domains.elts;
for (m = 0; m < ipmcf->isp_domains.nelts; m++)
{
if (ngx_strcmp (idt[m].isp, ist[ip_pos].isp) == 0)
{
rc = ngx_regex_exec (idt[m].regex, &r->headers_in.host->value,
NULL, 0);
if (rc >= 0)
{
if (ipmcf->isp_cookies_expires)
{
cookie_expires_len =
sizeof (ngx_http_cookies_expires) - 1;
}
if (pc1 == NGX_DECLINED || cmp_r1 != 0)
{
u_isp_rhost_cookie = ngx_pcalloc (r->pool,
(ipmcf->isp_rhost_cookie_name.len
+ 1 +
r->headers_in.
host->value.len +
cookie_expires_len +
1 +
HTTP_DOMAIN_COOKIE_NAME_LEN
+ 1 +
idt[m].domain.len +
1) *
sizeof (u_char));
if (u_isp_rhost_cookie == NULL)
{
ngx_log_error (NGX_LOG_ERR,
r->connection->log,
0,
"ngx_pcalloc no args u_isp_rhost_cookie error");
return NGX_DECLINED;
}
p = ngx_copy (u_isp_rhost_cookie,
ipmcf->isp_rhost_cookie_name.data,
ipmcf->isp_rhost_cookie_name.len);
*p++ = '=';
p = ngx_copy (p, r->headers_in.host->value.data,
r->headers_in.host->value.len);
if (ipmcf->isp_cookies_expires ==
HTTP_COOKIES_MAX_EXPIRES)
{
p =
ngx_copy (p, ngx_http_cookies_expires,
cookie_expires_len);
}
else if (ipmcf->isp_cookies_expires)
{
p =
ngx_copy (p, ngx_http_cookies_expires,
sizeof ("; expires=") - 1);
p =
ngx_http_cookie_time (p,
ngx_time () +
ipmcf->isp_cookies_expires);
}
*p++ = ';';
p = ngx_copy (p, ngx_http_domain_cookie_name,
HTTP_DOMAIN_COOKIE_NAME_LEN);
*p++ = '=';
p = ngx_copy (p, idt[m].domain.data, idt[m].domain.len);
*p++ = '\0';
ngx_http_write_isp_cookie (r, u_isp_rhost_cookie);
}
if (pc2 == NGX_DECLINED || cmp_r2 != 0)
{
u_isp_taddr_cookie = ngx_pcalloc (r->pool,
(ipmcf->isp_taddr_cookie_name.len
+ 1 + taddr_len +
cookie_expires_len +
1 +
HTTP_DOMAIN_COOKIE_NAME_LEN
+ 1 +
idt[m].domain.len +
1) *
sizeof (u_char));
if (u_isp_taddr_cookie == NULL)
{
ngx_log_error (NGX_LOG_ERR,
r->connection->log,
0,
"ngx_pcalloc no args u_isp_taddr_cookie error");
return NGX_DECLINED;
}
p =
ngx_copy (u_isp_taddr_cookie,
ipmcf->isp_taddr_cookie_name.data,
ipmcf->isp_taddr_cookie_name.len);
*p++ = '=';
p = ngx_copy (p, taddr, taddr_len);
if (ipmcf->isp_cookies_expires ==
HTTP_COOKIES_MAX_EXPIRES)
{
p =
ngx_copy (p, ngx_http_cookies_expires,
cookie_expires_len);
}
else if (ipmcf->isp_cookies_expires)
{
p =
ngx_copy (p, ngx_http_cookies_expires,
sizeof ("; expires=") - 1);
p =
ngx_http_cookie_time (p,
ngx_time () +
ipmcf->isp_cookies_expires);
}
*p++ = ';';
p =
ngx_copy (p, ngx_http_domain_cookie_name,
HTTP_DOMAIN_COOKIE_NAME_LEN);
*p++ = '=';
p = ngx_copy (p, idt[m].domain.data, idt[m].domain.len);
*p++ = '\0';
ngx_http_write_isp_cookie (r, u_isp_taddr_cookie);
}
return NGX_DECLINED;
}
else
{
ssl = r->connection->ssl == NULL ? 0 : 1;
con_schema_len = ssl ? HTTPS_SCHEMA_LEN : HTTP_SCHEMA_LEN;
if (r->args.data == NULL)
{
u_relative_uri =
ngx_pcalloc (r->pool,
(r->uri.len + 1) * sizeof (u_char));
if (u_relative_uri == NULL)
{
ngx_log_error (NGX_LOG_ERR,
r->connection->log,
0,
"ngx_pcalloc no args u_relative_uri error");
return NGX_DECLINED;
}
p = ngx_copy (u_relative_uri, r->uri.data, r->uri.len);
*p++ = '\0';
}
else
{
u_relative_uri =
ngx_pcalloc (r->pool,
(r->uri.len + r->args.len +
2) * sizeof (u_char));
if (u_relative_uri == NULL)
{
ngx_log_error (NGX_LOG_ERR,
r->connection->log,
0,
"ngx_pcalloc with args u_relative_uri error");
return NGX_DECLINED;
}
p = ngx_copy (u_relative_uri, r->uri.data, r->uri.len);
*p++ = '?';
p = ngx_copy (p, r->args.data, r->args.len);
*p++ = '\0';
}
str_relative_uri_len = ngx_strlen (u_relative_uri);
str_uri_len =
con_schema_len + idt[m].replace.len +
str_relative_uri_len;
u_uri =
ngx_pcalloc (r->pool, str_uri_len * sizeof (u_char));
if (u_uri == NULL)
{
ngx_log_error (NGX_LOG_ERR,
r->connection->log,
0, "ngx_pcalloc no args u_uri error");
return NGX_DECLINED;
}
p =
(ssl ? ngx_copy (u_uri, ngx_https_schema, con_schema_len)
: ngx_copy (u_uri, ngx_http_schema, con_schema_len));
p = ngx_copy (p, idt[m].replace.data, idt[m].replace.len);
p = ngx_copy (p, u_relative_uri, str_relative_uri_len);
str_uri.len = str_uri_len;
str_uri.data = u_uri;
return ngx_cross_isp_redirect (r, str_uri);
}
}
}
}
return NGX_DECLINED;
}
static long
ngx_isp_store_binary_search (ngx_array_t data, ngx_uint_t ip)
{
long low = -1;
long high = data.nelts;
ngx_uint_t mid;
ngx_isp_store_t *ist = data.elts;
while (high - low > 1)
{
mid = (low + high) >> 1;
if (ist[mid].ip_start > ip)
{
high = mid;
}
else
{
low = mid;
}
}
if ((low == -1) || !(ist[low].ip_start <= ip && ip <= ist[low].ip_end))
{
return -1;
}
else
{
return low;
}
}
static ngx_int_t
ngx_cross_isp_redirect (ngx_http_request_t * r, ngx_str_t url)
{
ngx_buf_t *b;
ngx_chain_t out;
size_t ngx_http_302_page_len = ngx_strlen (ngx_http_302_page);
r->headers_out.content_type.len = sizeof ("text/html") - 1;
r->headers_out.content_type.data = (u_char *) "text/html";
b = ngx_pcalloc (r->pool, sizeof (ngx_buf_t));
out.buf = b;
out.next = NULL;
b->pos = ngx_http_302_page;
b->last = ngx_http_302_page + ngx_http_302_page_len;
b->memory = 1;
b->last_buf = 1;
r->headers_out.status = NGX_HTTP_MOVED_TEMPORARILY;
r->headers_out.location = ngx_list_push (&r->headers_out.headers);
r->headers_out.location->hash = 1;
ngx_str_set (&r->headers_out.location->key, "Location");
r->headers_out.location->value = url;
r->headers_out.content_length_n = ngx_http_302_page_len;
ngx_http_send_header (r);
return ngx_http_write_filter (r, &out);
}
static void
ngx_http_write_isp_cookie (ngx_http_request_t * r, u_char * cookie)
{
ngx_table_elt_t *set_cookie;
set_cookie = ngx_list_push (&r->headers_out.headers);
if (set_cookie == NULL)
{
return;
}
set_cookie->hash = 1;
set_cookie->key.len = sizeof ("Set-Cookie") - 1;
set_cookie->key.data = (u_char *) "Set-Cookie";
set_cookie->value.len = ngx_strlen (cookie);
set_cookie->value.data = cookie;
}