# HG changeset patch # User Igor Sysoev # Date 1148923692 0 # Node ID 7cbef16c71a1f43a07f8141f02e0135c775f0f5b # Parent d01fc553611dd561db2936c0f07622b23c7abded nginx-0.3.48-RELEASE import *) Change: now the ngx_http_charset_module works for subrequests, if the response has no "Content-Type" header line. *) Bugfix: if the "proxy_pass" directive has no URI part, then the "proxy_redirect default" directive add the unnecessary slash in start of the rewritten redirect. *) Bugfix: the internal redirect always transform client's HTTP method to GET, now the transformation is made for the "X-Accel-Redirect" redirects only and if the method is not HEAD; the bug had appeared in 0.3.42. *) Bugfix: the ngx_http_perl_module could not be built, if the perl was built with the threads support; the bug had appeared in 0.3.46. diff --git a/auto/cc/msvc b/auto/cc/msvc --- a/auto/cc/msvc +++ b/auto/cc/msvc @@ -49,7 +49,7 @@ case $CPU in ;; esac -# __cdecl, use with OpenSSL +# __cdecl, use with OpenSSL, md5 asm, and sha1 asm #CPU_OPT="$CPU_OPT -Gd" # __stdcall #CPU_OPT="$CPU_OPT -Gz" @@ -62,7 +62,6 @@ CFLAGS="$CFLAGS $CPU_OPT" # warnings -#CFLAGS="$CFLAGS -W3" CFLAGS="$CFLAGS -W4" # stop on warning diff --git a/auto/lib/conf b/auto/lib/conf --- a/auto/lib/conf +++ b/auto/lib/conf @@ -23,6 +23,18 @@ if [ $USE_MD5 = YES ]; then fi +if [ $USE_SHA1 = YES ]; then + + if [ $OPENSSL != NONE -a $OPENSSL != NO ]; then + have=NGX_HAVE_OPENSSL_SHA1_H . auto/have + SHA1=YES + + else + . auto/lib/sha1/conf + fi + +fi + if [ $USE_ZLIB = YES ]; then . auto/lib/zlib/conf fi diff --git a/auto/lib/make b/auto/lib/make --- a/auto/lib/make +++ b/auto/lib/make @@ -10,6 +10,10 @@ if [ $MD5 != NONE -a $MD5 != NO -a $MD5 . auto/lib/md5/make fi +if [ $SHA1 != NONE -a $SHA1 != NO -a $SHA1 != YES ]; then + . auto/lib/sha1/make +fi + if [ $OPENSSL != NONE -a $OPENSSL != NO -a $OPENSSL != YES ]; then . auto/lib/openssl/make fi diff --git a/auto/lib/md5/makefile.bcc b/auto/lib/md5/makefile.bcc --- a/auto/lib/md5/makefile.bcc +++ b/auto/lib/md5/makefile.bcc @@ -8,7 +8,7 @@ CFLAGS = -q -O2 -tWM $(CPU_OPT) -DL_ENDI md5.lib: bcc32 -c $(CFLAGS) -DMD5_ASM md5_dgst.c - tlib md5.lib +md5_dgst.obj +asm/m-win32.obj + tlib md5.lib +md5_dgst.obj +"asm\m-win32.obj" !else diff --git a/auto/lib/md5/makefile.msvc b/auto/lib/md5/makefile.msvc --- a/auto/lib/md5/makefile.msvc +++ b/auto/lib/md5/makefile.msvc @@ -2,7 +2,7 @@ # Copyright (C) Igor Sysoev -CFLAGS = -nologo -MT -O2 -Ob1 -Oi -Gs $(LIBC) $(CPU_OPT) -D L_ENDIAN +CFLAGS = -nologo -O2 -Ob1 -Oi -Gs $(LIBC) $(CPU_OPT) -D L_ENDIAN !if "$(MD5_ASM)" == "YES" diff --git a/auto/lib/sha1/conf b/auto/lib/sha1/conf new file mode 100644 --- /dev/null +++ b/auto/lib/sha1/conf @@ -0,0 +1,81 @@ + +# Copyright (C) Igor Sysoev + + +if [ $SHA1 != NONE ]; then + + CORE_INCS="$CORE_INCS $SHA1" + + case "$NGX_CC_NAME" in + + msvc* | owc* | bcc) + LINK_DEPS="$LINK_DEPS $SHA1/sha1.lib" + CORE_LIBS="$CORE_LIBS $SHA1/sha1.lib" + ;; + + icc*) + LINK_DEPS="$LINK_DEPS $SHA1/libsha.a" + + # to allow -ipo optimization we link with the *.o but not library + CORE_LIBS="$CORE_LIBS $SHA1/sha1_dgst.o" + + if [ $SHA1_ASM = YES ]; then + CORE_LIBS="$CORE_LIBS $SHA1/asm/sx86-elf.o" + fi + ;; + + *) + LINK_DEPS="$LINK_DEPS $SHA1/libsha.a" + CORE_LIBS="$CORE_LIBS $SHA1/libsha.a" + #CORE_LIBS="$CORE_LIBS -L $SHA1 -lsha" + ;; + + esac + +else + + if [ "$NGX_PLATFORM" != win32 ]; then + SHA1=NO + + # FreeBSD + + ngx_feature="sha1 in system md library" + ngx_feature_name= + ngx_feature_run=no + ngx_feature_incs="#include " + ngx_feature_libs="-lmd" + ngx_feature_test="SHA_CTX sha1; SHA1_Init(&sha1)" + . auto/feature + + + if [ $ngx_found = yes ]; then + CORE_LIBS="$CORE_LIBS $ngx_feature_libs" + SHA1=YES + SHA1_LIB=md + ngx_found=no + + else + if [ $SHA1 = NO ]; then + + # OpenSSL crypto library + + ngx_feature="OpenSSL sha1 crypto library" + ngx_feature_name= + ngx_feature_run=no + ngx_feature_incs="#include " + ngx_feature_libs="-lcrypto" + ngx_feature_test="SHA_CTX sha1; SHA1_Init(&sha1)" + . auto/feature + fi + fi + + + if [ $ngx_found = yes ]; then + have=NGX_HAVE_OPENSSL_SHA1_H . auto/have + CORE_LIBS="$CORE_LIBS $ngx_feature_libs" + SHA1=YES + SHA1_LIB=crypto + fi + fi + +fi diff --git a/auto/lib/sha1/make b/auto/lib/sha1/make new file mode 100644 --- /dev/null +++ b/auto/lib/sha1/make @@ -0,0 +1,96 @@ + +# Copyright (C) Igor Sysoev + + +case "$NGX_CC_NAME" in + + msvc*) + ngx_makefile=makefile.msvc + ngx_opt="CPU_OPT=\"$CPU_OPT\" LIBC=$LIBC SHA1_ASM=$SHA1_ASM" + ;; + + owc*) + ngx_makefile=makefile.owc + ngx_opt="CPU_OPT=\"$CPU_OPT\"" + ;; + + bcc) + ngx_makefile=makefile.bcc + ngx_opt="-DCPU_OPT=\"$CPU_OPT\" -DSHA1_ASM=$SHA1_ASM" + ;; + +esac + + +done=NO + + +case "$NGX_PLATFORM" in + + win32) + cp auto/lib/sha1/$ngx_makefile $SHA1 + + cat << END >> $NGX_MAKEFILE + +`echo "$SHA1/sha1.lib: $NGX_MAKEFILE" | sed -e "s/\//$ngx_regex_dirsep/g"` + cd `echo $SHA1 | sed -e "s/\//$ngx_regex_dirsep/g"` + \$(MAKE) -f $ngx_makefile $ngx_opt + cd ..\\..\\.. + +END + + done=YES + ;; + + SunOS:*:i86pc) + if [ $SHA1_ASM = YES ]; then + + cat << END >> $NGX_MAKEFILE + +$SHA1/libsha.a: $NGX_MAKEFILE + cd $SHA1 \\ + && \$(MAKE) CFLAGS="$SHA1_OPT -DSOL -DSHA1_ASM -DL_ENDIAN" \\ + CC="\$(CC)" CPP="\$(CPP)" \\ + SHA_ASM_OBJ=asm/sx86-sol.o clean libsha.a + +END + + done=YES + fi + ;; + + # FreeBSD: i386 + # Linux: i686 + + *:i386 | *:i686) + if [ $SHA1_ASM = YES ]; then + + cat << END >> $NGX_MAKEFILE + +$SHA1/libsha.a: $NGX_MAKEFILE + cd $SHA1 \\ + && \$(MAKE) CFLAGS="$SHA1_OPT -DELF -DSHA1_ASM -DL_ENDIAN" \\ + CC="\$(CC)" CPP="\$(CPP)" \\ + SHA_ASM_OBJ=asm/sx86-elf.o clean libsha.a + +END + + done=YES + fi + ;; + +esac + + +if [ $done = NO ]; then + + cat << END >> $NGX_MAKEFILE + +$SHA1/libsha.a: $NGX_MAKEFILE + cd $SHA1 \\ + && \$(MAKE) CFLAGS="$SHA1_OPT" \\ + CC="\$(CC)" SHA_ASM_OBJ= clean libsha.a + +END + +fi diff --git a/auto/lib/sha1/makefile.bcc b/auto/lib/sha1/makefile.bcc new file mode 100644 --- /dev/null +++ b/auto/lib/sha1/makefile.bcc @@ -0,0 +1,19 @@ + +# Copyright (C) Igor Sysoev + + +CFLAGS = -q -O2 -tWM $(CPU_OPT) -DL_ENDIAN + +!if "$(SHA1_ASM)" == "YES" + +sha1.lib: + bcc32 -c $(CFLAGS) -DSHA1_ASM sha1dgst.c + tlib sha1.lib +sha1dgst.obj +"asm\s-win32.obj" + +!else + +sha1.lib: + bcc32 -c $(CFLAGS) sha1dgst.c + tlib sha1.lib +sha1dgst.obj + +!endif diff --git a/auto/lib/sha1/makefile.msvc b/auto/lib/sha1/makefile.msvc new file mode 100644 --- /dev/null +++ b/auto/lib/sha1/makefile.msvc @@ -0,0 +1,19 @@ + +# Copyright (C) Igor Sysoev + + +CFLAGS = -nologo -O2 -Ob1 -Oi -Gs $(LIBC) $(CPU_OPT) -D L_ENDIAN + +!if "$(SHA1_ASM)" == "YES" + +sha1.lib: + cl -c $(CFLAGS) -D SHA1_ASM sha1dgst.c + link -lib -out:sha1.lib sha1dgst.obj asm/s-win32.obj + +!else + +sha1.lib: + cl -c $(CFLAGS) sha1dgst.c + link -lib -out:sha1.lib sha1dgst.obj + +!endif diff --git a/auto/lib/sha1/makefile.owc b/auto/lib/sha1/makefile.owc new file mode 100644 --- /dev/null +++ b/auto/lib/sha1/makefile.owc @@ -0,0 +1,9 @@ + +# Copyright (C) Igor Sysoev + + +CFLAGS = -zq -bt=nt -bm -ot -op -oi -oe -s $(CPU_OPT) + +sha1.lib: + wcl386 -c $(CFLAGS) -dL_ENDIAN sha1dgst.c + wlib -n sha1.lib sha1dgst.obj diff --git a/auto/options b/auto/options --- a/auto/options +++ b/auto/options @@ -89,6 +89,11 @@ MD5=NONE MD5_OPT= MD5_ASM=NO +USE_SHA1=NO +SHA1=NONE +SHA1_OPT= +SHA1_ASM=NO + USE_ZLIB=NO ZLIB=NONE ZLIB_OPT= @@ -191,6 +196,10 @@ do --with-md5-opt=*) MD5_OPT="$value" ;; --with-md5-asm) MD5_ASM=YES ;; + --with-sha1=*) SHA1="$value" ;; + --with-sha1-opt=*) SHA1_OPT="$value" ;; + --with-sha1-asm) SHA1_ASM=YES ;; + --with-zlib=*) ZLIB="$value" ;; --with-zlib-opt=*) ZLIB_OPT="$value" ;; --with-zlib-asm=*) ZLIB_ASM="$value" ;; @@ -285,6 +294,10 @@ cat << END --with-md5-opt=OPTIONS set additional options for md5 building --with-md5-asm use md5 assembler sources + --with-sha1=DIR set path to sha1 library sources + --with-sha1-opt=OPTIONS set additional options for sha1 building + --with-sha1-asm use sha1 assembler sources + --with-zlib=DIR set path to zlib library sources --with-zlib-opt=OPTIONS set additional options for zlib building --with-zlib-asm=CPU use zlib assembler sources optimized diff --git a/auto/summary b/auto/summary --- a/auto/summary +++ b/auto/summary @@ -63,6 +63,19 @@ case $MD5 in *) echo " + using md5 library: $MD5" ;; esac +case $SHA1 in + YES) + case $OPENSSL in + NONE|NO) echo " + sha1: using system $SHA1_LIB library" ;; + *) echo " + sha1: using OpenSSL library" ;; + esac + ;; + + NONE) echo " + sha1 library is not used" ;; + NO) echo " + sha1 library is not found" ;; + *) echo " + using sha1 library: $SHA1" ;; +esac + case $ZLIB in YES) echo " + using system zlib library" ;; NONE) echo " + zlib library is not used" ;; diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml --- a/docs/xml/nginx/changes.xml +++ b/docs/xml/nginx/changes.xml @@ -9,6 +9,62 @@ nginx changelog + + + + +теперь модуль ngx_http_charset_module работает для подзапросов, +в ответах которых нет строки заголовка "Content-Type". + + +now the ngx_http_charset_module works for subrequests, +if the response has no "Content-Type" header line. + + + + + +если в директиве proxy_pass не было URI, +то директива "proxy_redirect default" добавляла в переписанный +редирект в начало лишний слэш. + + +if the "proxy_pass" directive has no URI part, +then the "proxy_redirect default" directive add the unnecessary slash +in start of the rewritten redirect. + + + + + +внутренний редирект всегда превращал любой HTTP-метод в GET, +теперь это делается только для редиректов, выполняемых с помощью +X-Accel-Redirect, и у которых метод не равен HEAD; +ошибка появилась в 0.3.42. + + +the internal redirect always transform client's HTTP method to GET, +now the transformation is made for the "X-Accel-Redirect" redirects only +and if the method is not HEAD; +bug appeared in 0.3.42. + + + + + +модуль ngx_http_perl_module не собирался, если перл был с поддержкой потоков; +ошибка появилась в 0.3.46. + + +the ngx_http_perl_module could not be built, if the perl was built +with the threads support; +bug appeared in 0.3.46. + + + + + + diff --git a/src/core/nginx.h b/src/core/nginx.h --- 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 --- 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_ 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_ 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,19 +174,30 @@ ngx_http_charset_header_filter(ngx_http_ charset = ctx->charset; } - if (r->headers_out.content_type.len == 0) { - return ngx_http_next_header_filter(r); - } + charsets = mcf->charsets.elts; + + if (r == r->main) { + if (r->headers_out.content_type.len == 0) { + return ngx_http_next_header_filter(r); + } - 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 (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; + } } - charsets = mcf->charsets.elts; - lcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module); len = 0; diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c --- 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 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 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, 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 --- 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_interpre 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_ #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_htt 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_comman 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_comman } } - 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_comman } 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_co 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_co } } - 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_co } 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 --- 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_requ 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 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1470,7 +1470,6 @@ ngx_http_finalize_request(ngx_http_reque || 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 --- 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_scr 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 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -1160,6 +1160,10 @@ ngx_http_upstream_process_header(ngx_eve 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 --- /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 --- /dev/null +++ b/src/mysql/ngx_http_mysql_test.c @@ -0,0 +1,196 @@ + +/* + * Copyright (C) Igor Sysoev + */ + +#include +#include +#include +#include + + +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 --- 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 #include #include +#include #include +#if (NGX_HAVE_OPENSSL_SHA1_H) +#include +#else +#include +#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 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 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 (gr1->protocol < 10) { + ngx_log_error(NGX_LOG_ERR, rev->log, 0, + "mysql server %V sent unsupported protocol version %ud", + &m->peer.peers->peer[0].name, gr1->protocol); + + ngx_mysql_close(m, NGX_ERROR); + return; + } + + gr2 = (ngx_mysql_greeting2_pkt_t *) + (gr1->version + ngx_strlen(gr1->version) + 1); + + capacity = ngx_m16toh(gr2->capacity); + + ngx_log_debug8(NGX_LOG_DEBUG_MYSQL, rev->log, 0, + "mysql version: %ud, \"%s\", thread: %ud, salt: \"%s\", " + "capacity: %Xd, charset: %ud, status: %ud, salt rest \"%s\"", + 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; } - if (p[4]) < 10) { + 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 unsupported protocol version %ud", - &ctx->peer.peers->peer[0].name, p[4]); + "mysql server %V sent incomplete response packet", + &m->peer.peers->peer[0].name); ngx_mysql_close(m, NGX_ERROR); return; } - len = ngx_strlen(&p[5]); - t = p + 5 + len + 1; + 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); +} + - capacity = ngx_m16toh((&t[4 + 9])); +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; +} + - ngx_log_debug8(NGX_LOG_DEBUG_MYSQL, rev->log, 0, - "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]); +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; - capacity &= NGX_MYSQL_LONG_PASSWORD - | NGX_MYSQL_CONNECT_WITH_DB - | NGX_MYSQL_PROTOCOL_41; + 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; + + 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 --- a/src/mysql/ngx_mysql.h +++ b/src/mysql/ngx_mysql.h @@ -11,26 +11,74 @@ #include #include #include +#include + + +typedef struct ngx_mysql_s ngx_mysql_t; + +typedef void (*ngx_mysql_handler_pt)(ngx_mysql_t *m); -typedef struct { +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_ */