diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/core/nginx.h | 2 | ||||
-rw-r--r-- | src/http/modules/ngx_http_charset_filter_module.c | 39 | ||||
-rw-r--r-- | src/http/modules/ngx_http_proxy_module.c | 22 | ||||
-rw-r--r-- | src/http/modules/perl/ngx_http_perl_module.c | 38 | ||||
-rw-r--r-- | src/http/ngx_http_core_module.c | 1 | ||||
-rw-r--r-- | src/http/ngx_http_request.c | 1 | ||||
-rw-r--r-- | src/http/ngx_http_script.c | 4 | ||||
-rw-r--r-- | src/http/ngx_http_upstream.c | 4 | ||||
-rw-r--r-- | src/mysql/config | 13 | ||||
-rw-r--r-- | src/mysql/ngx_http_mysql_test.c | 196 | ||||
-rw-r--r-- | src/mysql/ngx_mysql.c | 386 | ||||
-rw-r--r-- | src/mysql/ngx_mysql.h | 64 |
12 files changed, 705 insertions, 65 deletions
diff --git a/src/core/nginx.h b/src/core/nginx.h index 72aaa34bc..c376b92f2 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,7 +8,7 @@ #define _NGINX_H_INCLUDED_ -#define NGINX_VER "nginx/0.3.47" +#define NGINX_VER "nginx/0.3.48" #define NGINX_VAR "NGINX" #define NGX_OLDPID_EXT ".oldbin" diff --git a/src/http/modules/ngx_http_charset_filter_module.c b/src/http/modules/ngx_http_charset_filter_module.c index 3c9e01b3e..c7aa14cfb 100644 --- a/src/http/modules/ngx_http_charset_filter_module.c +++ b/src/http/modules/ngx_http_charset_filter_module.c @@ -154,7 +154,7 @@ ngx_http_charset_header_filter(ngx_http_request_t *r) ngx_uint_t i; ngx_http_charset_t *charsets; ngx_http_charset_ctx_t *ctx; - ngx_http_charset_loc_conf_t *lcf; + ngx_http_charset_loc_conf_t *lcf, *mlcf; ngx_http_charset_main_conf_t *mcf; mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module); @@ -162,9 +162,9 @@ ngx_http_charset_header_filter(ngx_http_request_t *r) ctx = ngx_http_get_module_ctx(r->main, ngx_http_charset_filter_module); if (ctx == NULL) { - lcf = ngx_http_get_module_loc_conf(r->main, - ngx_http_charset_filter_module); - charset = lcf->charset; + mlcf = ngx_http_get_module_loc_conf(r->main, + ngx_http_charset_filter_module); + charset = mlcf->charset; if (charset == NGX_HTTP_NO_CHARSET) { return ngx_http_next_header_filter(r); @@ -174,18 +174,29 @@ ngx_http_charset_header_filter(ngx_http_request_t *r) charset = ctx->charset; } - if (r->headers_out.content_type.len == 0) { - return ngx_http_next_header_filter(r); - } + charsets = mcf->charsets.elts; - if (ngx_strncasecmp(r->headers_out.content_type.data, "text/", 5) != 0 - && ngx_strncasecmp(r->headers_out.content_type.data, - "application/x-javascript", 24) != 0) - { - return ngx_http_next_header_filter(r); - } + if (r == r->main) { + if (r->headers_out.content_type.len == 0) { + return ngx_http_next_header_filter(r); + } - charsets = mcf->charsets.elts; + if (ngx_strncasecmp(r->headers_out.content_type.data, "text/", 5) != 0 + && ngx_strncasecmp(r->headers_out.content_type.data, + "application/x-javascript", 24) != 0) + { + return ngx_http_next_header_filter(r); + } + + } else { + if (r->headers_out.content_type.len == 0) { + mlcf = ngx_http_get_module_loc_conf(r->main, + ngx_http_charset_filter_module); + source_charset = mlcf->source_charset; + + goto found; + } + } lcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module); diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index f5fb9184b..31a4355e5 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -1349,7 +1349,9 @@ ngx_http_proxy_rewrite_redirect_text(ngx_http_request_t *r, ngx_table_elt_t *h, p = ngx_copy(p, h->value.data, prefix); - p = ngx_copy(p, pr->replacement.text.data, pr->replacement.text.len); + if (pr->replacement.text.len) { + p = ngx_copy(p, pr->replacement.text.data, pr->replacement.text.len); + } ngx_memcpy(p, h->value.data + prefix + pr->redirect.len, h->value.len - pr->redirect.len - prefix); @@ -1694,7 +1696,14 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) pr->handler = ngx_http_proxy_rewrite_redirect_text; pr->redirect = conf->upstream.url; - pr->replacement.text = conf->upstream.location; + + if (conf->upstream.uri.len) { + pr->replacement.text = conf->upstream.location; + + } else { + pr->replacement.text.len = 0; + pr->replacement.text.data = NULL; + } } } @@ -2263,7 +2272,14 @@ ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) pr->handler = ngx_http_proxy_rewrite_redirect_text; pr->redirect = plcf->upstream.url; - pr->replacement.text = plcf->upstream.location; + + if (plcf->upstream.uri.len) { + pr->replacement.text = plcf->upstream.location; + + } else { + pr->replacement.text.len = 0; + pr->replacement.text.data = NULL; + } return NGX_CONF_OK; } diff --git a/src/http/modules/perl/ngx_http_perl_module.c b/src/http/modules/perl/ngx_http_perl_module.c index 975c727c8..91a9c85ca 100644 --- a/src/http/modules/perl/ngx_http_perl_module.c +++ b/src/http/modules/perl/ngx_http_perl_module.c @@ -34,6 +34,12 @@ typedef struct { } ngx_http_perl_variable_t; +typedef struct { + SV *sv; + PerlInterpreter *perl; +} ngx_http_perl_cleanup_t; + + #if (NGX_HTTP_SSI) static ngx_int_t ngx_http_perl_ssi(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ssi_ctx, ngx_str_t **params); @@ -51,7 +57,7 @@ static char *ngx_http_perl_init_interpreter(ngx_conf_t *cf, static PerlInterpreter * ngx_http_perl_create_interpreter(ngx_http_perl_main_conf_t *pmcf, ngx_log_t *log); -static ngx_int_t ngx_http_perl_run_requires(ngx_array_t *requires, +static ngx_int_t ngx_http_perl_run_requires(pTHX_ ngx_array_t *requires, ngx_log_t *log); static ngx_int_t ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, SV *sub, ngx_str_t **args, ngx_str_t *handler, ngx_str_t *rv); @@ -478,7 +484,7 @@ static char * ngx_http_perl_init_interpreter(ngx_conf_t *cf, ngx_http_perl_main_conf_t *pmcf) { #if (NGX_HAVE_PERL_CLONE || NGX_HAVE_PERL_MULTIPLICITY) - ngx_pool_cleanup_t *cln; + ngx_pool_cleanup_t *cln; cln = ngx_pool_cleanup_add(cf->pool, 0); if (cln == NULL) { @@ -504,7 +510,9 @@ ngx_http_perl_init_interpreter(ngx_conf_t *cf, ngx_http_perl_main_conf_t *pmcf) #if !(NGX_HAVE_PERL_CLONE || NGX_HAVE_PERL_MULTIPLICITY) if (perl) { - if (ngx_http_perl_run_requires(&pmcf->requires, cf->log) != NGX_OK) { + if (ngx_http_perl_run_requires(aTHX_ &pmcf->requires, cf->log) + != NGX_OK) + { return NGX_CONF_ERROR; } @@ -613,7 +621,7 @@ ngx_http_perl_create_interpreter(ngx_http_perl_main_conf_t *pmcf, goto fail; } - if (ngx_http_perl_run_requires(&pmcf->requires, log) != NGX_OK) { + if (ngx_http_perl_run_requires(aTHX_ &pmcf->requires, log) != NGX_OK) { goto fail; } @@ -634,7 +642,7 @@ fail: static ngx_int_t -ngx_http_perl_run_requires(ngx_array_t *requires, ngx_log_t *log) +ngx_http_perl_run_requires(pTHX_ ngx_array_t *requires, ngx_log_t *log) { char **script; STRLEN len; @@ -870,9 +878,11 @@ ngx_http_perl_cleanup_perl(void *data) static void ngx_http_perl_cleanup_sv(void *data) { - SV *sv = data; + ngx_http_perl_cleanup_t *cln = data; - SvREFCNT_dec(sv); + dTHXa(cln->perl); + + SvREFCNT_dec(cln->sv); } @@ -967,6 +977,7 @@ ngx_http_perl(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_str_t *value; ngx_pool_cleanup_t *cln; + ngx_http_perl_cleanup_t *pcln; ngx_http_core_loc_conf_t *clcf; ngx_http_perl_main_conf_t *pmcf; @@ -986,7 +997,7 @@ ngx_http_perl(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } } - cln = ngx_pool_cleanup_add(cf->pool, 0); + cln = ngx_pool_cleanup_add(cf->pool, sizeof(ngx_http_perl_cleanup_t)); if (cln == NULL) { return NGX_CONF_ERROR; } @@ -1012,7 +1023,9 @@ ngx_http_perl(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } cln->handler = ngx_http_perl_cleanup_sv; - cln->data = plcf->sub; + pcln = cln->data; + pcln->sv = plcf->sub; + pcln->perl = pmcf->perl; clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); clcf->handler = ngx_http_perl_handler; @@ -1028,6 +1041,7 @@ ngx_http_perl_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_str_t *value; ngx_pool_cleanup_t *cln; ngx_http_variable_t *v; + ngx_http_perl_cleanup_t *pcln; ngx_http_perl_variable_t *pv; ngx_http_perl_main_conf_t *pmcf; @@ -1065,7 +1079,7 @@ ngx_http_perl_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } } - cln = ngx_pool_cleanup_add(cf->pool, 0); + cln = ngx_pool_cleanup_add(cf->pool, sizeof(ngx_http_perl_cleanup_t)); if (cln == NULL) { return NGX_CONF_ERROR; } @@ -1091,7 +1105,9 @@ ngx_http_perl_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } cln->handler = ngx_http_perl_cleanup_sv; - cln->data = pv->sub; + pcln = cln->data; + pcln->sv = pv->sub; + pcln->perl = pmcf->perl; v->get_handler = ngx_http_perl_variable; v->data = (uintptr_t) pv; diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 6cbbf09e7..f08ec458d 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -1330,7 +1330,6 @@ ngx_http_internal_redirect(ngx_http_request_t *r, ngx_http_update_location_config(r); r->internal = 1; - r->method = NGX_HTTP_GET; r->uri_changes--; diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 4f7d24fa5..c606ec81a 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1470,7 +1470,6 @@ ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc) || rc == NGX_HTTP_CREATED || rc == NGX_HTTP_NO_CONTENT) { - if (rc == NGX_HTTP_CLOSE) { ngx_http_close_request(r, rc); return; diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c index 9826ecea5..94793d7e7 100644 --- a/src/http/ngx_http_script.c +++ b/src/http/ngx_http_script.c @@ -833,6 +833,10 @@ ngx_http_script_return_code(ngx_http_script_engine_t *e) e->status = code->status; + if (code->status == NGX_HTTP_NO_CONTENT) { + e->request->header_only = 1; + } + e->ip += sizeof(ngx_http_script_return_code_t) - sizeof(uintptr_t); } diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 4b914abd8..e53d32c1b 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -1160,6 +1160,10 @@ ngx_http_upstream_process_header(ngx_event_t *rev) r->zero_in_uri = 1; } + if (r->method != NGX_HTTP_HEAD) { + r->method = NGX_HTTP_GET; + } + ngx_http_internal_redirect(r, uri, &args); return; } diff --git a/src/mysql/config b/src/mysql/config new file mode 100644 index 000000000..cdec6390a --- /dev/null +++ b/src/mysql/config @@ -0,0 +1,13 @@ + +ngx_addon_name=ngx_mysql + +HTTP_MODULES="$HTTP_MODULES ngx_http_mysql_test_module" + +HTTP_INCS="$HTTP_INCS $ngx_addon_dir" +HTTP_DEPS="$HTTP_DEPS $ngx_addon_dir/ngx_mysql.h" +#CORE_LIBS="$CORE_LIBS -lmd" + +USE_SHA1=YES + +NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_mysql.c" +NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_mysql_test.c" diff --git a/src/mysql/ngx_http_mysql_test.c b/src/mysql/ngx_http_mysql_test.c new file mode 100644 index 000000000..0b83f7d51 --- /dev/null +++ b/src/mysql/ngx_http_mysql_test.c @@ -0,0 +1,196 @@ + +/* + * Copyright (C) Igor Sysoev + */ + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_mysql.h> +#include <ngx_http.h> + + +typedef struct { + ngx_peers_t *peers; +} ngx_http_mysql_test_conf_t; + + +static void ngx_http_mysql_auth(ngx_mysql_t *m); +static void ngx_http_mysql_done(ngx_mysql_t *m); +static void *ngx_http_mysql_test_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_mysql_test(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + +static ngx_command_t ngx_http_mysql_test_commands[] = { + + { ngx_string("mysql_test"), + NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_mysql_test, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +ngx_http_module_t ngx_http_mysql_test_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_mysql_test_create_loc_conf, /* create location configuration */ + NULL /* merge location configuration */ +}; + + +ngx_module_t ngx_http_mysql_test_module = { + NGX_MODULE_V1, + &ngx_http_mysql_test_module_ctx, /* module context */ + ngx_http_mysql_test_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_str_t ngx_mysql_login = ngx_string("root"); +static ngx_str_t ngx_mysql_passwd = ngx_string("tp"); +static ngx_str_t ngx_mysql_database = ngx_string("mysql"); +static ngx_str_t ngx_mysql_command_query = + ngx_string("select * from user"); + + +static ngx_int_t +ngx_http_mysql_test_handler(ngx_http_request_t *r) +{ + ngx_int_t rc; + ngx_mysql_t *m; + ngx_http_mysql_test_conf_t *mtcf; + + mtcf = ngx_http_get_module_loc_conf(r, ngx_http_mysql_test_module); + + m = ngx_pcalloc(r->pool, sizeof(ngx_mysql_t)); + + if (m == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + m->pool = r->pool; + m->handler = ngx_http_mysql_auth; + m->data = r; + + m->login = &ngx_mysql_login; + m->passwd = &ngx_mysql_passwd; + m->database = &ngx_mysql_database; + + m->peer.log = r->connection->log; + m->peer.log_error = NGX_ERROR_ERR; + m->peer.peers = mtcf->peers; + m->peer.tries = mtcf->peers->number; + + rc = ngx_mysql_connect(m); + + if (rc == NGX_OK || rc == NGX_AGAIN) { + return NGX_DONE; + } + + return NGX_HTTP_INTERNAL_SERVER_ERROR; +} + + +static void +ngx_http_mysql_auth(ngx_mysql_t *m) +{ + ngx_http_request_t *r; + + r = m->data; + + if (m->state != NGX_OK) { + ngx_http_finalize_request(r, NGX_HTTP_NO_CONTENT); + return; + } + + m->query.len = NGX_MYSQL_CMDPKT_LEN + ngx_mysql_command_query.len; + + m->query.data = ngx_palloc(r->pool, m->query.len); + if (m->query.data == NULL) { + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + ngx_memcpy(m->query.data + NGX_MYSQL_CMDPKT_LEN, + ngx_mysql_command_query.data, ngx_mysql_command_query.len); + + m->handler = ngx_http_mysql_done; + + ngx_mysql_query(m); +} + + +static void +ngx_http_mysql_done(ngx_mysql_t *m) +{ + ngx_http_request_t *r; + + r = m->data; + + ngx_http_finalize_request(r, NGX_HTTP_NO_CONTENT); +} + + +static void * +ngx_http_mysql_test_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_mysql_test_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_mysql_test_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + return conf; +} + +static char * +ngx_http_mysql_test(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_mysql_test_conf_t *mtcf = conf; + + ngx_str_t *value; + ngx_url_t u; + ngx_http_core_loc_conf_t *clcf; + + clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + clcf->handler = ngx_http_mysql_test_handler; + + value = cf->args->elts; + + ngx_memzero(&u, sizeof(ngx_url_t)); + + u.url = value[1]; + u.default_portn = 3306; + + if (ngx_parse_url(cf, &u) != NGX_OK) { + if (u.err) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%s in upstream \"%V\"", u.err, &u.url); + } + + return NGX_CONF_ERROR; + } + + mtcf->peers = u.peers; + + return NGX_CONF_OK; +} diff --git a/src/mysql/ngx_mysql.c b/src/mysql/ngx_mysql.c index 1e008b5e4..daabcd855 100644 --- a/src/mysql/ngx_mysql.c +++ b/src/mysql/ngx_mysql.c @@ -4,13 +4,100 @@ */ +/* the library supports the subset of the MySQL 4.1+ protocol (version 10) */ + + #include <ngx_config.h> #include <ngx_core.h> #include <ngx_event.h> +#include <ngx_event_connect.h> #include <ngx_mysql.h> +#if (NGX_HAVE_OPENSSL_SHA1_H) +#include <openssl/sha.h> +#else +#include <sha.h> +#endif -/* the library supports the subset of the MySQL 4.1+ protocol (version 10) */ + +#define NGX_MYSQL_LONG_PASSWORD 0x0001 +#define NGX_MYSQL_CONNECT_WITH_DB 0x0008 +#define NGX_MYSQL_PROTOCOL_41 0x0200 +#define NGX_MYSQL_SECURE_CONNECTION 0x8000 + + +#define NGX_MYSQL_CMD_QUERY 3 + + +typedef struct { + u_char pktlen[3]; + u_char pktn; + + u_char protocol; + u_char version[1]; /* NULL-terminated string */ +} ngx_mysql_greeting1_pkt_t; + + +typedef struct { + u_char thread[4]; + u_char salt1[9]; + u_char capacity[2]; + u_char charset; + u_char status[2]; + u_char zero[13]; + u_char salt2[13]; +} ngx_mysql_greeting2_pkt_t; + + +typedef struct { + u_char pktlen[3]; + u_char pktn; + + u_char capacity[4]; + u_char max_packet[4]; + u_char charset; + u_char zero[23]; + u_char login[1]; /* NULL-terminated string */ + + /* + * u_char passwd_len; 0 if no password + * u_char passwd[20]; + * + * u_char database[1]; NULL-terminated string + */ + +} ngx_mysql_auth_pkt_t; + + +typedef struct { + u_char pktlen[3]; + u_char pktn; + u_char fields; +} ngx_mysql_response_pkt_t; + + +typedef struct { + u_char pktlen[3]; + u_char pktn; + u_char err; + u_char code[2]; + u_char message[1]; /* string */ +} ngx_mysql_error_pkt_t; + + +typedef struct { + u_char pktlen[3]; + u_char pktn; + u_char command; + u_char arg[1]; /* string */ +} ngx_mysql_command_pkt_t; + + +static void ngx_mysql_read_server_greeting(ngx_event_t *rev); +static void ngx_mysql_empty_handler(ngx_event_t *wev); +static void ngx_mysql_read_auth_result(ngx_event_t *rev); +static void ngx_mysql_read_query_result(ngx_event_t *rev); +static void ngx_mysql_close(ngx_mysql_t *m, ngx_int_t rc); ngx_int_t @@ -32,11 +119,12 @@ ngx_mysql_connect(ngx_mysql_t *m) return rc; } + m->peer.connection->data = m; + m->peer.connection->read->handler = ngx_mysql_read_server_greeting; - m->peer.connection->write->handler = ngx_mysql_emtpy_handler; + m->peer.connection->write->handler = ngx_mysql_empty_handler; ngx_add_timer(m->peer.connection->read, /* STUB */ 5000); - ngx_add_timer(m->peer.connection->write, /* STUB */ 5000); return NGX_OK; } @@ -45,10 +133,17 @@ ngx_mysql_connect(ngx_mysql_t *m) static void ngx_mysql_read_server_greeting(ngx_event_t *rev) { - size_t len; - u_char *p, *t; - ngx_mysql_t *m; - ngx_connection_t *c; + size_t len; + u_char *p; + ssize_t n; + ngx_uint_t i, capacity; + ngx_mysql_t *m; + ngx_connection_t *c; + ngx_mysql_greeting1_pkt_t *gr1; + ngx_mysql_greeting2_pkt_t *gr2; + ngx_mysql_auth_pkt_t *auth; + SHA_CTX sha; + u_char hash1[20], hash2[20]; c = rev->data; m = c->data; @@ -56,16 +151,16 @@ ngx_mysql_read_server_greeting(ngx_event_t *rev) if (rev->timedout) { ngx_log_error(NGX_LOG_ERR, rev->log, NGX_ETIMEDOUT, "mysql server %V timed out", - &ctx->peer.peers->peer[0].name); + &m->peer.peers->peer[0].name); ngx_mysql_close(m, NGX_ERROR); return; } if (m->buf == NULL) { - m->peer.log->action = "reading to mysql server greeting"; + m->peer.log->action = "reading mysql server greeting"; - m->buf = ngx_create_temp(m->pool, /* STUB */ 1024); + m->buf = ngx_create_temp_buf(m->pool, /* STUB */ 1024); if (m->buf == NULL) { ngx_mysql_close(m, NGX_ERROR); return; @@ -83,43 +178,282 @@ ngx_mysql_read_server_greeting(ngx_event_t *rev) return; } - p = m->buf->pos; + gr1 = (ngx_mysql_greeting1_pkt_t *) m->buf->pos; - if (ngx_m24toh(p) > n - 4) { + if (ngx_m24toh(gr1->pktlen) > n - 4) { ngx_log_error(NGX_LOG_ERR, rev->log, 0, "mysql server %V sent incomplete greeting packet", - &ctx->peer.peers->peer[0].name); + &m->peer.peers->peer[0].name); ngx_mysql_close(m, NGX_ERROR); return; } - if (p[4]) < 10) { + if (gr1->protocol < 10) { ngx_log_error(NGX_LOG_ERR, rev->log, 0, "mysql server %V sent unsupported protocol version %ud", - &ctx->peer.peers->peer[0].name, p[4]); + &m->peer.peers->peer[0].name, gr1->protocol); ngx_mysql_close(m, NGX_ERROR); return; } - len = ngx_strlen(&p[5]); - t = p + 5 + len + 1; + gr2 = (ngx_mysql_greeting2_pkt_t *) + (gr1->version + ngx_strlen(gr1->version) + 1); - capacity = ngx_m16toh((&t[4 + 9])); + capacity = ngx_m16toh(gr2->capacity); ngx_log_debug8(NGX_LOG_DEBUG_MYSQL, rev->log, 0, - "mysql version: %ud, \"%s\", thread: %ud, salt: \"%s\", ", + "mysql version: %ud, \"%s\", thread: %ud, salt: \"%s\", " "capacity: %Xd, charset: %ud, status: %ud, salt rest \"%s\"", - p[4], &p[5], ngx_m32toh(t), &t[4], - capacity, t[4 + 9 + 2], - ngx_m16toh((&t[4 + 9 + 2 + 1])), - t[4 + 9 + 2 + 1 + 2 + 13]); + gr1->protocol, gr1->version, ngx_m32toh(gr2->thread), + gr2->salt1, capacity, gr2->charset, + ngx_m16toh(gr2->status), &gr2->salt2); + + capacity = NGX_MYSQL_LONG_PASSWORD + | NGX_MYSQL_CONNECT_WITH_DB + | NGX_MYSQL_PROTOCOL_41 + | NGX_MYSQL_SECURE_CONNECTION; + + len = 4 + 4 + 4 + 1 + 23 + m->login->len + 1 + 1 + m->database->len + 1; + + if (m->passwd->len) { + len += 20; + } + + auth = ngx_palloc(m->pool, len); + if (auth == NULL) { + ngx_mysql_close(m, NGX_ERROR); + return; + } + + ngx_htom24(auth->pktlen, len - 4); + auth->pktn = (u_char) (gr1->pktn + 1); + + ngx_htom32(auth->capacity, capacity); + ngx_htom32(auth->max_packet, 0x01000000); /* max packet size 2^24 */ + ngx_memzero(auth->zero, 24); + auth->charset = gr2->charset; + + p = ngx_copy(auth->login, m->login->data, m->login->len); + *p++ = '\0'; + + if (m->passwd->len) { + + *p++ = (u_char) 20; + + SHA1_Init(&sha); + SHA1_Update(&sha, m->passwd->data, m->passwd->len); + SHA1_Final(hash1, &sha); + + SHA1_Init(&sha); + SHA1_Update(&sha, hash1, 20); + SHA1_Final(hash2, &sha); + + SHA1_Init(&sha); + SHA1_Update(&sha, gr2->salt1, 8); + SHA1_Update(&sha, gr2->salt2, 12); + SHA1_Update(&sha, hash2, 20); + SHA1_Final(hash2, &sha); + + for (i = 0; i < 20; i++) { + *p++ = (u_char) (hash1[i] ^ hash2[i]); + } + + } else { + *p++ = '\0'; + } + + p = ngx_copy(p, m->database->data, m->database->len); + *p = '\0'; + + + n = ngx_send(m->peer.connection, (void *) auth, len); + + if (n < (ssize_t) len) { + ngx_log_error(NGX_LOG_ERR, rev->log, 0, + "the incomplete packet was sent to mysql server %V", + &m->peer.peers->peer[0].name); + + ngx_mysql_close(m, NGX_ERROR); + return; + } + + m->peer.connection->read->handler = ngx_mysql_read_auth_result; + + ngx_add_timer(m->peer.connection->read, /* STUB */ 5000); +} + + +static void +ngx_mysql_empty_handler(ngx_event_t *wev) +{ + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0, "mysql empty handler"); + + return; +} + + +static void +ngx_mysql_read_auth_result(ngx_event_t *rev) +{ + ssize_t n, len; + ngx_str_t msg; + ngx_mysql_t *m; + ngx_connection_t *c; + ngx_mysql_error_pkt_t *epkt; + ngx_mysql_response_pkt_t *pkt; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "mysql read auth"); + + c = rev->data; + m = c->data; + + m->peer.log->action = "reading mysql auth result"; + + n = ngx_recv(m->peer.connection, m->buf->pos, /* STUB */ 1024); + + if (n == NGX_AGAIN) { + return; + } + + if (n < 5) { + ngx_mysql_close(m, NGX_ERROR); + return; + } + + pkt = (ngx_mysql_response_pkt_t *) m->buf->pos; + + len = ngx_m24toh(pkt->pktlen); + + if (len > n - 4) { + ngx_log_error(NGX_LOG_ERR, rev->log, 0, + "mysql server %V sent incomplete response packet", + &m->peer.peers->peer[0].name); + + ngx_mysql_close(m, NGX_ERROR); + return; + } + + if (pkt->fields == 0) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "mysql auth OK"); + + m->state = NGX_OK; + m->pktn = 0; + + m->handler(m); + + return; + } + + epkt = (ngx_mysql_error_pkt_t *) pkt; + + msg.len = (u_char *) epkt + 4 + len - epkt->message; + msg.data = epkt->message; + + ngx_log_error(NGX_LOG_ERR, rev->log, 0, + "mysql server %V sent error (%ud): \"%V\"", + &m->peer.peers->peer[0].name, ngx_m16toh(epkt->code), &msg); + + ngx_mysql_close(m, NGX_ERROR); +} + + +ngx_int_t +ngx_mysql_query(ngx_mysql_t *m) +{ + ssize_t n; + ngx_mysql_command_pkt_t *pkt; + + pkt = (ngx_mysql_command_pkt_t *) m->query.data; + + ngx_htom24(pkt->pktlen, m->query.len - 4); + pkt->pktn = (u_char) m->pktn++; + pkt->command = NGX_MYSQL_CMD_QUERY; + + n = ngx_send(m->peer.connection, m->query.data, m->query.len); + + if (n < (ssize_t) m->query.len) { + ngx_log_error(NGX_LOG_ERR, m->peer.log, 0, + "the incomplete packet was sent to mysql server %V", + &m->peer.peers->peer[0].name); + + ngx_mysql_close(m, NGX_ERROR); + return NGX_OK; + } + + m->peer.connection->read->handler = ngx_mysql_read_query_result; + + ngx_add_timer(m->peer.connection->read, /* STUB */ 5000); + + /* STUB handle event */ + + return NGX_OK; +} + + +static void +ngx_mysql_read_query_result(ngx_event_t *rev) +{ + ssize_t n, len; + ngx_str_t msg; + ngx_mysql_t *m; + ngx_connection_t *c; + ngx_mysql_error_pkt_t *epkt; + ngx_mysql_response_pkt_t *pkt; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "mysql read query result"); + + c = rev->data; + m = c->data; + + m->peer.log->action = "reading mysql read query result"; + + n = ngx_recv(m->peer.connection, m->buf->pos, /* STUB */ 1024); + + if (n == NGX_AGAIN) { + return; + } + + if (n < 5) { + ngx_mysql_close(m, NGX_ERROR); + return; + } + + pkt = (ngx_mysql_response_pkt_t *) m->buf->pos; + + len = ngx_m24toh(pkt->pktlen); + + if (len > n - 4) { + ngx_log_error(NGX_LOG_ERR, rev->log, 0, + "mysql server %V sent incomplete response packet", + &m->peer.peers->peer[0].name); + + ngx_mysql_close(m, NGX_ERROR); + return; + } + + if (pkt->fields != 0xff) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "mysql query OK"); + + m->state = NGX_OK; + m->pktn = pkt->pktn; + + m->handler(m); + + return; + } + + epkt = (ngx_mysql_error_pkt_t *) pkt; + + msg.len = (u_char *) epkt + 4 + len - epkt->message; + msg.data = epkt->message; - capacity &= NGX_MYSQL_LONG_PASSWORD - | NGX_MYSQL_CONNECT_WITH_DB - | NGX_MYSQL_PROTOCOL_41; + ngx_log_error(NGX_LOG_ERR, rev->log, 0, + "mysql server %V sent error (%ud): \"%V\"", + &m->peer.peers->peer[0].name, ngx_m16toh(epkt->code), &msg); + ngx_mysql_close(m, NGX_ERROR); } diff --git a/src/mysql/ngx_mysql.h b/src/mysql/ngx_mysql.h index 99f10396b..17cb1afba 100644 --- a/src/mysql/ngx_mysql.h +++ b/src/mysql/ngx_mysql.h @@ -11,26 +11,74 @@ #include <ngx_config.h> #include <ngx_core.h> #include <ngx_event.h> +#include <ngx_event_connect.h> -typedef struct { +typedef struct ngx_mysql_s ngx_mysql_t; + +typedef void (*ngx_mysql_handler_pt)(ngx_mysql_t *m); + + +struct ngx_mysql_s { ngx_peer_connection_t peer; -} ngx_mysql_t; + + ngx_buf_t *buf; + ngx_pool_t *pool; + + ngx_str_t *login; + ngx_str_t *passwd; + ngx_str_t *database; + + ngx_str_t query; + + ngx_uint_t pktn; + + ngx_mysql_handler_pt handler; + void *data; + ngx_int_t state; + +}; + + +#define NGX_MYSQL_CMDPKT_LEN 5 #if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED && 0) -#define ngx_m16toh(n) (*(uint32_t *) n & 0x0000ffff) -#define ngx_m24toh(n) (*(uint32_t *) n & 0x00ffffff) -#define ngx_m32toh(n) *(uint32_t *) n +#define ngx_m16toh(n) (*(uint32_t *) n & 0x0000ffff) +#define ngx_m24toh(n) (*(uint32_t *) n & 0x00ffffff) +#define ngx_m32toh(n) *(uint32_t *) n + +#define ngx_htom16(n, m) *(uint16_t *) n = (uint16_t) ((m) & 0xffff) + +#define ngx_htom24(n, m) (n)[0] = (u_char) ((m) & 0xff); \ + (n)[1] = (u_char) (((m) >> 8) & 0xff); \ + (n)[2] = (u_char) (((m) >> 16) & 0xff) + +#define ngx_htom32(n, m) *(uint32_t *) (n) = (m) #else -#define ngx_m16toh(n) (n[0] | n[1] << 8) -#define ngx_m24toh(n) (n[0] | n[1] << 8 | n[2] << 16) -#define ngx_m32toh(n) (n[0] | n[1] << 8 | n[2] << 16 | n[3] << 24) +#define ngx_m16toh(n) (n[0] | n[1] << 8) +#define ngx_m24toh(n) (n[0] | n[1] << 8 | n[2] << 16) +#define ngx_m32toh(n) (n[0] | n[1] << 8 | n[2] << 16 | n[3] << 24) + +#define ngx_htom16(n, m) (n)[0] = (u_char) (m); (n)[1] = (u_char) ((m) >> 8) + +#define ngx_htom24(n, m) (n)[0] = (u_char) ((m) & 0xff); \ + (n)[1] = (u_char) (((m) >> 8) & 0xff); \ + (n)[2] = (u_char) (((m) >> 16) & 0xff) + +#define ngx_htom32(n, m) (n)[0] = (u_char) ((m) & 0xff); \ + (n)[1] = (u_char) (((m) >> 8) & 0xff); \ + (n)[2] = (u_char) (((m) >> 16) & 0xff); \ + (n)[3] = (u_char) (((m) >> 24) & 0xff) #endif +ngx_int_t ngx_mysql_connect(ngx_mysql_t *m); +ngx_int_t ngx_mysql_query(ngx_mysql_t *m); + + #endif /* _NGX_MYSQL_H_INCLUDED_ */ |